Subversion Repository Public Repository

litesoft

Diff Revisions 948 vs 950 for /trunk/Java/GWT/OldServer/src/org/litesoft/GWT/eventbus/server/nonpublic/ServerEventBusManager.java

Diff revisions: vs.
  @@ -1,461 +1,461 @@
1 - // This Source Code is in the Public Domain per: http://unlicense.org
2 - package org.litesoft.GWT.eventbus.server.nonpublic;
3 -
4 - import org.litesoft.GWT.eventbus.client.*;
5 - import org.litesoft.GWT.eventbus.client.nonpublic.*;
6 - import org.litesoft.GWT.eventbus.server.*;
7 - import org.litesoft.commonfoundation.typeutils.Objects;
8 - import org.litesoft.logger.*;
9 - import org.litesoft.sequences.*;
10 -
11 - import javax.servlet.http.*;
12 - import java.util.*;
13 -
14 - public class ServerEventBusManager implements ServerEventBusBroadcaster {
15 - private static final Logger LOGGER = LoggerFactory.getLogger( ServerEventBusManager.class );
16 -
17 - public static final ServerEventBusManager INSTANCE = new ServerEventBusManager();
18 -
19 - private ServerEventBusManager() {
20 - }
21 -
22 - private static final String SERVER_EVENT_BUSES = "ServerEventBuses";
23 - private static final Long MAX_CLIENT_ID = (long) (Integer.MAX_VALUE - 2000);
24 - private static SequenceSource sClientIdNumberSequenceSource = SequenceSource.NULL;
25 -
26 - public static synchronized void setClientIdNumberSequenceSource( SequenceSource pSequenceSource ) {
27 - sClientIdNumberSequenceSource = (pSequenceSource != null) ? pSequenceSource : SequenceSource.NULL;
28 - }
29 -
30 - public static synchronized int getNextClientIdNumber() {
31 - long cid = sClientIdNumberSequenceSource.getNextSequenceNumber( SERVER_EVENT_BUSES, MAX_CLIENT_ID );
32 - return (int) cid;
33 - }
34 -
35 - private final NodeMap mNodes = new NodeMap();
36 -
37 - public EventPackage getPackageForNewServerEventBus( int pClientIdNumber ) {
38 - return null;
39 - }
40 -
41 - public TemporaryServerEventBus createTemporaryServerEventBus( String pWhy, ServerEventBus pParent,
42 - ClientWindowInstanceDataManager pInitialClientWindowInstanceData ) {
43 - int zClientIdNumber = getNextClientIdNumber();
44 -
45 - TemporaryServerEventBus zTempSEB = new TemporaryServerEventBus( zClientIdNumber );
46 -
47 - synchronized ( mNodes ) {
48 - zTempSEB.initialize( pWhy, pParent.getClientIdNumber(), pInitialClientWindowInstanceData );
49 - }
50 -
51 - // Force use of same stuff
52 - ServerEventBusSessionMapper.addServerEventBus( pParent, zTempSEB );
53 -
54 - return zTempSEB;
55 - }
56 -
57 - public TemporaryServerEventBus createTemporaryServerEventBus( String pWhy, HttpServletRequest pRequest,
58 - ThreadLocalContextFactory pThreadLocalContextFactory,
59 - ClientWindowInstanceDataManager pInitialClientWindowInstanceData ) {
60 - int zClientIdNumber = getNextClientIdNumber();
61 -
62 - TemporaryServerEventBus zTempSEB = new TemporaryServerEventBus( zClientIdNumber );
63 -
64 - synchronized ( mNodes ) {
65 - zTempSEB.initialize( pWhy, null, pInitialClientWindowInstanceData );
66 - }
67 -
68 - ServerEventBusSessionMapper.addServerEventBus( pRequest, pThreadLocalContextFactory, zTempSEB );
69 -
70 - return zTempSEB;
71 - }
72 -
73 - /**
74 - * @return may return null
75 - */
76 - public Integer getParentClientID( int pClientIdNumber ) {
77 - return mNodes.getNode( pClientIdNumber ).getParentClientID();
78 - }
79 -
80 - /**
81 - * @return may return null
82 - */
83 - public ServerEventBus getServerEventBus( int pClientIdNumber ) {
84 - return mNodes.getServerEventBusOrDisposedZombie( pClientIdNumber );
85 - }
86 -
87 - /**
88 - * @return may return null
89 - */
90 - public ServerEventBus getRootServerEventBus( int pClientIdNumber ) {
91 - return mNodes.getRootNode( pClientIdNumber ).getServerEventBus();
92 - }
93 -
94 - /**
95 - * @return may return null
96 - */
97 - public ServerEventBus getParentServerEventBus( int pClientIdNumber ) {
98 - return mNodes.getParentNode( pClientIdNumber ).getServerEventBus();
99 - }
100 -
101 - /**
102 - * @return may return an empty array, but never null
103 - */
104 - public ServerEventBus[] getAllServerEventBuses() {
105 - return SelectorAll.INSTANCE.select( mNodes.getNodes() );
106 - }
107 -
108 - /**
109 - * @return may return an empty array, but never null
110 - */
111 - public ServerEventBus[] getChildrenServerEventBuses( int pClientIdNumber ) {
112 - return new SelectorChildren( pClientIdNumber ).select( mNodes.getNodes() );
113 - }
114 -
115 - /**
116 - * @return may return an empty array, but never null
117 - */
118 - public ServerEventBus[] getAllRelatedServerEventBuses( int pClientIdNumber ) {
119 - Node rootNode = mNodes.getRootNode( pClientIdNumber );
120 - return rootNode.isReal() ? //
121 - new SelectorAllRelated().select( rootNode, mNodes.getNodes() ) : //
122 - ServerEventBus.EMPTY_ARRAY;
123 - }
124 -
125 - public void broadcast( EventPackage pEventPackage ) {
126 - if ( pEventPackage != null ) {
127 - ServerEventBus[] buses = getAllServerEventBuses();
128 - if ( buses != null ) {
129 - for ( ServerEventBus bus : buses ) {
130 - if ( bus != null ) {
131 - bus.publishIfNotDisposed( pEventPackage );
132 - }
133 - }
134 - }
135 - }
136 - }
137 -
138 - public static class BackDoor {
139 - public static ServerEventBus updateServerEventBus( ServerEventBus pNewSEB, Integer pParentClientID ) {
140 - return ServerEventBusManager.INSTANCE.mNodes.updateServerEventBus( pNewSEB, pParentClientID );
141 - }
142 - }
143 -
144 - private static class Node {
145 - private int mClientID;
146 - private Integer mParentClientID;
147 - private ServerEventBus mServerEventBus;
148 - private int mChildCount = 0;
149 -
150 - public Node( Integer pParentClientID, int pClientID, ServerEventBus pServerEventBus ) {
151 - mParentClientID = pParentClientID;
152 - mClientID = pClientID;
153 - mServerEventBus = pServerEventBus;
154 - }
155 -
156 - public String toString() {
157 - return "" + mClientID + ":" + ((getServerEventBus() != null) ? "SEB" : "---") + " ^" +
158 - mParentClientID + " c:" + mChildCount;
159 - }
160 -
161 - public int getClientID() {
162 - return mClientID;
163 - }
164 -
165 - public Integer getParentClientID() {
166 - return mParentClientID;
167 - }
168 -
169 - public synchronized ServerEventBus getServerEventBus() {
170 - return mServerEventBus;
171 - }
172 -
173 - public synchronized void replaceServerEventBus( ServerEventBus pServerEventBus ) {
174 - mServerEventBus = pServerEventBus;
175 - }
176 -
177 - public synchronized ServerEventBus clearServerEventBus() {
178 - ServerEventBus rv = mServerEventBus;
179 - mServerEventBus = null;
180 - return rv;
181 - }
182 -
183 - public synchronized boolean shouldRemove() {
184 - return isReal() && (mServerEventBus == null) && (mChildCount < 1);
185 - }
186 -
187 - public synchronized void incChildCount() {
188 - mChildCount++;
189 - }
190 -
191 - public synchronized void decChildCount() {
192 - mChildCount--;
193 - }
194 -
195 - public boolean isReal() {
196 - return true;
197 - }
198 - }
199 -
200 - private static final Node NULL_NODE = new Node( null, 0, null ) {
201 - public boolean isReal() {
202 - return false;
203 - }
204 -
205 - public void incChildCount() {
206 - }
207 -
208 - public void decChildCount() {
209 - }
210 - };
211 -
212 - private abstract static class AbstractSelector {
213 - public ServerEventBus[] select( Node[] pNodes ) {
214 - List<ServerEventBus> buses = new ArrayList<ServerEventBus>();
215 - addAppropriate( buses, pNodes );
216 - return buses.toArray( new ServerEventBus[buses.size()] );
217 - }
218 -
219 - protected void addAppropriate( List<ServerEventBus> pBuses, Node[] pNodes ) {
220 - for ( Node node : pNodes ) {
221 - ServerEventBus seb = node.getServerEventBus();
222 - if ( (seb != null) && acceptable( node, seb ) ) {
223 - pBuses.add( seb );
224 - }
225 - }
226 - }
227 -
228 - protected boolean acceptable( Node pNode, ServerEventBus pSEB ) {
229 - return true;
230 - }
231 - }
232 -
233 - private static class SelectorAll extends AbstractSelector {
234 - public static final AbstractSelector INSTANCE = new SelectorAll();
235 - }
236 -
237 - private static class SelectorChildren extends AbstractSelector {
238 - private Integer mParentID;
239 -
240 - public SelectorChildren( int pParentID ) {
241 - mParentID = pParentID;
242 - }
243 -
244 - protected boolean acceptable( Node pNode, ServerEventBus pSEB ) {
245 - return mParentID.equals( pNode.getParentClientID() );
246 - }
247 - }
248 -
249 - private static class SelectorAllRelated {
250 - public ServerEventBus[] select( Node pRoot, Node[] pNodes ) {
251 - List<ServerEventBus> buses = new ArrayList<ServerEventBus>();
252 - new Adder( buses, pNodes ).addAppropriate( pRoot );
253 - return buses.toArray( new ServerEventBus[buses.size()] );
254 - }
255 -
256 - private static class Adder {
257 - private List<ServerEventBus> mBuses;
258 - private Node[] mNodes;
259 -
260 - public Adder( List<ServerEventBus> pBuses, Node[] pNodes ) {
261 - mBuses = pBuses;
262 - mNodes = pNodes;
263 - }
264 -
265 - public void addAppropriate( Node pCurrent ) {
266 - ServerEventBus seb = pCurrent.getServerEventBus();
267 - if ( seb != null ) {
268 - mBuses.add( seb );
269 - }
270 - Integer parentID = pCurrent.getClientID();
271 - for ( Node node : mNodes ) {
272 - if ( parentID.equals( node.getParentClientID() ) ) {
273 - addAppropriate( node );
274 - }
275 - }
276 - }
277 - }
278 - }
279 -
280 - private static class NodeMap implements ServerEventBusDisposeListener {
281 - private final Map<Integer, Node> mServerEventBusNodes = new HashMap<Integer, Node>();
282 - private final Set<Integer> mDisposedServerEventBuses = new HashSet<Integer>();
283 -
284 - public Node getNode( Integer pClientIdNumberFromParentReference ) {
285 - return (pClientIdNumberFromParentReference == null) ? //
286 - NULL_NODE : //
287 - getNode( pClientIdNumberFromParentReference.intValue() );
288 - }
289 -
290 - public Node getNode( int pClientIdNumber ) {
291 - Node node = getRealNode( pClientIdNumber );
292 - return (node != null) ? node : NULL_NODE;
293 - }
294 -
295 - public Node getRequiredNode( int pClientIdNumber ) {
296 - Node node = getRealNode( pClientIdNumber );
297 - if ( node == null ) {
298 - throw new IllegalStateException( "No ServerEventBus Node for ClientID: " + pClientIdNumber );
299 - }
300 - return node;
301 - }
302 -
303 - // from ServerEventBusDisposeListener
304 - public void init( IServerEventBus pServerEventBus ) {
305 - }
306 -
307 - // from ServerEventBusDisposeListener
308 - public void disposing( IServerEventBus pServerEventBus ) {
309 - int clientId = pServerEventBus.getClientIdNumber();
310 -
311 - List<ServerEventBus> mAncestors = Collections.emptyList();
312 -
313 - ServerEventBus zExistingSEB;
314 -
315 - synchronized ( this ) {
316 - Node node = getNode( clientId );
317 - zExistingSEB = node.clearServerEventBus();
318 - if ( null != zExistingSEB ) {
319 - mAncestors = getAncestors( node );
320 -
321 - mDisposedServerEventBuses.add( clientId );
322 - }
323 -
324 - while ( node.shouldRemove() ) {
325 - mServerEventBusNodes.remove( node.getClientID() );
326 - node = getNode( node.getParentClientID() );
327 - node.decChildCount();
328 - }
329 - }
330 -
331 - if ( zExistingSEB instanceof NonTemporaryServerEventBus ) {
332 - LOGGER.debug.log( "---Disposed: ", zExistingSEB );
333 - }
334 -
335 - notifyAncestorsOfRemovedDecendant( mAncestors, clientId );
336 - }
337 -
338 - public synchronized ServerEventBus getServerEventBusOrDisposedZombie( int pClientIdNumber ) {
339 - ServerEventBus zBus = getNode( pClientIdNumber ).getServerEventBus();
340 - if ( zBus != null ) {
341 - return zBus;
342 - }
343 - return mDisposedServerEventBuses.contains( pClientIdNumber ) ? //
344 - ZombieServerEventBus.INSTANCE : //
345 - null;
346 - }
347 -
348 - public synchronized Node getRealNode( int pClientIdNumber ) {
349 - return mServerEventBusNodes.get( pClientIdNumber );
350 - }
351 -
352 - public synchronized Node[] getNodes() {
353 - return mServerEventBusNodes.values().toArray( new Node[mServerEventBusNodes.size()] );
354 - }
355 -
356 - public synchronized Node getParentNode( int pClientIdNumber ) {
357 - Integer parentClientID = getNode( pClientIdNumber ).getParentClientID();
358 - return getNode( parentClientID );
359 - }
360 -
361 - public synchronized Node getRootNode( int pClientIdNumber ) {
362 - Node node = getNode( pClientIdNumber );
363 - for ( Integer parentClientID; null != (parentClientID = node.getParentClientID()); ) {
364 - node = getNode( parentClientID );
365 - }
366 - return node;
367 - }
368 -
369 - public ServerEventBus updateServerEventBus( ServerEventBus pNewSEB, Integer pParentClientID ) {
370 - if ( !pNewSEB.getType().isManagable() ) {
371 - throw badType( "Managable", pNewSEB );
372 - }
373 -
374 - int clientId = pNewSEB.getClientIdNumber();
375 -
376 - ServerEventBus zExistingSEB = null;
377 -
378 - List<ServerEventBus> mAncestors = Collections.emptyList();
379 -
380 - synchronized ( this ) {
381 - Node node = getRealNode( clientId );
382 - if ( node != null ) {
383 - zExistingSEB = node.getServerEventBus();
384 - if ( zExistingSEB != null ) {
385 - mAncestors = getAncestors( node );
386 -
387 - // Since we are replacing we do NOT want to get the dispose notice on the old!
388 - zExistingSEB.removeListener( this );
389 -
390 - if ( !pNewSEB.getType().isUpdateReplacable() ) {
391 - throw badType( "UpdateReplacable", pNewSEB );
392 - }
393 - }
394 - node.replaceServerEventBus( pNewSEB );
395 - if ( !Objects.areNonArraysEqual( pParentClientID, node.getParentClientID() ) ) {
396 - throw new IllegalStateException( "Mismatched Parent Client IDs (" +
397 - node.getParentClientID() + ":Existing - New:" +
398 - pParentClientID + ") for Client ID: " + clientId );
399 - }
400 - } else {
401 - mServerEventBusNodes.put( clientId, new Node( pParentClientID, clientId, pNewSEB ) );
402 - if ( pParentClientID != null ) {
403 - getNode( pParentClientID ).incChildCount();
404 - }
405 - }
406 - }
407 - if ( pNewSEB instanceof NonTemporaryServerEventBus ) {
408 - LOGGER.debug.log( "---Alive---: ", pNewSEB );
409 - }
410 - pNewSEB.addListener( this );
411 - notifyAncestorsOfAddedDecendant( mAncestors, clientId );
412 - return zExistingSEB;
413 - }
414 -
415 - private IllegalStateException badType( String pWhy, ServerEventBus pNewSEB ) {
416 - return new IllegalStateException( "Not " + pWhy + ": " + pNewSEB.getType() + " ServerEventBus!" );
417 - }
418 -
419 - /**
420 - * called under lock
421 - */
422 - private List<ServerEventBus> getAncestors( Node pNode ) {
423 - List<ServerEventBus> zBuses = new ArrayList<ServerEventBus>();
424 - for ( Integer parentClientID; null != (parentClientID = pNode.getParentClientID()); ) {
425 - pNode = getNode( parentClientID );
426 - ServerEventBus zBus = pNode.getServerEventBus();
427 - if ( zBus != null ) {
428 - zBuses.add( zBus );
429 - }
430 - }
431 - return zBuses;
432 - }
433 -
434 - /**
435 - * called unsynchronized
436 - */
437 - private void notifyAncestorsOfAddedDecendant( List<ServerEventBus> pAncestors, int pClientId ) {
438 - notifyAncestorsWith( pAncestors, pClientId, true );
439 - }
440 -
441 - /**
442 - * called unsynchronized
443 - */
444 - private void notifyAncestorsOfRemovedDecendant( List<ServerEventBus> pAncestors, int pClientId ) {
445 - notifyAncestorsWith( pAncestors, pClientId, false );
446 - }
447 -
448 - /**
449 - * called unsynchronized
450 - */
451 - private void notifyAncestorsWith( List<ServerEventBus> pAncestors, int pClientId, boolean pAdd ) {
452 - if ( !pAncestors.isEmpty() ) {
453 - EventPackage eventPackage =
454 - new NotificationReDecendantEventPackage( "ServerEventBusManager", pClientId, pAdd );
455 - for ( ServerEventBus zAncestor : pAncestors ) {
456 - zAncestor.publish( eventPackage );
457 - }
458 - }
459 - }
460 - }
461 - }
1 + // This Source Code is in the Public Domain per: http://unlicense.org
2 + package org.litesoft.GWT.eventbus.server.nonpublic;
3 +
4 + import org.litesoft.GWT.eventbus.client.*;
5 + import org.litesoft.GWT.eventbus.client.nonpublic.*;
6 + import org.litesoft.GWT.eventbus.server.*;
7 + import org.litesoft.commonfoundation.base.*;
8 + import org.litesoft.logger.*;
9 + import org.litesoft.sequences.*;
10 +
11 + import javax.servlet.http.*;
12 + import java.util.*;
13 +
14 + public class ServerEventBusManager implements ServerEventBusBroadcaster {
15 + private static final Logger LOGGER = LoggerFactory.getLogger( ServerEventBusManager.class );
16 +
17 + public static final ServerEventBusManager INSTANCE = new ServerEventBusManager();
18 +
19 + private ServerEventBusManager() {
20 + }
21 +
22 + private static final String SERVER_EVENT_BUSES = "ServerEventBuses";
23 + private static final Long MAX_CLIENT_ID = (long) (Integer.MAX_VALUE - 2000);
24 + private static SequenceSource sClientIdNumberSequenceSource = SequenceSource.NULL;
25 +
26 + public static synchronized void setClientIdNumberSequenceSource( SequenceSource pSequenceSource ) {
27 + sClientIdNumberSequenceSource = (pSequenceSource != null) ? pSequenceSource : SequenceSource.NULL;
28 + }
29 +
30 + public static synchronized int getNextClientIdNumber() {
31 + long cid = sClientIdNumberSequenceSource.getNextSequenceNumber( SERVER_EVENT_BUSES, MAX_CLIENT_ID );
32 + return (int) cid;
33 + }
34 +
35 + private final NodeMap mNodes = new NodeMap();
36 +
37 + public EventPackage getPackageForNewServerEventBus( int pClientIdNumber ) {
38 + return null;
39 + }
40 +
41 + public TemporaryServerEventBus createTemporaryServerEventBus( String pWhy, ServerEventBus pParent,
42 + ClientWindowInstanceDataManager pInitialClientWindowInstanceData ) {
43 + int zClientIdNumber = getNextClientIdNumber();
44 +
45 + TemporaryServerEventBus zTempSEB = new TemporaryServerEventBus( zClientIdNumber );
46 +
47 + synchronized ( mNodes ) {
48 + zTempSEB.initialize( pWhy, pParent.getClientIdNumber(), pInitialClientWindowInstanceData );
49 + }
50 +
51 + // Force use of same stuff
52 + ServerEventBusSessionMapper.addServerEventBus( pParent, zTempSEB );
53 +
54 + return zTempSEB;
55 + }
56 +
57 + public TemporaryServerEventBus createTemporaryServerEventBus( String pWhy, HttpServletRequest pRequest,
58 + ThreadLocalContextFactory pThreadLocalContextFactory,
59 + ClientWindowInstanceDataManager pInitialClientWindowInstanceData ) {
60 + int zClientIdNumber = getNextClientIdNumber();
61 +
62 + TemporaryServerEventBus zTempSEB = new TemporaryServerEventBus( zClientIdNumber );
63 +
64 + synchronized ( mNodes ) {
65 + zTempSEB.initialize( pWhy, null, pInitialClientWindowInstanceData );
66 + }
67 +
68 + ServerEventBusSessionMapper.addServerEventBus( pRequest, pThreadLocalContextFactory, zTempSEB );
69 +
70 + return zTempSEB;
71 + }
72 +
73 + /**
74 + * @return may return null
75 + */
76 + public Integer getParentClientID( int pClientIdNumber ) {
77 + return mNodes.getNode( pClientIdNumber ).getParentClientID();
78 + }
79 +
80 + /**
81 + * @return may return null
82 + */
83 + public ServerEventBus getServerEventBus( int pClientIdNumber ) {
84 + return mNodes.getServerEventBusOrDisposedZombie( pClientIdNumber );
85 + }
86 +
87 + /**
88 + * @return may return null
89 + */
90 + public ServerEventBus getRootServerEventBus( int pClientIdNumber ) {
91 + return mNodes.getRootNode( pClientIdNumber ).getServerEventBus();
92 + }
93 +
94 + /**
95 + * @return may return null
96 + */
97 + public ServerEventBus getParentServerEventBus( int pClientIdNumber ) {
98 + return mNodes.getParentNode( pClientIdNumber ).getServerEventBus();
99 + }
100 +
101 + /**
102 + * @return may return an empty array, but never null
103 + */
104 + public ServerEventBus[] getAllServerEventBuses() {
105 + return SelectorAll.INSTANCE.select( mNodes.getNodes() );
106 + }
107 +
108 + /**
109 + * @return may return an empty array, but never null
110 + */
111 + public ServerEventBus[] getChildrenServerEventBuses( int pClientIdNumber ) {
112 + return new SelectorChildren( pClientIdNumber ).select( mNodes.getNodes() );
113 + }
114 +
115 + /**
116 + * @return may return an empty array, but never null
117 + */
118 + public ServerEventBus[] getAllRelatedServerEventBuses( int pClientIdNumber ) {
119 + Node rootNode = mNodes.getRootNode( pClientIdNumber );
120 + return rootNode.isReal() ? //
121 + new SelectorAllRelated().select( rootNode, mNodes.getNodes() ) : //
122 + ServerEventBus.EMPTY_ARRAY;
123 + }
124 +
125 + public void broadcast( EventPackage pEventPackage ) {
126 + if ( pEventPackage != null ) {
127 + ServerEventBus[] buses = getAllServerEventBuses();
128 + if ( buses != null ) {
129 + for ( ServerEventBus bus : buses ) {
130 + if ( bus != null ) {
131 + bus.publishIfNotDisposed( pEventPackage );
132 + }
133 + }
134 + }
135 + }
136 + }
137 +
138 + public static class BackDoor {
139 + public static ServerEventBus updateServerEventBus( ServerEventBus pNewSEB, Integer pParentClientID ) {
140 + return ServerEventBusManager.INSTANCE.mNodes.updateServerEventBus( pNewSEB, pParentClientID );
141 + }
142 + }
143 +
144 + private static class Node {
145 + private int mClientID;
146 + private Integer mParentClientID;
147 + private ServerEventBus mServerEventBus;
148 + private int mChildCount = 0;
149 +
150 + public Node( Integer pParentClientID, int pClientID, ServerEventBus pServerEventBus ) {
151 + mParentClientID = pParentClientID;
152 + mClientID = pClientID;
153 + mServerEventBus = pServerEventBus;
154 + }
155 +
156 + public String toString() {
157 + return "" + mClientID + ":" + ((getServerEventBus() != null) ? "SEB" : "---") + " ^" +
158 + mParentClientID + " c:" + mChildCount;
159 + }
160 +
161 + public int getClientID() {
162 + return mClientID;
163 + }
164 +
165 + public Integer getParentClientID() {
166 + return mParentClientID;
167 + }
168 +
169 + public synchronized ServerEventBus getServerEventBus() {
170 + return mServerEventBus;
171 + }
172 +
173 + public synchronized void replaceServerEventBus( ServerEventBus pServerEventBus ) {
174 + mServerEventBus = pServerEventBus;
175 + }
176 +
177 + public synchronized ServerEventBus clearServerEventBus() {
178 + ServerEventBus rv = mServerEventBus;
179 + mServerEventBus = null;
180 + return rv;
181 + }
182 +
183 + public synchronized boolean shouldRemove() {
184 + return isReal() && (mServerEventBus == null) && (mChildCount < 1);
185 + }
186 +
187 + public synchronized void incChildCount() {
188 + mChildCount++;
189 + }
190 +
191 + public synchronized void decChildCount() {
192 + mChildCount--;
193 + }
194 +
195 + public boolean isReal() {
196 + return true;
197 + }
198 + }
199 +
200 + private static final Node NULL_NODE = new Node( null, 0, null ) {
201 + public boolean isReal() {
202 + return false;
203 + }
204 +
205 + public void incChildCount() {
206 + }
207 +
208 + public void decChildCount() {
209 + }
210 + };
211 +
212 + private abstract static class AbstractSelector {
213 + public ServerEventBus[] select( Node[] pNodes ) {
214 + List<ServerEventBus> buses = new ArrayList<ServerEventBus>();
215 + addAppropriate( buses, pNodes );
216 + return buses.toArray( new ServerEventBus[buses.size()] );
217 + }
218 +
219 + protected void addAppropriate( List<ServerEventBus> pBuses, Node[] pNodes ) {
220 + for ( Node node : pNodes ) {
221 + ServerEventBus seb = node.getServerEventBus();
222 + if ( (seb != null) && acceptable( node, seb ) ) {
223 + pBuses.add( seb );
224 + }
225 + }
226 + }
227 +
228 + protected boolean acceptable( Node pNode, ServerEventBus pSEB ) {
229 + return true;
230 + }
231 + }
232 +
233 + private static class SelectorAll extends AbstractSelector {
234 + public static final AbstractSelector INSTANCE = new SelectorAll();
235 + }
236 +
237 + private static class SelectorChildren extends AbstractSelector {
238 + private Integer mParentID;
239 +
240 + public SelectorChildren( int pParentID ) {
241 + mParentID = pParentID;
242 + }
243 +
244 + protected boolean acceptable( Node pNode, ServerEventBus pSEB ) {
245 + return mParentID.equals( pNode.getParentClientID() );
246 + }
247 + }
248 +
249 + private static class SelectorAllRelated {
250 + public ServerEventBus[] select( Node pRoot, Node[] pNodes ) {
251 + List<ServerEventBus> buses = new ArrayList<ServerEventBus>();
252 + new Adder( buses, pNodes ).addAppropriate( pRoot );
253 + return buses.toArray( new ServerEventBus[buses.size()] );
254 + }
255 +
256 + private static class Adder {
257 + private List<ServerEventBus> mBuses;
258 + private Node[] mNodes;
259 +
260 + public Adder( List<ServerEventBus> pBuses, Node[] pNodes ) {
261 + mBuses = pBuses;
262 + mNodes = pNodes;
263 + }
264 +
265 + public void addAppropriate( Node pCurrent ) {
266 + ServerEventBus seb = pCurrent.getServerEventBus();
267 + if ( seb != null ) {
268 + mBuses.add( seb );
269 + }
270 + Integer parentID = pCurrent.getClientID();
271 + for ( Node node : mNodes ) {
272 + if ( parentID.equals( node.getParentClientID() ) ) {
273 + addAppropriate( node );
274 + }
275 + }
276 + }
277 + }
278 + }
279 +
280 + private static class NodeMap implements ServerEventBusDisposeListener {
281 + private final Map<Integer, Node> mServerEventBusNodes = new HashMap<Integer, Node>();
282 + private final Set<Integer> mDisposedServerEventBuses = new HashSet<Integer>();
283 +
284 + public Node getNode( Integer pClientIdNumberFromParentReference ) {
285 + return (pClientIdNumberFromParentReference == null) ? //
286 + NULL_NODE : //
287 + getNode( pClientIdNumberFromParentReference.intValue() );
288 + }
289 +
290 + public Node getNode( int pClientIdNumber ) {
291 + Node node = getRealNode( pClientIdNumber );
292 + return (node != null) ? node : NULL_NODE;
293 + }
294 +
295 + public Node getRequiredNode( int pClientIdNumber ) {
296 + Node node = getRealNode( pClientIdNumber );
297 + if ( node == null ) {
298 + throw new IllegalStateException( "No ServerEventBus Node for ClientID: " + pClientIdNumber );
299 + }
300 + return node;
301 + }
302 +
303 + // from ServerEventBusDisposeListener
304 + public void init( IServerEventBus pServerEventBus ) {
305 + }
306 +
307 + // from ServerEventBusDisposeListener
308 + public void disposing( IServerEventBus pServerEventBus ) {
309 + int clientId = pServerEventBus.getClientIdNumber();
310 +
311 + List<ServerEventBus> mAncestors = Collections.emptyList();
312 +
313 + ServerEventBus zExistingSEB;
314 +
315 + synchronized ( this ) {
316 + Node node = getNode( clientId );
317 + zExistingSEB = node.clearServerEventBus();
318 + if ( null != zExistingSEB ) {
319 + mAncestors = getAncestors( node );
320 +
321 + mDisposedServerEventBuses.add( clientId );
322 + }
323 +
324 + while ( node.shouldRemove() ) {
325 + mServerEventBusNodes.remove( node.getClientID() );
326 + node = getNode( node.getParentClientID() );
327 + node.decChildCount();
328 + }
329 + }
330 +
331 + if ( zExistingSEB instanceof NonTemporaryServerEventBus ) {
332 + LOGGER.debug.log( "---Disposed: ", zExistingSEB );
333 + }
334 +
335 + notifyAncestorsOfRemovedDecendant( mAncestors, clientId );
336 + }
337 +
338 + public synchronized ServerEventBus getServerEventBusOrDisposedZombie( int pClientIdNumber ) {
339 + ServerEventBus zBus = getNode( pClientIdNumber ).getServerEventBus();
340 + if ( zBus != null ) {
341 + return zBus;
342 + }
343 + return mDisposedServerEventBuses.contains( pClientIdNumber ) ? //
344 + ZombieServerEventBus.INSTANCE : //
345 + null;
346 + }
347 +
348 + public synchronized Node getRealNode( int pClientIdNumber ) {
349 + return mServerEventBusNodes.get( pClientIdNumber );
350 + }
351 +
352 + public synchronized Node[] getNodes() {
353 + return mServerEventBusNodes.values().toArray( new Node[mServerEventBusNodes.size()] );
354 + }
355 +
356 + public synchronized Node getParentNode( int pClientIdNumber ) {
357 + Integer parentClientID = getNode( pClientIdNumber ).getParentClientID();
358 + return getNode( parentClientID );
359 + }
360 +
361 + public synchronized Node getRootNode( int pClientIdNumber ) {
362 + Node node = getNode( pClientIdNumber );
363 + for ( Integer parentClientID; null != (parentClientID = node.getParentClientID()); ) {
364 + node = getNode( parentClientID );
365 + }
366 + return node;
367 + }
368 +
369 + public ServerEventBus updateServerEventBus( ServerEventBus pNewSEB, Integer pParentClientID ) {
370 + if ( !pNewSEB.getType().isManagable() ) {
371 + throw badType( "Managable", pNewSEB );
372 + }
373 +
374 + int clientId = pNewSEB.getClientIdNumber();
375 +
376 + ServerEventBus zExistingSEB = null;
377 +
378 + List<ServerEventBus> mAncestors = Collections.emptyList();
379 +
380 + synchronized ( this ) {
381 + Node node = getRealNode( clientId );
382 + if ( node != null ) {
383 + zExistingSEB = node.getServerEventBus();
384 + if ( zExistingSEB != null ) {
385 + mAncestors = getAncestors( node );
386 +
387 + // Since we are replacing we do NOT want to get the dispose notice on the old!
388 + zExistingSEB.removeListener( this );
389 +
390 + if ( !pNewSEB.getType().isUpdateReplacable() ) {
391 + throw badType( "UpdateReplacable", pNewSEB );
392 + }
393 + }
394 + node.replaceServerEventBus( pNewSEB );
395 + if ( !Currently.areEqual( pParentClientID, node.getParentClientID() ) ) {
396 + throw new IllegalStateException( "Mismatched Parent Client IDs (" +
397 + node.getParentClientID() + ":Existing - New:" +
398 + pParentClientID + ") for Client ID: " + clientId );
399 + }
400 + } else {
401 + mServerEventBusNodes.put( clientId, new Node( pParentClientID, clientId, pNewSEB ) );
402 + if ( pParentClientID != null ) {
403 + getNode( pParentClientID ).incChildCount();
404 + }
405 + }
406 + }
407 + if ( pNewSEB instanceof NonTemporaryServerEventBus ) {
408 + LOGGER.debug.log( "---Alive---: ", pNewSEB );
409 + }
410 + pNewSEB.addListener( this );
411 + notifyAncestorsOfAddedDecendant( mAncestors, clientId );
412 + return zExistingSEB;
413 + }
414 +
415 + private IllegalStateException badType( String pWhy, ServerEventBus pNewSEB ) {
416 + return new IllegalStateException( "Not " + pWhy + ": " + pNewSEB.getType() + " ServerEventBus!" );
417 + }
418 +
419 + /**
420 + * called under lock
421 + */
422 + private List<ServerEventBus> getAncestors( Node pNode ) {
423 + List<ServerEventBus> zBuses = new ArrayList<ServerEventBus>();
424 + for ( Integer parentClientID; null != (parentClientID = pNode.getParentClientID()); ) {
425 + pNode = getNode( parentClientID );
426 + ServerEventBus zBus = pNode.getServerEventBus();
427 + if ( zBus != null ) {
428 + zBuses.add( zBus );
429 + }
430 + }
431 + return zBuses;
432 + }
433 +
434 + /**
435 + * called unsynchronized
436 + */
437 + private void notifyAncestorsOfAddedDecendant( List<ServerEventBus> pAncestors, int pClientId ) {
438 + notifyAncestorsWith( pAncestors, pClientId, true );
439 + }
440 +
441 + /**
442 + * called unsynchronized
443 + */
444 + private void notifyAncestorsOfRemovedDecendant( List<ServerEventBus> pAncestors, int pClientId ) {
445 + notifyAncestorsWith( pAncestors, pClientId, false );
446 + }
447 +
448 + /**
449 + * called unsynchronized
450 + */
451 + private void notifyAncestorsWith( List<ServerEventBus> pAncestors, int pClientId, boolean pAdd ) {
452 + if ( !pAncestors.isEmpty() ) {
453 + EventPackage eventPackage =
454 + new NotificationReDecendantEventPackage( "ServerEventBusManager", pClientId, pAdd );
455 + for ( ServerEventBus zAncestor : pAncestors ) {
456 + zAncestor.publish( eventPackage );
457 + }
458 + }
459 + }
460 + }
461 + }