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