1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package fulmine.model.component;
17
18 import static fulmine.util.Utils.EMPTY_STRING;
19 import static fulmine.util.Utils.logException;
20 import static fulmine.util.Utils.safeToString;
21 import static fulmine.util.Utils.string;
22
23 import java.util.Collections;
24 import java.util.List;
25
26 import fulmine.AbstractLifeCycle;
27 import fulmine.Addressable;
28 import fulmine.IAddressable;
29 import fulmine.IDomain;
30 import fulmine.IType;
31 import fulmine.context.IFrameworkContext;
32 import fulmine.event.IEvent;
33 import fulmine.event.IEventFrameExecution;
34 import fulmine.event.IEventSource;
35 import fulmine.event.listener.IEventListener;
36 import fulmine.event.listener.IPriorityEventListener;
37 import fulmine.event.system.ISystemEvent;
38 import fulmine.event.system.ISystemEventListener;
39 import fulmine.protocol.wire.IWireIdentity;
40 import fulmine.protocol.wire.IWireState;
41 import fulmine.protocol.wire.operation.IOperationScope;
42 import fulmine.util.array.ArrayUtils;
43 import fulmine.util.collection.ReferenceCountingList;
44 import fulmine.util.log.AsyncLog;
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public abstract class AbstractComponent extends AbstractLifeCycle implements
62 IComponent, Cloneable
63 {
64 private final static AsyncLog LOG = new AsyncLog(AbstractComponent.class);
65
66
67 private final IAddressable id;
68
69
70 private final byte eventGroupId;
71
72
73 private volatile byte isClone;
74
75
76 private IEventFrameExecution drivingFrame;
77
78
79 private IEventFrameExecution currentFrame;
80
81
82
83
84
85
86 private volatile List<IEventListener> listeners;
87
88
89
90
91
92
93 private IEventSource source = this;
94
95
96
97
98
99
100
101
102
103
104
105
106 protected AbstractComponent(String identity, IType type, IDomain domain)
107 {
108
109 this(identity, type, domain, (byte) 0);
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123
124 protected AbstractComponent(String identity, IType type, IDomain domain,
125 byte eventGroupId)
126 {
127 super();
128 this.id = new Addressable(identity, type, domain);
129
130
131
132
133 if (identity.indexOf("**") > -1)
134 {
135 throw new RuntimeException(
136 "Containers cannot have the following characters '**', attempted identity "
137 + identity + " for " + type + ", " + domain);
138 }
139 this.eventGroupId = eventGroupId;
140 }
141
142 public final byte getEventSourceGroupId()
143 {
144 return this.eventGroupId;
145 }
146
147 public final String getIdentity()
148 {
149 return this.getAddressable().getIdentity();
150 }
151
152 public final IType getType()
153 {
154 return this.getAddressable().getType();
155 }
156
157 public final IDomain getDomain()
158 {
159 return this.getAddressable().getDomain();
160 }
161
162 public final String getAddress()
163 {
164 return this.getAddressable().getAddress();
165 }
166
167 public final IEventSource getSource()
168 {
169 return this.source;
170 }
171
172 public final IEventFrameExecution getDrivingFrame()
173 {
174 return this.drivingFrame;
175 }
176
177 public final IEventFrameExecution getFrame()
178 {
179 return this.currentFrame;
180 }
181
182
183
184
185
186
187
188
189
190
191
192 public final void setFrame(IEventFrameExecution frame)
193 {
194 this.currentFrame = frame;
195 }
196
197
198
199
200
201
202
203 protected final void setDrivingFrame(IEventFrameExecution drivingFrame)
204 {
205 this.drivingFrame = drivingFrame;
206 }
207
208 public final void readState(IOperationScope scope, byte[] dataBuffer,
209 int start, int numberOfBytes)
210 {
211 boolean processed = false;
212 try
213 {
214 if (scope.include(this))
215 {
216 processed =
217 doReadState(scope, dataBuffer, start, numberOfBytes);
218 scope.exiting(this, processed);
219 }
220 }
221 catch (Exception e)
222 {
223 scope.exception(this, e);
224 }
225 }
226
227 public final void writeState(IOperationScope scope, IWireIdentity wireId,
228 byte[][] headerBuffer, int[] headerBufferPosition, byte[][] dataBuffer,
229 int[] dataBufferPosition, boolean completeState)
230 {
231 boolean processed = false;
232 try
233 {
234 if (scope.include(this))
235 {
236 processed =
237 doWriteState(scope, wireId, headerBuffer,
238 headerBufferPosition, dataBuffer, dataBufferPosition,
239 completeState);
240 scope.exiting(this, processed);
241 }
242 }
243 catch (Exception e)
244 {
245 scope.exception(this, e);
246 }
247 }
248
249
250
251
252 public void addEvent(IEvent event)
253 {
254 final List<IEventListener> listeners = getListeners();
255 for (IEventListener eventListener : listeners)
256 {
257 eventListener.update(event);
258 }
259 }
260
261 public final boolean addListener(IEventListener listener)
262 {
263 if (this instanceof ISystemEvent
264 && !(listener instanceof ISystemEventListener))
265 {
266 throw new IllegalArgumentException(this + " can only have "
267 + ISystemEventListener.class.getSimpleName()
268 + " instances added as listeners.");
269 }
270 boolean added = false;
271 List<IEventListener> copy = null;
272
273 synchronized (this)
274 {
275 if (this.listeners == null)
276 {
277 copy = new ReferenceCountingList<IEventListener>(0);
278 }
279 else
280 {
281 copy =
282 new ReferenceCountingList<IEventListener>(this.listeners);
283 }
284 if (listener instanceof IPriorityEventListener)
285 {
286 added = !copy.contains(listener);
287 copy.add(0, listener);
288 }
289 else
290 {
291 added = copy.add(listener);
292 }
293 this.listeners = copy;
294 if (added)
295 {
296 doPostAddListener(listener);
297 }
298 }
299 if (added)
300 {
301 try
302 {
303 listener.addedAsListenerFor(this);
304 }
305 catch (Exception e)
306 {
307 logException(getLog(), this, e);
308 }
309 if (getLog().isDebugEnabled())
310 {
311 getLog().debug(
312 "Added listener " + safeToString(listener) + " to source "
313 + createIdentityString());
314 }
315 }
316 return added;
317 }
318
319 public final List<IEventListener> getListeners()
320 {
321 final List<IEventListener> local = this.listeners;
322 if (local == null)
323 {
324 return Collections.emptyList();
325 }
326
327 return Collections.unmodifiableList(local);
328 }
329
330 public final boolean removeListener(IEventListener listener)
331 {
332
333
334
335
336
337
338 if (!isActive())
339 {
340 return false;
341 }
342 List<IEventListener> copy = null;
343 boolean removed = false;
344
345 synchronized (this)
346 {
347 final List<IEventListener> local = this.listeners;
348 if (local == null)
349 {
350 return false;
351 }
352 copy = new ReferenceCountingList<IEventListener>(local);
353 removed = copy.remove(listener);
354 if (copy.size() == 0)
355 {
356 this.listeners = null;
357 }
358 else
359 {
360 this.listeners = copy;
361 }
362 if (removed)
363 {
364 doPostRemoveListener(listener);
365 }
366 }
367 if (removed)
368 {
369 try
370 {
371 listener.removedAsListenerFrom(this);
372 }
373 catch (Exception e)
374 {
375 logException(getLog(), this, e);
376 }
377 if (getLog().isDebugEnabled())
378 {
379 getLog().debug(
380 "Removed listener " + safeToString(listener)
381 + " from source " + createIdentityString());
382 }
383 }
384 return removed;
385 }
386
387 public final List<IEventListener> removeListeners()
388 {
389 synchronized (this)
390 {
391 final List<IEventListener> local = this.listeners;
392 if (local == null)
393 {
394 return Collections.emptyList();
395 }
396
397 final List<IEventListener> copy =
398 new ReferenceCountingList<IEventListener>(local);
399 for (IEventListener eventListener : copy)
400 {
401 try
402 {
403 removeListener(eventListener);
404 }
405 catch (Exception e)
406 {
407 logException(getLog(), eventListener, e);
408 }
409 }
410 return copy;
411 }
412 }
413
414
415
416
417
418
419
420
421
422 protected void doPostAddListener(IEventListener listener)
423 {
424
425 }
426
427
428
429
430
431
432
433
434
435 protected void doPostRemoveListener(IEventListener listener)
436 {
437
438 }
439
440 @Override
441 protected void doStart()
442 {
443
444 }
445
446 @Override
447 protected final void doDestroy()
448 {
449 if (!isClone())
450 {
451 doComponentDestroy();
452 }
453 }
454
455
456
457
458 protected void doComponentDestroy()
459 {
460 this.currentFrame = null;
461 this.drivingFrame = null;
462
463
464 }
465
466
467
468
469
470
471
472 protected final void checkClone()
473 {
474 if (isClone())
475 {
476 throw new IllegalStateException(
477 "This is a clone and cannot be altered");
478 }
479 }
480
481
482
483
484
485
486 public final boolean isClone()
487 {
488 return this.isClone == 1;
489 }
490
491
492
493
494
495
496 protected final String createIdentityString()
497 {
498 return string(this, getAddress());
499 }
500
501
502
503
504
505
506
507
508 protected StringBuilder getIdentityString()
509 {
510 StringBuilder sb = new StringBuilder();
511 sb.append((isClone == 1 ? "[clone]" : EMPTY_STRING)).append(
512 getIdentity());
513 return sb;
514 }
515
516
517
518
519
520
521
522
523
524
525
526
527
528 protected abstract boolean doWriteState(IOperationScope scope,
529 IWireIdentity wireId, byte[][] headerBuffer,
530 int[] headerBufferPosition, byte[][] dataBuffer,
531 int[] dataBufferPosition, boolean completeState) throws Exception;
532
533
534
535
536
537
538
539
540
541
542 protected abstract boolean doReadState(IOperationScope scope,
543 byte[] buffer, int start, int numberOfBytes) throws Exception;
544
545 public String toDetailedString()
546 {
547 return createIdentityString();
548 }
549
550 public String toIdentityString()
551 {
552 return createIdentityString();
553 }
554
555 public IEvent getTriggerEvent()
556 {
557
558 return null;
559 }
560
561 public void setTriggerEvent(IEvent triggerEvent)
562 {
563
564 }
565
566 @Override
567 protected AsyncLog getLog()
568 {
569 return LOG;
570 }
571
572 public final IAddressable getAddressable()
573 {
574 return id;
575 }
576
577 @Override
578 public String toString()
579 {
580 return createIdentityString();
581 }
582
583 @Override
584 public Object clone() throws CloneNotSupportedException
585 {
586 final AbstractComponent clone = (AbstractComponent) super.clone();
587 clone.isClone = 1;
588 clone.source = this;
589 return clone;
590 }
591
592 @Override
593 public int hashCode()
594 {
595 return this.getAddressable().hashCode();
596 }
597
598 @Override
599 public boolean equals(Object obj)
600 {
601 return this.getAddressable().equals(obj);
602 }
603 }