• 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 ('hasChanged' in owningProperty) {
96          (owningProperty as ISinglePropertyChangeSubscriber<any>).hasChanged(newValue);
97        }
98        if ('propertyHasChanged' in owningProperty) {
99          (owningProperty as IMultiPropertiesChangeSubscriber).propertyHasChanged(propName);
100        }
101      } else {
102        stateMgmtConsole.error(`SubscribaleAbstract: notifyHasChanged: unknown subscriber.'${subscribedId}' error!.`);
103      }
104    });
105  }
106
107  /**
108   * Method used by the framework to add subscribing decorated variables
109   * Subclass may overwrite this function but must call the function of the base
110   * class from its own implementation.
111   * @param subscriber new subscriber that implements ISinglePropertyChangeSubscriber
112   * and/or IMultiPropertiesChangeSubscriber interfaces
113   *
114   * @since 9
115   */
116
117  public addOwningProperty(subscriber: IPropertySubscriber): void {
118    stateMgmtConsole.debug(`SubscribaleAbstract: addOwningProperty: subscriber '${subscriber.id__()}'.`)
119    this.owningProperties_.add(subscriber.id__());
120  }
121
122  /**
123   * Method used by the framework to ubsubscribing decorated variables
124   * Subclass may overwrite this function but must call the function of the base
125   * class from its own implementation.
126   * @param subscriber subscriber that implements ISinglePropertyChangeSubscriber
127   * and/or IMultiPropertiesChangeSubscriber interfaces
128   *
129   * @since 9
130   */
131  public removeOwningProperty(property: IPropertySubscriber): void {
132    return this.removeOwningPropertyById(property.id__());
133  }
134
135  /**
136   * Same as @see removeOwningProperty() but by Subscriber id.
137   * @param subscriberId
138  *
139  * @since 9
140   */
141  public removeOwningPropertyById(subscriberId: number): void {
142    stateMgmtConsole.debug(`SubscribaleAbstract: removeOwningProperty '${subscriberId}'.`)
143    this.owningProperties_.delete(subscriberId);
144  }
145}
146