| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 part of service; |
| 6 |
| 7 /// A [ServiceObject] is an object known to the VM service and is tied |
| 8 /// to an owning [Isolate]. |
| 9 abstract class ServiceObject extends Observable { |
| 10 Isolate _isolate; |
| 11 |
| 12 /// Owning isolate. |
| 13 Isolate get isolate => _isolate; |
| 14 |
| 15 /// Owning vm. |
| 16 VM get vm => _isolate.vm; |
| 17 |
| 18 /// The complete service url of this object. |
| 19 String get link => isolate.relativeLink(_id); |
| 20 |
| 21 /// The complete service url of this object with a '#/' prefix. |
| 22 String get hashLink => isolate.relativeHashLink(_id); |
| 23 |
| 24 String _id; |
| 25 /// The id of this object. |
| 26 String get id => _id; |
| 27 |
| 28 String _serviceType; |
| 29 /// The service type of this object. |
| 30 String get serviceType => _serviceType; |
| 31 |
| 32 bool _ref; |
| 33 |
| 34 @observable String name; |
| 35 @observable String vmName; |
| 36 |
| 37 ServiceObject(this._isolate, this._id, this._serviceType) { |
| 38 _ref = isRefType(_serviceType); |
| 39 _serviceType = stripRef(_serviceType); |
| 40 _created(); |
| 41 } |
| 42 |
| 43 ServiceObject.fromMap(this._isolate, ObservableMap m) { |
| 44 assert(isServiceMap(m)); |
| 45 _id = m['id']; |
| 46 _ref = isRefType(m['type']); |
| 47 _serviceType = stripRef(m['type']); |
| 48 _created(); |
| 49 update(m); |
| 50 } |
| 51 |
| 52 /// If [this] was created from a reference, load the full object |
| 53 /// from the service by calling [reload]. Else, return [this]. |
| 54 Future<ServiceObject> load() { |
| 55 if (!_ref) { |
| 56 // Not a reference. |
| 57 return new Future.value(this); |
| 58 } |
| 59 // Call refresh which will fill in the entire object. |
| 60 return reload(); |
| 61 } |
| 62 |
| 63 /// Reload [this]. Returns a future which completes to [this] or |
| 64 /// a [ServiceError]. |
| 65 Future<ServiceObject> reload() { |
| 66 assert(isolate != null); |
| 67 if (id == '') { |
| 68 // Errors don't have ids. |
| 69 assert(serviceType == 'Error'); |
| 70 return new Future.value(this); |
| 71 } |
| 72 return isolate.vm.getAsMap(link).then(update); |
| 73 } |
| 74 |
| 75 /// Update [this] using [m] as a source. [m] can be a reference. |
| 76 ServiceObject update(ObservableMap m) { |
| 77 // Assert that m is a service map. |
| 78 assert(ServiceObject.isServiceMap(m)); |
| 79 if ((m['type'] == 'Error') && (_serviceType != 'Error')) { |
| 80 // Got an unexpected error. Don't update the object. |
| 81 return _upgradeToServiceObject(vm, isolate, m); |
| 82 } |
| 83 // TODO(johnmccutchan): Should we allow for a ServiceObject's id |
| 84 // or type to change? |
| 85 _id = m['id']; |
| 86 _serviceType = stripRef(m['type']); |
| 87 _update(m); |
| 88 return this; |
| 89 } |
| 90 |
| 91 // update internal state from [map]. [map] can be a reference. |
| 92 void _update(ObservableMap map); |
| 93 |
| 94 /// Returns true if [this] has only been partially initialized via |
| 95 /// a reference. See [load]. |
| 96 bool isRef() => _ref; |
| 97 |
| 98 void _created() { |
| 99 var refNotice = _ref ? ' Created from reference.' : ''; |
| 100 Logger.root.info('Created ServiceObject for \'${_id}\' with type ' |
| 101 '\'${_serviceType}\'.' + refNotice); |
| 102 } |
| 103 |
| 104 /// Returns true if [map] is a service map. i.e. it has the following keys: |
| 105 /// 'id' and a 'type'. |
| 106 static bool isServiceMap(ObservableMap m) { |
| 107 return (m != null) && (m['id'] != null) && (m['type'] != null); |
| 108 } |
| 109 |
| 110 /// Returns true if [type] is a reference type. i.e. it begins with an |
| 111 /// '@' character. |
| 112 static bool isRefType(String type) { |
| 113 return type.startsWith('@'); |
| 114 } |
| 115 |
| 116 /// Returns the unreffed version of [type]. |
| 117 static String stripRef(String type) { |
| 118 if (!isRefType(type)) { |
| 119 return type; |
| 120 } |
| 121 // Strip off the '@' character. |
| 122 return type.substring(1); |
| 123 } |
| 124 } |
| 125 |
| 126 /// Recursively upgrades all [ServiceObject]s inside [collection] which must |
| 127 /// be an [ObservableMap] or an [ObservableList]. Upgraded elements will be |
| 128 /// associated with [vm] and [isolate]. |
| 129 void upgradeCollection(collection, VM vm, Isolate isolate) { |
| 130 if (collection is ObservableMap) { |
| 131 _upgradeObservableMap(collection, vm, isolate); |
| 132 } else if (collection is ObservableList) { |
| 133 _upgradeObservableList(collection, vm, isolate); |
| 134 } |
| 135 } |
| 136 |
| 137 void _upgradeObservableMap(ObservableMap map, VM vm, Isolate isolate) { |
| 138 map.forEach((k, v) { |
| 139 if ((v is ObservableMap) && ServiceObject.isServiceMap(v)) { |
| 140 map[k] = v = _upgradeToServiceObject(vm, isolate, v); |
| 141 } else if (v is ObservableList) { |
| 142 _upgradeObservableList(v, vm, isolate); |
| 143 } else if (v is ObservableMap) { |
| 144 _upgradeObservableMap(v, vm, isolate); |
| 145 } |
| 146 }); |
| 147 } |
| 148 |
| 149 void _upgradeObservableList(ObservableList list, VM vm, Isolate isolate) { |
| 150 for (var i = 0; i < list.length; i++) { |
| 151 var v = list[i]; |
| 152 if ((v is ObservableMap) && ServiceObject.isServiceMap(v)) { |
| 153 list[i] = _upgradeToServiceObject(vm, isolate, v); |
| 154 } else if (v is ObservableList) { |
| 155 _upgradeObservableList(v, vm, isolate); |
| 156 } else if (v is ObservableMap) { |
| 157 _upgradeObservableMap(v, vm, isolate); |
| 158 } |
| 159 } |
| 160 } |
| 161 |
| 162 /// Upgrades response ([m]) from [vm] and [isolate] to a [ServiceObject]. |
| 163 /// This acts like a factory which consumes an ObservableMap and returns |
| 164 /// a fully upgraded ServiceObject. |
| 165 ServiceObject _upgradeToServiceObject(VM vm, Isolate isolate, ObservableMap m) { |
| 166 assert(ServiceObject.isServiceMap(m)); |
| 167 var type = ServiceObject.stripRef(m['type']); |
| 168 switch (type) { |
| 169 case 'Error': |
| 170 return new ServiceError.fromMap(isolate, m); |
| 171 case 'IsolateList': |
| 172 vm.isolates.update(m); |
| 173 return vm.isolates; |
| 174 case 'Script': |
| 175 return isolate.scripts.putIfAbsent(m); |
| 176 case 'Code': |
| 177 return isolate.codes.putIfAbsent(m); |
| 178 case 'Isolate': |
| 179 return vm.isolates.getIsolateFromMap(m); |
| 180 case 'Class': |
| 181 return isolate.classes.putIfAbsent(m); |
| 182 } |
| 183 return new ServiceMap.fromMap(isolate, m); |
| 184 } |
| OLD | NEW |