• 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/**
18 * ObservedPropertyAbstract base class for the implementation o all state variables
19 * Its base class SubscribedAbstractProperty<T> provides all public / SDK functions.
20 *
21 * This class and all other definitons in this file are framework
22 * internal / non-SDK.
23 *
24 */
25
26type SynchedPropertyFactoryFunc = <T>(source: ObservedPropertyAbstract<T>) => ObservedPropertyAbstract<T>;
27
28/*
29   manage subscriptions to a property
30   managing the property is left to sub
31   classes
32   Extended by ObservedProperty, SyncedPropertyOneWay
33   and SyncedPropertyTwoWay
34*/
35abstract class ObservedPropertyAbstract<T> extends SubscribedAbstractProperty<T> {
36  protected subscribers_: Set<number>
37  private id_: number;
38  protected info_?: PropertyInfo;
39
40  constructor(subscribeMe?: IPropertySubscriber, info?: PropertyInfo) {
41    super();
42    this.subscribers_ = new Set<number>();
43    this.id_ = SubscriberManager.MakeId();
44    SubscriberManager.Add(this);
45    if (subscribeMe) {
46      this.subscribers_.add(subscribeMe.id__());
47    }
48    if (info) {
49      this.info_ = info;
50    }
51  }
52
53  aboutToBeDeleted() {
54    SubscriberManager.Delete(this.id__())
55  }
56
57  id__(): number {
58    return this.id_;
59  }
60
61  public info(): PropertyInfo {
62    return this.info_;
63  }
64
65  public setInfo(propName: PropertyInfo) {
66    if (propName && propName != "") {
67      this.info_ = propName;
68    }
69  }
70
71  public abstract get(): T;
72
73  // Partial Update "*PU" classes will overwrite
74  public getUnmonitored(): T {
75    return this.get();
76  }
77
78  public abstract set(newValue: T): void;
79
80  // update the element id for recycle custom component
81  public updateElmtId(oldElmtId: number, newElmtId: number): void {
82    if (this.subscribers_.has(oldElmtId)) {
83      this.subscribers_.delete(oldElmtId);
84      this.subscribers_.add(newElmtId);
85    }
86  }
87
88  // Method name is used to check object is of type ObservedPropertyAbstract
89  // Do NOT override in derived classed, use addSubscriber
90  public subscribeMe(subscriber: ISinglePropertyChangeSubscriber<T>): void {
91    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: subscribeMe: Property new subscriber '${subscriber.id__()}'`);
92    this.subscribers_.add(subscriber.id__());
93  }
94
95  /*
96    the inverse function of createOneWaySync or createTwoWaySync
97    Do NOT override in derived classed, use removeSubscriber
98  */
99  public unlinkSuscriber(subscriberId: number): void {
100    this.subscribers_.delete(subscriberId);
101  }
102
103  /*
104    Virtualized version of the subscription mechanism - add subscriber
105  */
106  public addSubscriber(subscriber: ISinglePropertyChangeSubscriber<T>):void {
107    if (subscriber) {
108      this.subscribeMe(subscriber);
109    }
110  }
111
112  /*
113    Virtualized version of the subscription mechanism - remove subscriber
114  */
115  public removeSubscriber(subscriber: IPropertySubscriber, id?: number):void {
116    if (id) {
117      this.unlinkSuscriber(id);
118    } else if (subscriber) {
119      this.unlinkSuscriber(subscriber.id__());
120    }
121  }
122
123  protected notifyHasChanged(newValue: T) {
124    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: notifyHasChanged, notifying.`);
125    this.subscribers_.forEach((subscribedId) => {
126      var subscriber: IPropertySubscriber = SubscriberManager.Find(subscribedId)
127      if (subscriber) {
128        // FU code path
129        if ('hasChanged' in subscriber) {
130          (subscriber as ISinglePropertyChangeSubscriber<T>).hasChanged(newValue);
131        }
132        if ('propertyHasChanged' in subscriber) {
133          (subscriber as IMultiPropertiesChangeSubscriber).propertyHasChanged(this.info_);
134        }
135
136        // PU code path, only used for ObservedPropertySimple/Object stored inside App/LocalStorage
137        // ObservedPropertySimplePU/ObjectPU  used in all other PU cases, has its own notifyPropertyHasChangedPU()
138        if ('syncPeerHasChanged' in subscriber) {
139          (subscriber as unknown as PeerChangeEventReceiverPU<T>).syncPeerHasChanged(this as unknown as ObservedPropertyAbstractPU<T>);
140        }
141      } else {
142        stateMgmtConsole.warn(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: notifyHasChanged: unknown subscriber ID '${subscribedId}' error!`);
143      }
144    });
145  }
146
147  protected notifyPropertyRead() {
148    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: propertyRead.`)
149    this.subscribers_.forEach((subscribedId) => {
150      var subscriber: IPropertySubscriber = SubscriberManager.Find(subscribedId)
151      if (subscriber) {
152        if ('propertyRead' in subscriber) {
153          (subscriber as IMultiPropertiesReadSubscriber).propertyRead(this.info_);
154        }
155      }
156    });
157  }
158
159  /*
160  return numebr of subscribers to this property
161  mostly useful for unit testin
162  */
163  public numberOfSubscrbers(): number {
164    return this.subscribers_.size;
165  }
166
167
168  /**
169   * These functions are meant for use in connection with the App Stoage and
170   * business logic implementation.
171   * the created Link and Prop will update when 'this' property value
172   * changes.
173   *
174   * These functions are depreciated and will be removed
175   * these are replaced with createSync
176   */
177  public abstract createLink(subscribeOwner?: IPropertySubscriber,
178    linkPropName?: PropertyInfo): ObservedPropertyAbstract<T>;
179  public abstract createProp(subscribeOwner?: IPropertySubscriber,
180    linkPropName?: PropertyInfo): ObservedPropertyAbstract<T>;
181
182  /**
183   * provide a factory function that creates a SynchedPropertyXXXX of choice
184   * that uses 'this' as source
185   * @param factoryFunc
186   * @returns
187   */
188  public createSync(factoryFunc: SynchedPropertyFactoryFunc): ObservedPropertyAbstract<T> {
189    return factoryFunc<T>(this);
190  }
191
192  /**
193   * depreciated SDK function, not used anywhere by the framework
194   */
195  public createTwoWaySync(subscribeMe?: IPropertySubscriber, info?: string): SubscribedAbstractProperty<T> {
196    stateMgmtConsole.warn("Using depreciated method 'createTwoWaySync'!")
197    return this.createLink(subscribeMe, info);
198  }
199
200  /**
201   * depreciated SDK function, not used anywhere by the framework
202   */
203  public createOneWaySync(subscribeMe?: IPropertySubscriber, info?: string): SubscribedAbstractProperty<T> {
204    stateMgmtConsole.warn("Using depreciated method 'createOneWaySync' !")
205    return this.createProp(subscribeMe, info);
206  }
207
208  /**
209   * factory function for concrete 'object' or 'simple' ObservedProperty object
210   * depending if value is Class object
211   * or simple type (boolean | number | string)
212   * @param value
213   * @param owningView
214   * @param thisPropertyName
215   * @returns either
216   */
217  static CreateObservedObject<C>(value: C, owningView: IPropertySubscriber, thisPropertyName: PropertyInfo)
218    : ObservedPropertyAbstract<C> {
219    return (typeof value === "object") ?
220      new ObservedPropertyObject(value, owningView, thisPropertyName)
221      : new ObservedPropertySimple(value, owningView, thisPropertyName);
222  }
223}
224