• 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> implements AbstractProperty<T> {
36  protected subscribers_: Set<number>;
37  private id_: number;
38  protected info_?: PropertyInfo;
39  protected isFake_: boolean = false;
40  constructor(subscribeMe?: IPropertySubscriber, info?: PropertyInfo) {
41    super();
42    this.subscribers_ = new Set<number>();
43    this.id_ = SubscriberManager.MakeStateVariableId();
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 __isFake_ObservedPropertyAbstract_Internal(): boolean {
72    return this.isFake_;
73  }
74
75  public __setIsFake_ObservedPropertyAbstract_Internal(isFake: boolean): void {
76    this.isFake_ = isFake;
77  }
78
79  // Partial Update "*PU" classes will overwrite
80  public getUnmonitored(): T {
81    return this.get();
82  }
83
84  // update the element id for recycle custom component
85  public updateElmtId(oldElmtId: number, newElmtId: number): void {
86    if (this.subscribers_.has(oldElmtId)) {
87      this.subscribers_.delete(oldElmtId);
88      this.subscribers_.add(newElmtId);
89    }
90  }
91
92  // Method name is used to check object is of type ObservedPropertyAbstract
93  // Do NOT override in derived classed, use addSubscriber
94  public subscribeMe(subscriber: ISinglePropertyChangeSubscriber<T>): void {
95    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || 'unknown'}']: subscribeMe: Property new subscriber '${subscriber.id__()}'`);
96    this.subscribers_.add(subscriber.id__());
97  }
98
99  /*
100    the inverse function of createOneWaySync or createTwoWaySync
101    Do NOT override in derived classed, use removeSubscriber
102  */
103  public unlinkSuscriber(subscriberId: number): void {
104    this.subscribers_.delete(subscriberId);
105  }
106
107  /*
108    Virtualized version of the subscription mechanism - add subscriber
109  */
110  public addSubscriber(subscriber: ISinglePropertyChangeSubscriber<T>):void {
111    if (subscriber) {
112      this.subscribeMe(subscriber);
113    }
114  }
115
116  /*
117    Virtualized version of the subscription mechanism - remove subscriber
118  */
119  public removeSubscriber(subscriber: IPropertySubscriber, id?: number):void {
120    if (id) {
121      this.unlinkSuscriber(id);
122    } else if (subscriber) {
123      this.unlinkSuscriber(subscriber.id__());
124    }
125  }
126
127  // FU code path callback
128  protected notifyHasChanged(newValue: T) {
129    stateMgmtProfiler.begin('ObservedPropertyAbstract.notifyHasChanged');
130    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || 'unknown'}']: notifyHasChanged, notifying.`);
131    this.subscribers_.forEach((subscribedId) => {
132      let subscriber: IPropertySubscriber = SubscriberManager.Find(subscribedId);
133      if (subscriber) {
134        // FU code path
135        if ('hasChanged' in subscriber) {
136          (subscriber as ISinglePropertyChangeSubscriber<T>).hasChanged(newValue);
137        }
138        if ('propertyHasChanged' in subscriber) {
139          (subscriber as IMultiPropertiesChangeSubscriber).propertyHasChanged(this.info_);
140        }
141      } else {
142        stateMgmtConsole.warn(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || 'unknown'}']: notifyHasChanged: unknown subscriber ID '${subscribedId}' error!`);
143      }
144    });
145    stateMgmtProfiler.end();
146  }
147
148  protected notifyPropertyRead() {
149    stateMgmtProfiler.begin('ObservedPropertyAbstract.notifyPropertyRead');
150    stateMgmtConsole.debug(`ObservedPropertyAbstract[${this.id__()}, '${this.info() || 'unknown'}']: propertyRead.`);
151    this.subscribers_.forEach((subscribedId) => {
152      var subscriber: IPropertySubscriber = SubscriberManager.Find(subscribedId)
153      if (subscriber) {
154        if ('propertyRead' in subscriber) {
155          (subscriber as IMultiPropertiesReadSubscriber).propertyRead(this.info_);
156        }
157      }
158    });
159    stateMgmtProfiler.end();
160  }
161
162  /*
163  return numebr of subscribers to this property
164  mostly useful for unit testin
165  */
166  public numberOfSubscrbers(): number {
167    return this.subscribers_.size;
168  }
169
170
171  /**
172   * These functions are meant for use in connection with the App Stoage and
173   * business logic implementation.
174   * the created Link and Prop will update when 'this' property value
175   * changes.
176   *
177   * These functions are depreciated and will be removed
178   * these are replaced with createSync
179   */
180  public abstract createLink(subscribeOwner?: IPropertySubscriber,
181    linkPropName?: PropertyInfo): ObservedPropertyAbstract<T>;
182  public abstract createProp(subscribeOwner?: IPropertySubscriber,
183    linkPropName?: PropertyInfo): ObservedPropertyAbstract<T>;
184
185  /**
186   * provide a factory function that creates a SynchedPropertyXXXX of choice
187   * that uses 'this' as source
188   * @param factoryFunc
189   * @returns
190   */
191  public createSync(factoryFunc: SynchedPropertyFactoryFunc): ObservedPropertyAbstract<T> {
192    return factoryFunc<T>(this);
193  }
194
195  /**
196   * depreciated SDK function, not used anywhere by the framework
197   */
198  public createTwoWaySync(subscribeMe?: IPropertySubscriber, info?: string): SubscribedAbstractProperty<T> {
199    stateMgmtConsole.warn("Using depreciated method 'createTwoWaySync'!");
200    return this.createLink(subscribeMe, info);
201  }
202
203  /**
204   * depreciated SDK function, not used anywhere by the framework
205   */
206  public createOneWaySync(subscribeMe?: IPropertySubscriber, info?: string): SubscribedAbstractProperty<T> {
207    stateMgmtConsole.warn("Using depreciated method 'createOneWaySync' !");
208    return this.createProp(subscribeMe, info);
209  }
210
211  /**
212   * factory function for concrete 'object' or 'simple' ObservedProperty object
213   * depending if value is Class object
214   * or simple type (boolean | number | string)
215   * @param value
216   * @param owningView
217   * @param thisPropertyName
218   * @returns either
219   */
220  static CreateObservedObject<C>(value: C, owningView: IPropertySubscriber, thisPropertyName: PropertyInfo)
221    : ObservedPropertyAbstract<C> {
222    return (typeof value === 'object') ?
223      new ObservedPropertyObject(value, owningView, thisPropertyName)
224      : new ObservedPropertySimple(value, owningView, thisPropertyName);
225  }
226}
227