• 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
81  public subscribeMe(subscriber: ISinglePropertyChangeSubscriber<T>): void {
82    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: subscribeMe: Property new subscriber '${subscriber.id__()}'`);
83    this.subscribers_.add(subscriber.id__());
84  }
85
86  /*
87    the inverse function of createOneWaySync or createTwoWaySync
88  */
89  public unlinkSuscriber(subscriberId: number): void {
90    this.subscribers_.delete(subscriberId);
91  }
92
93  protected notifyHasChanged(newValue: T) {
94    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: notifyHasChanged, notifying.`);
95    this.subscribers_.forEach((subscribedId) => {
96      var subscriber: IPropertySubscriber = SubscriberManager.Find(subscribedId)
97      if (subscriber) {
98        // FU code path
99        if ('hasChanged' in subscriber) {
100          (subscriber as ISinglePropertyChangeSubscriber<T>).hasChanged(newValue);
101        }
102        if ('propertyHasChanged' in subscriber) {
103          (subscriber as IMultiPropertiesChangeSubscriber).propertyHasChanged(this.info_);
104        }
105
106        // PU code path, only used for ObservedPropertySimple/Object stored inside App/LocalStorage
107        // ObservedPropertySimplePU/ObjectPU  used in all other PU cases, has its own notifyPropertyHasChangedPU()
108        if ('syncPeerHasChanged' in subscriber) {
109          (subscriber as unknown as PeerChangeEventReceiverPU<T>).syncPeerHasChanged(this as unknown as ObservedPropertyAbstractPU<T>);
110        }
111      } else {
112        stateMgmtConsole.warn(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: notifyHasChanged: unknown subscriber ID '${subscribedId}' error!`);
113      }
114    });
115  }
116
117  protected notifyPropertyRead() {
118    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || "unknown"}']: propertyRead.`)
119    this.subscribers_.forEach((subscribedId) => {
120      var subscriber: IPropertySubscriber = SubscriberManager.Find(subscribedId)
121      if (subscriber) {
122        if ('propertyRead' in subscriber) {
123          (subscriber as IMultiPropertiesReadSubscriber).propertyRead(this.info_);
124        }
125      }
126    });
127  }
128
129  /*
130  return numebr of subscribers to this property
131  mostly useful for unit testin
132  */
133  public numberOfSubscrbers(): number {
134    return this.subscribers_.size;
135  }
136
137
138  /**
139   * These functions are meant for use in connection with the App Stoage and
140   * business logic implementation.
141   * the created Link and Prop will update when 'this' property value
142   * changes.
143   *
144   * These functions are depreciated and will be removed
145   * these are replaced with createSync
146   */
147  public abstract createLink(subscribeOwner?: IPropertySubscriber,
148    linkPropName?: PropertyInfo): ObservedPropertyAbstract<T>;
149  public abstract createProp(subscribeOwner?: IPropertySubscriber,
150    linkPropName?: PropertyInfo): ObservedPropertyAbstract<T>;
151
152  /**
153   * provide a factory function that creates a SynchedPropertyXXXX of choice
154   * that uses 'this' as source
155   * @param factoryFunc
156   * @returns
157   */
158  public createSync(factoryFunc: SynchedPropertyFactoryFunc): ObservedPropertyAbstract<T> {
159    return factoryFunc<T>(this);
160  }
161
162  /**
163   * depreciated SDK function, not used anywhere by the framework
164   */
165  public createTwoWaySync(subscribeMe?: IPropertySubscriber, info?: string): SubscribedAbstractProperty<T> {
166    stateMgmtConsole.warn("Using depreciated method 'createTwoWaySync'!")
167    return this.createLink(subscribeMe, info);
168  }
169
170  /**
171   * depreciated SDK function, not used anywhere by the framework
172   */
173  public createOneWaySync(subscribeMe?: IPropertySubscriber, info?: string): SubscribedAbstractProperty<T> {
174    stateMgmtConsole.warn("Using depreciated method 'createOneWaySync' !")
175    return this.createProp(subscribeMe, info);
176  }
177
178  /**
179   * factory function for concrete 'object' or 'simple' ObservedProperty object
180   * depending if value is Class object
181   * or simple type (boolean | number | string)
182   * @param value
183   * @param owningView
184   * @param thisPropertyName
185   * @returns either
186   */
187  static CreateObservedObject<C>(value: C, owningView: IPropertySubscriber, thisPropertyName: PropertyInfo)
188    : ObservedPropertyAbstract<C> {
189    return (typeof value === "object") ?
190      new ObservedPropertyObject(value, owningView, thisPropertyName)
191      : new ObservedPropertySimple(value, owningView, thisPropertyName);
192  }
193}
194