• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16/*
17  Overview of the Observed Property class hiararchy
18
19  ObservedPropertyAbstract
20     |-- ObservedSimplePropertyAbstract - boolean, number, string
21     |         |-- ObservedSimpleProperty - owns the property
22     |         |-- SynchedSimplePropertyOneWay - one way sync from ObservedSimpleProperty
23     |         |        |--SynchedPropertySimpleOneWaySubscribing - one way sync
24     |         |           from ObservedSimpleProperty, return value of AppStorage.prop(..)
25     |         |-- SynchedSimplePropertyTwoWay - two way sync with ObservedSimpleProperty
26     |
27     |-- ObservedObjectPropertyAbstract - Object proxied by ObservedObject
28               |-- ObservedObjectProperty - owns the property
29               |-- SynchedObjectPropertyTwoWay - two way sync with ObservedObjectProperty
30
31*/
32
33/*
34   manage subscriptions to a property
35   managing the property is left to sub
36   classes
37   Extended by ObservedProperty, SyncedPropertyOneWay
38   and SyncedPropertyTwoWay
39*/
40abstract class ObservedPropertyAbstract<T>  {
41  protected subscribers_: Set<number>
42  private id_: number;
43  private info_?: PropertyInfo;
44
45  constructor(subscribeMe?: IPropertySubscriber, info?: PropertyInfo) {
46    this.subscribers_ = new Set<number>();
47    this.id_ = SubscriberManager.Get().MakeId();
48    SubscriberManager.Get().add(this);
49    if (subscribeMe) {
50      this.subscribers_.add(subscribeMe.id__());
51    }
52    if (info) {
53      this.info_ = info;
54    }
55  }
56
57  aboutToBeDeleted() {
58    SubscriberManager.Get().delete(this.id__())
59  }
60
61  id__(): number {
62    return this.id_;
63  }
64
65  public info(): PropertyInfo {
66    return this.info_;
67  }
68
69  public abstract get(): T;
70  public abstract set(newValue: T): void;
71
72
73  public subscribeMe(subscriber: ISinglePropertyChangeSubscriber<T>): void {
74    console.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: subscribeMe: Property new subscriber '${subscriber.id__()}'`);
75    this.subscribers_.add(subscriber.id__());
76  }
77
78  /*
79    the inverse function of createOneWaySync or createTwoWaySync
80  */
81  public unlinkSuscriber(subscriberId: number): void {
82    this.subscribers_.delete(subscriberId);
83  }
84
85  protected notifyHasChanged(newValue: T) {
86    //console.debug(`ObservedPropertyAbstract[${this.id()}, '${this.info() || "unknown"}']: notifyHasChanged to newValue '${JSON.stringify(newValue)}', notifying.`)
87    console.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: notifyHasChanged, notifying.`);
88    var registry: IPropertySubscriberLookup = SubscriberManager.Get();
89    this.subscribers_.forEach((subscribedId) => {
90      var subscriber: IPropertySubscriber = registry!.get(subscribedId)
91      if (subscriber) {
92        if ('hasChanged' in subscriber) {
93          (subscriber as ISinglePropertyChangeSubscriber<T>).hasChanged(newValue);
94        }
95        if ('propertyHasChanged' in subscriber) {
96          (subscriber as IMultiPropertiesChangeSubscriber).propertyHasChanged(this.info_);
97        }
98      } else {
99        console.error(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: notifyHasChanged: unknown subscriber ID '${subscribedId}' error!`);
100      }
101    });
102  }
103
104  protected notifyPropertyRead() {
105    console.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: propertyRead.`)
106    var registry: IPropertySubscriberLookup = SubscriberManager.Get();
107    this.subscribers_.forEach((subscribedId) => {
108      var subscriber: IPropertySubscriber = registry!.get(subscribedId)
109      if (subscriber) {
110        if ('propertyRead' in subscriber) {
111          (subscriber as IMultiPropertiesReadSubscriber).propertyRead(this.info_);
112        }
113      }
114    });
115  }
116
117  /*
118  return numebr of subscribers to this property
119  mostly useful for unit testin
120  */
121  public numberOfSubscrbers(): number {
122    return this.subscribers_.size;
123  }
124
125
126  /**
127   * These functions are meant for use in connection with the App Stoage and
128   * business logic implementation.
129   * the created Link and Prop will update when 'this' property value
130   * changes.
131   */
132  public abstract createLink(subscribeOwner?: IPropertySubscriber,
133    linkPropName?: PropertyInfo, contentObserver?: ObservedPropertyAbstract<T>): ObservedPropertyAbstract<T>;
134  public abstract createProp(subscribeOwner?: IPropertySubscriber,
135    linkPropName?: PropertyInfo, contentObserver?: ObservedPropertyAbstract<T>): ObservedPropertyAbstract<T>;
136
137  /**
138   * factory function for concrete 'object' or 'simple' ObservedProperty object
139   * depending if value is Class object
140   * or simple type (boolean | number | string)
141   * @param value
142   * @param owningView
143   * @param thisPropertyName
144   * @returns either
145   */
146  static CreateObservedObject<C>(value: C, owningView: IPropertySubscriber, thisPropertyName: PropertyInfo)
147    : ObservedPropertyAbstract<C> {
148    return (typeof value === "object") ?
149      new ObservedPropertyObject(value, owningView, thisPropertyName)
150      : new ObservedPropertySimple(value, owningView, thisPropertyName);
151  }
152}
153