1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
|
17 | |
|
18 | |
|
19 | |
|
20 | |
|
21 | |
|
22 | |
|
23 | |
|
24 | |
|
25 | |
|
26 | |
|
27 | |
|
28 | |
|
29 | 1 | package org.vostokframework.application.monitoring.monitors |
30 | |
{ |
31 | |
import org.as3collections.IIterator; |
32 | |
import org.as3collections.IList; |
33 | |
import org.as3collections.IMap; |
34 | |
import org.as3collections.lists.ArrayList; |
35 | |
import org.as3collections.lists.TypedList; |
36 | |
import org.as3collections.maps.HashMap; |
37 | |
import org.as3collections.maps.TypedMap; |
38 | |
import org.vostokframework.VostokIdentification; |
39 | |
import org.vostokframework.application.monitoring.ILoadingMonitor; |
40 | |
import org.vostokframework.domain.loading.ILoader; |
41 | |
import org.vostokframework.domain.loading.errors.DuplicateLoadingMonitorError; |
42 | |
import org.vostokframework.domain.loading.errors.LoadingMonitorNotFoundError; |
43 | |
|
44 | |
import flash.events.TimerEvent; |
45 | |
import flash.utils.Timer; |
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
public class CompositeLoadingMonitor extends LoadingMonitor |
53 | |
{ |
54 | |
|
55 | |
|
56 | |
|
57 | |
private var _isFirstProgressDispatch:Boolean; |
58 | |
private var _lastPercent:int; |
59 | |
private var _monitors:IMap; |
60 | |
private var _monitorsListeners:IList; |
61 | |
private var _progressTimer:Timer; |
62 | |
private var _progressTimerDelay:int; |
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
public function CompositeLoadingMonitor(loader:ILoader, dispatcher:LoadingMonitorDispatcher) |
69 | |
{ |
70 | 1 | super(loader, dispatcher); |
71 | |
|
72 | 1 | _monitors = new TypedMap(new HashMap(), String, ILoadingMonitor); |
73 | 1 | _monitorsListeners = new TypedList(new ArrayList(), EventListener); |
74 | 1 | _progressTimerDelay = 50; |
75 | 1 | _progressTimer = new Timer(_progressTimerDelay); |
76 | 1 | _isFirstProgressDispatch = true; |
77 | |
|
78 | 1 | addTimerListener(); |
79 | 1 | } |
80 | |
|
81 | |
override public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void |
82 | |
{ |
83 | 1 | validateDisposal(); |
84 | |
|
85 | 1 | if (!dispatcher.typeBelongs(type)) |
86 | |
{ |
87 | 1 | var eventListener:EventListener = new EventListener(type, listener, useCapture, priority, useWeakReference); |
88 | 1 | _monitorsListeners.add(eventListener); |
89 | |
|
90 | 1 | addListenersOnMonitors(); |
91 | 1 | return; |
92 | |
} |
93 | |
|
94 | 1 | super.addEventListener(type, listener, useCapture, priority, useWeakReference); |
95 | 1 | } |
96 | |
|
97 | |
override public function addChild(child:ILoadingMonitor):void |
98 | |
{ |
99 | 1 | validateDisposal(); |
100 | |
|
101 | 1 | if (!child) throw new ArgumentError("Argument <child> must not be null."); |
102 | 1 | if (containsChild(child.loader.identification)) throw new DuplicateLoadingMonitorError("There is already an ILoadingMonitor object stored for a ILoader object with identification:\n<" + child.loader.identification + ">"); |
103 | |
|
104 | 1 | _monitors.put(child.loader.identification.toString(), child); |
105 | 1 | addListenersOnMonitors(); |
106 | 1 | } |
107 | |
|
108 | |
override public function addChildren(children:IList):void |
109 | |
{ |
110 | 1 | validateDisposal(); |
111 | |
|
112 | 1 | if (!children) throw new ArgumentError("Argument <children> must not be null."); |
113 | 1 | if (children.isEmpty()) return; |
114 | |
|
115 | 1 | var it:IIterator = children.iterator(); |
116 | |
var child:ILoadingMonitor; |
117 | |
|
118 | 1 | while (it.hasNext()) |
119 | |
{ |
120 | 1 | child = it.next(); |
121 | 1 | addChild(child); |
122 | |
} |
123 | 1 | } |
124 | |
|
125 | |
override public function containsChild(identification:VostokIdentification):Boolean |
126 | |
{ |
127 | 1 | if (_monitors.isEmpty()) return false; |
128 | |
|
129 | 1 | if (_monitors.containsKey(identification.toString())) |
130 | |
{ |
131 | 1 | return true; |
132 | |
} |
133 | |
|
134 | 1 | var it:IIterator = _monitors.iterator(); |
135 | |
var child:ILoadingMonitor; |
136 | |
|
137 | 1 | while (it.hasNext()) |
138 | |
{ |
139 | 1 | child = it.next(); |
140 | 1 | if (child.containsChild(identification)) return true; |
141 | |
} |
142 | |
|
143 | 1 | return false; |
144 | |
} |
145 | |
|
146 | |
override public function getChild(identification:VostokIdentification):ILoadingMonitor |
147 | |
{ |
148 | 1 | validateDisposal(); |
149 | |
|
150 | 1 | if (_monitors.containsKey(identification.toString())) |
151 | |
{ |
152 | 1 | return _monitors.getValue(identification.toString()); |
153 | |
} |
154 | |
else |
155 | |
{ |
156 | 1 | var it:IIterator = _monitors.iterator(); |
157 | |
var child:ILoadingMonitor; |
158 | |
|
159 | 1 | while (it.hasNext()) |
160 | |
{ |
161 | 1 | child = it.next(); |
162 | 1 | if (child.containsChild(identification)) return child.getChild(identification); |
163 | |
} |
164 | |
|
165 | 0 | var message:String = "There is no ILoadingMonitor object stored with identification:\n"; |
166 | 0 | message += "<" + identification + ">"; |
167 | 0 | throw new LoadingMonitorNotFoundError(message); |
168 | |
} |
169 | |
} |
170 | |
|
171 | |
override public function hasEventListener(type:String):Boolean |
172 | |
{ |
173 | 1 | validateDisposal(); |
174 | |
|
175 | 1 | if (!dispatcher.typeBelongs(type)) |
176 | |
{ |
177 | 1 | return monitorsHasEventListener(type); |
178 | |
} |
179 | |
|
180 | 0 | return super.hasEventListener(type); |
181 | |
} |
182 | |
|
183 | |
override public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void |
184 | |
{ |
185 | 1 | validateDisposal(); |
186 | |
|
187 | 1 | if (!dispatcher.typeBelongs(type)) |
188 | |
{ |
189 | 1 | removeListenerOnMonitors(type, listener, useCapture); |
190 | 1 | return; |
191 | |
} |
192 | |
|
193 | 1 | super.removeEventListener(type, listener, useCapture); |
194 | 1 | } |
195 | |
|
196 | |
override public function removeChild(identification:VostokIdentification):void |
197 | |
{ |
198 | 1 | validateDisposal(); |
199 | |
|
200 | 1 | if (_monitors.containsKey(identification.toString())) |
201 | |
{ |
202 | 1 | var monitor:ILoadingMonitor = _monitors.getValue(identification.toString()); |
203 | 1 | monitor.dispose(); |
204 | |
|
205 | 1 | _monitors.remove(identification.toString()); |
206 | |
} |
207 | |
else |
208 | |
{ |
209 | 0 | var it:IIterator = _monitors.iterator(); |
210 | |
var child:ILoadingMonitor; |
211 | |
|
212 | 0 | while (it.hasNext()) |
213 | |
{ |
214 | 0 | child = it.next(); |
215 | 0 | if (child.containsChild(identification)) |
216 | |
{ |
217 | 0 | child.removeChild(identification); |
218 | 0 | return; |
219 | |
} |
220 | |
} |
221 | |
|
222 | 0 | var message:String = "There is no ILoadingMonitor object stored with identification:\n"; |
223 | 0 | message += "<" + identification + ">"; |
224 | 0 | throw new LoadingMonitorNotFoundError(message); |
225 | |
} |
226 | 1 | } |
227 | |
|
228 | |
override public function willTrigger(type:String):Boolean |
229 | |
{ |
230 | 0 | validateDisposal(); |
231 | |
|
232 | 0 | if (!dispatcher.typeBelongs(type)) |
233 | |
{ |
234 | 0 | return monitorsWillTrigger(type); |
235 | |
} |
236 | |
|
237 | 0 | return super.willTrigger(type); |
238 | |
} |
239 | |
|
240 | |
override protected function doDispose():void |
241 | |
{ |
242 | 1 | removeListenersOnMonitors(); |
243 | 1 | removeTimerListener(); |
244 | 1 | _progressTimer.stop(); |
245 | 1 | _monitors.clear(); |
246 | 1 | _monitorsListeners.clear(); |
247 | |
|
248 | 1 | _monitors = null; |
249 | 1 | _monitorsListeners = null; |
250 | 1 | _progressTimer = null; |
251 | 1 | } |
252 | |
|
253 | |
override protected function loadingComplete():void |
254 | |
{ |
255 | 1 | _progressTimer.stop(); |
256 | 1 | _progressTimer.reset(); |
257 | 1 | } |
258 | |
|
259 | |
override protected function loadingStarted():void |
260 | |
{ |
261 | 1 | _progressTimer.start(); |
262 | 1 | } |
263 | |
|
264 | |
private function addListenersOnMonitors():void |
265 | |
{ |
266 | 1 | var itMonitors:IIterator = _monitors.iterator(); |
267 | |
var itListeners:IIterator; |
268 | |
var monitor:ILoadingMonitor; |
269 | |
var eventListener:EventListener; |
270 | |
|
271 | 1 | while (itMonitors.hasNext()) |
272 | |
{ |
273 | 1 | monitor = itMonitors.next(); |
274 | 1 | itListeners = _monitorsListeners.iterator(); |
275 | |
|
276 | 1 | while (itListeners.hasNext()) |
277 | |
{ |
278 | 1 | eventListener = itListeners.next(); |
279 | 1 | monitor.addEventListener(eventListener.type, eventListener.listener, eventListener.useCapture, eventListener.priority, eventListener.useWeakReference); |
280 | |
} |
281 | |
} |
282 | 1 | } |
283 | |
|
284 | |
private function addTimerListener():void |
285 | |
{ |
286 | 1 | _progressTimer.addEventListener(TimerEvent.TIMER, progressTimerEventHandler, false, 0, true); |
287 | 1 | } |
288 | |
|
289 | |
private function monitorsHasEventListener(type:String):Boolean |
290 | |
{ |
291 | 1 | if (_monitorsListeners.isEmpty()) return false; |
292 | |
|
293 | 1 | var it:IIterator = _monitorsListeners.iterator(); |
294 | |
var eventListener:EventListener; |
295 | |
|
296 | 1 | while (it.hasNext()) |
297 | |
{ |
298 | 1 | eventListener = it.next(); |
299 | 1 | if (eventListener.type == type) return true; |
300 | |
} |
301 | |
|
302 | 0 | return false; |
303 | |
} |
304 | |
|
305 | |
private function monitorsWillTrigger(type:String):Boolean |
306 | |
{ |
307 | 0 | if (_monitors.isEmpty()) return false; |
308 | |
|
309 | 0 | var monitor:ILoadingMonitor = _monitors.iterator().next(); |
310 | 0 | return monitor.willTrigger(type); |
311 | |
} |
312 | |
|
313 | |
private function progress():void |
314 | |
{ |
315 | 1 | validateDisposal(); |
316 | |
|
317 | 1 | var it:IIterator = _monitors.iterator(); |
318 | |
var monitor:ILoadingMonitor; |
319 | |
|
320 | |
var bytesLoaded:int; |
321 | |
var bytesTotal:int; |
322 | |
var totalLoadersHasBytesTotal:int; |
323 | |
var totalLoadersHasNotBytesTotal:int; |
324 | |
|
325 | 1 | while (it.hasNext()) |
326 | |
{ |
327 | 1 | monitor = it.next(); |
328 | |
|
329 | 1 | if (monitor.monitoring && monitor.monitoring.bytesTotal > 0) |
330 | |
{ |
331 | 1 | totalLoadersHasBytesTotal++; |
332 | 1 | bytesTotal += monitor.monitoring.bytesTotal; |
333 | 1 | bytesLoaded += monitor.monitoring.bytesLoaded; |
334 | |
} |
335 | |
} |
336 | |
|
337 | 1 | totalLoadersHasNotBytesTotal = _monitors.size() - totalLoadersHasBytesTotal; |
338 | |
|
339 | 1 | if (totalLoadersHasNotBytesTotal > 0) |
340 | |
{ |
341 | 1 | var fakeBytes:int = bytesTotal / totalLoadersHasBytesTotal; |
342 | 1 | bytesTotal += fakeBytes * totalLoadersHasNotBytesTotal; |
343 | |
} |
344 | |
|
345 | 1 | _lastPercent = monitoring.percent; |
346 | 1 | updateMonitoring(bytesTotal, bytesLoaded); |
347 | |
|
348 | 1 | if (monitoring.percent != _lastPercent || _isFirstProgressDispatch) dispatcher.dispatchProgressEvent(monitoring); |
349 | |
|
350 | 1 | _isFirstProgressDispatch = false; |
351 | 1 | } |
352 | |
|
353 | |
private function removeListenerOnMonitors(type:String, listener:Function, useCapture:Boolean = false):void |
354 | |
{ |
355 | 1 | var it:IIterator = _monitors.iterator(); |
356 | |
var monitor:ILoadingMonitor; |
357 | |
|
358 | 1 | while (it.hasNext()) |
359 | |
{ |
360 | 1 | monitor = it.next(); |
361 | 1 | monitor.removeEventListener(type, listener, useCapture); |
362 | |
} |
363 | |
|
364 | 1 | var eventListener:EventListener = new EventListener(type, listener, useCapture); |
365 | 1 | _monitorsListeners.remove(eventListener); |
366 | 1 | } |
367 | |
|
368 | |
private function removeListenersOnMonitors():void |
369 | |
{ |
370 | 1 | var itMonitors:IIterator = _monitors.iterator(); |
371 | |
var itListeners:IIterator; |
372 | |
var monitor:ILoadingMonitor; |
373 | |
var eventListener:EventListener; |
374 | |
|
375 | 1 | while (itMonitors.hasNext()) |
376 | |
{ |
377 | 1 | monitor = itMonitors.next(); |
378 | 1 | itListeners = _monitorsListeners.iterator(); |
379 | |
|
380 | 1 | while (itListeners.hasNext()) |
381 | |
{ |
382 | 1 | eventListener = itListeners.next(); |
383 | 1 | monitor.removeEventListener(eventListener.type, eventListener.listener, eventListener.useCapture); |
384 | |
} |
385 | |
} |
386 | 1 | } |
387 | |
|
388 | |
private function removeTimerListener():void |
389 | |
{ |
390 | 1 | _progressTimer.removeEventListener(TimerEvent.TIMER, progressTimerEventHandler, false); |
391 | 1 | } |
392 | |
|
393 | |
private function progressTimerEventHandler(event:TimerEvent):void |
394 | |
{ |
395 | 1 | progress(); |
396 | 1 | } |
397 | |
|
398 | |
} |
399 | |
|
400 | |
} |