1/* 2 * Copyright (c) 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 * ObservedPropertyObjectPU 18 * implementation of @State and @Provide decorated variables of type class object 19 * 20 * all definitions in this file are framework internal 21 * 22 * class that holds an actual property value of type T 23 * uses its base class to manage subscribers to this 24 * property. 25*/ 26 27class ObservedPropertyObjectPU<T extends Object> extends ObservedPropertyObjectAbstractPU<T> 28 implements PeerChangeEventReceiverPU<T>, 29 ObservedObjectEventsPUReceiver<T> { 30 31 private wrappedValue_: T; 32 33 constructor(value: T, owningView: IPropertySubscriber, propertyName: PropertyInfo) { 34 super(owningView, propertyName); 35 this.setValueInternal(value); 36 } 37 38 aboutToBeDeleted(unsubscribeMe?: IPropertySubscriber) { 39 this.unsubscribeFromOwningProperty(); 40 if (unsubscribeMe) { 41 this.unlinkSuscriber(unsubscribeMe.id__()); 42 } 43 super.aboutToBeDeleted(); 44 } 45 46 /** 47 * Called by a SynchedPropertyObjectTwoWayPU (@Link, @Consume) that uses this as sync peer when it has changed 48 * @param eventSource 49 */ 50 syncPeerHasChanged(eventSource : ObservedPropertyAbstractPU<T>) { 51 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: syncPeerHasChanged peer '${eventSource.info()}'.`); 52 this.notifyPropertyHasChangedPU(); 53 } 54 55 /** 56 * Wraped ObservedObjectPU has changed 57 * @param souceObject 58 * @param changedPropertyName 59 */ 60 public objectPropertyHasChangedPU(souceObject: ObservedObject<T>, changedPropertyName : string) { 61 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: \ 62 objectPropertyHasChangedPU: contained ObservedObject property '${changedPropertyName}' has changed.`) 63 this.notifyPropertyHasChangedPU(); 64 } 65 66 67 public objectPropertyHasBeenReadPU(souceObject: ObservedObject<T>, changedPropertyName : string) { 68 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: \ 69 objectPropertyHasBeenReadPU: contained ObservedObject property '${changedPropertyName}' has been read.`); 70 this.notifyPropertyHasBeenReadPU(); 71 } 72 73 private unsubscribeFromOwningProperty() { 74 if (this.wrappedValue_) { 75 if (this.wrappedValue_ instanceof SubscribaleAbstract) { 76 (this.wrappedValue_ as SubscribaleAbstract).removeOwningProperty(this); 77 } else { 78 ObservedObject.removeOwningProperty(this.wrappedValue_, this); 79 } 80 } 81 } 82 /* 83 actually update this.wrappedValue_ 84 called needs to do value change check 85 and also notify with this.aboutToChange(); 86 */ 87 private setValueInternal(newValue: T): boolean { 88 if (typeof newValue !== 'object') { 89 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is NOT an object. Application error. Ignoring set.`); 90 return false; 91 } 92 93 this.unsubscribeFromOwningProperty(); 94 95 if (ObservedObject.IsObservedObject(newValue)) { 96 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an ObservedObject already`); 97 ObservedObject.addOwningProperty(newValue, this); 98 this.wrappedValue_ = newValue; 99 } else if (newValue instanceof SubscribaleAbstract) { 100 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an SubscribaleAbstract, subscribiung to it.`); 101 this.wrappedValue_ = newValue; 102 (this.wrappedValue_ as unknown as SubscribaleAbstract).addOwningProperty(this); 103 } else { 104 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}'] new value is an Object, needs to be wrapped in an ObservedObject.`); 105 this.wrappedValue_ = ObservedObject.createNew(newValue, this); 106 } 107 return true; 108 } 109 110 public get(): T { 111 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: get`); 112 this.notifyPropertyHasBeenReadPU(); 113 return this.wrappedValue_; 114 } 115 116 public getUnmonitored(): T { 117 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: getUnmonitored returns '${JSON.stringify(this.wrappedValue_)}' .`); 118 // unmonitored get access , no call to otifyPropertyRead ! 119 return this.wrappedValue_; 120 } 121 122 public set(newValue: T): void { 123 if (this.wrappedValue_ == newValue) { 124 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: set with unchanged value - ignoring.`); 125 return; 126 } 127 stateMgmtConsole.debug(`ObservedPropertyObject[${this.id__()}, '${this.info() || "unknown"}']: set, changed`); 128 this.setValueInternal(newValue); 129 this.notifyPropertyHasChangedPU(); 130 } 131} 132