• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2022 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 * SubscriableAbstract
19 *
20 * This class is part of the SDK.
21 * @since 9
22 *
23 * SubscriableAbstract is an abstract class that manages subscribers
24 * to value changes. These subscribers are the implementation of
25 * @State, @Link, @Provide, @Consume decorated variables inside the
26 * framework. Each using @State, @Link, etc., decorated varibale in
27 * a @Component will make its own subscription. When the component
28 * is created the subscription is added, and before the component
29 * is deleted it unsubscribes
30 *
31 * An application may extend SubscriableAbstract for a custom class
32 * that manages state data. @State, @Link, @Provide, @Consume
33 * decorated variables can hold an Object that is instance of
34 * SubscribaleAbstract.
35 *
36 * About lifecycle: It is legal use for two @Components with two @State
37 * decorated variables to share the same SubscribaleAbstract object.
38 * Each such decorated variable implementation makes its own
39 * subscription to the SubscribaleAbstract object. Hence, when both variables
40 * have unsubscribed the SubscribaleAbstract custom class may do its own
41 * de-initilialization, e.g. release held external resources.
42 *
43 * How to extend:
44 * A subclass manages the get and set to one or several properties on its own.
45 * The subclass needs to notify all relevant value changes to the framework for the
46 * UI to be updated. Notification should only be given for class properties that
47 * are used to generate the UI.
48 *
49 * A subclass must call super() in its constructor to let this base class
50 * initialize itself.
51 *
52 * A subclass must call 'notifyPropertyHasChanged*(' after the relevant property
53 * has changes. The framework will notify all dependent components to re-render.
54 *
55 * A sub-class may overwrite the 'addOwningProperty' function to add own
56 * functionality, but it must call super.addowningOwningProperty(..). E.g.
57 * the sub-class could connect to external resources upon the first subscriber.
58 *
59 * A sub-class may also overwrite the 'removeOwningProperty' function or
60 * 'removeOwningPropertyById' function to add own functionality,
61 * but it must call super.removeOwningProperty(..).
62 * E.g. the sub-class could release held external resources upon loosing the
63 * last subscriber.
64 *
65 */
66
67abstract class SubscribaleAbstract {
68
69  // keeps track of all subscribing properties
70  private owningProperties_: Set<number>;
71
72  /**
73   * make sure to call super() from subclass constructor!
74   *
75   * @since 9
76   */
77  constructor() {
78    this.owningProperties_ = new Set<number>();
79    stateMgmtConsole.debug(`SubscribaleAbstract: construcstor done`);
80  }
81
82  /**
83  * A subsclass must call this function whenever one of its properties has
84   * changed that is used to construct the UI.
85   * @param propName name of the change property
86   * @param newValue the property value after the change
87   *
88   * @since 9
89   */
90  protected notifyPropertyHasChanged(propName: string, newValue: any) {
91    stateMgmtConsole.debug(`SubscribaleAbstract: notifyPropertyHasChanged '${propName}'.`)
92    this.owningProperties_.forEach((subscribedId) => {
93      var owningProperty: IPropertySubscriber = SubscriberManager.Find(subscribedId)
94      if (owningProperty) {
95        if ('objectPropertyHasChangedPU' in owningProperty) {
96          // PU code path
97          (owningProperty as unknown as ObservedObjectEventsPUReceiver<any>).objectPropertyHasChangedPU(this, propName);
98        }
99
100        // FU code path
101        if ('hasChanged' in owningProperty) {
102          (owningProperty as ISinglePropertyChangeSubscriber<any>).hasChanged(newValue);
103        }
104        if ('propertyHasChanged' in owningProperty) {
105          (owningProperty as IMultiPropertiesChangeSubscriber).propertyHasChanged(propName);
106        }
107      } else {
108        stateMgmtConsole.error(`SubscribaleAbstract: notifyHasChanged: unknown subscriber.'${subscribedId}' error!.`);
109      }
110    });
111  }
112
113  /**
114   * Method used by the framework to add subscribing decorated variables
115   * Subclass may overwrite this function but must call the function of the base
116   * class from its own implementation.
117   * @param subscriber new subscriber that implements ISinglePropertyChangeSubscriber
118   * and/or IMultiPropertiesChangeSubscriber interfaces
119   *
120   * @since 9
121   */
122
123  public addOwningProperty(subscriber: IPropertySubscriber): void {
124    stateMgmtConsole.debug(`SubscribaleAbstract: addOwningProperty: subscriber '${subscriber.id__()}'.`)
125    this.owningProperties_.add(subscriber.id__());
126  }
127
128  /**
129   * Method used by the framework to ubsubscribing decorated variables
130   * Subclass may overwrite this function but must call the function of the base
131   * class from its own implementation.
132   * @param subscriber subscriber that implements ISinglePropertyChangeSubscriber
133   * and/or IMultiPropertiesChangeSubscriber interfaces
134   *
135   * @since 9
136   */
137  public removeOwningProperty(property: IPropertySubscriber): void {
138    return this.removeOwningPropertyById(property.id__());
139  }
140
141  /**
142   * Same as @see removeOwningProperty() but by Subscriber id.
143   * @param subscriberId
144  *
145  * @since 9
146   */
147  public removeOwningPropertyById(subscriberId: number): void {
148    stateMgmtConsole.debug(`SubscribaleAbstract: removeOwningProperty '${subscriberId}'.`)
149    this.owningProperties_.delete(subscriberId);
150  }
151}
152