1 | package dmg.cells.nucleus ; |
2 | import dmg.util.Args ; |
3 | import dmg.util.CollectionFactory; |
4 | import java.io.*; |
5 | import java.util.* ; |
6 | import java.util.concurrent.atomic.AtomicInteger; |
7 | import java.lang.reflect.* ; |
8 | import java.text.*; |
9 | |
10 | import org.slf4j.Logger; |
11 | import org.slf4j.LoggerFactory; |
12 | // |
13 | // package |
14 | // |
15 | /** |
16 | * |
17 | * |
18 | * @author Patrick Fuhrmann |
19 | * @version 0.1, 15 Feb 1998 |
20 | */ |
21 | class CellGlue { |
22 | |
23 | private final String _cellDomainName ; |
24 | private final Map<String, CellNucleus> _cellList = |
25 | CollectionFactory.newConcurrentHashMap(); |
26 | private final Map<String,List<CellEventListener>> _cellEventListener = |
27 | CollectionFactory.newConcurrentHashMap(); |
28 | private final Map<String, CellNucleus> _killedCellList = |
29 | CollectionFactory.newConcurrentHashMap(); |
30 | private final Map<String, Object> _cellContext = |
31 | CollectionFactory.newConcurrentHashMap(); |
32 | private final AtomicInteger _uniqueCounter = new AtomicInteger(100) ; |
33 | public int _printoutLevel = 0 ; |
34 | public int _defPrintoutLevel = CellNucleus.PRINT_ERRORS ; |
35 | private CellNucleus _systemNucleus = null ; |
36 | private ClassLoaderProvider _classLoader = null ; |
37 | private CellRoutingTable _routingTable = new CellRoutingTable() ; |
38 | private ThreadGroup _masterThreadGroup = null ; |
39 | private ThreadGroup _killerThreadGroup = null ; |
40 | |
41 | private final static Logger _logMessages = |
42 | LoggerFactory.getLogger("logger.org.dcache.cells.messages"); |
43 | private final static Logger _logGlue = |
44 | LoggerFactory.getLogger(CellGlue.class); |
45 | |
46 | CellGlue( String cellDomainName ){ |
47 | |
48 | String cellDomainNameLocal = cellDomainName ; |
49 | |
50 | if( ( cellDomainName == null ) || ( cellDomainName.equals("") ) ) |
51 | cellDomainNameLocal = "*" ; |
52 | |
53 | if( cellDomainNameLocal.charAt( cellDomainNameLocal.length() - 1 ) == '*' ){ |
54 | cellDomainNameLocal = |
55 | cellDomainNameLocal.substring(0,cellDomainNameLocal.length())+ |
56 | System.currentTimeMillis() ; |
57 | } |
58 | _cellDomainName = cellDomainNameLocal; |
59 | _classLoader = new ClassLoaderProvider() ; |
60 | _masterThreadGroup = new ThreadGroup( "Master-Thread-Group" ) ; |
61 | _killerThreadGroup = new ThreadGroup( "Killer-Thread-Group" ) ; |
62 | new CellUrl( this ) ; |
63 | } |
64 | ThreadGroup getMasterThreadGroup(){return _masterThreadGroup ; } |
65 | ThreadGroup getKillerThreadGroup(){return _killerThreadGroup ; } |
66 | |
67 | synchronized void addCell( String name , CellNucleus cell ) |
68 | throws IllegalArgumentException { |
69 | |
70 | if( _killedCellList.get( name ) != null ) |
71 | throw new IllegalArgumentException( "Name Mismatch ( cell " + name + " exist )" ) ; |
72 | if( _cellList.get( name ) != null ) |
73 | throw new IllegalArgumentException( "Name Mismatch ( cell " + name + " exist )" ) ; |
74 | |
75 | _cellList.put( name , cell ) ; |
76 | |
77 | sendToAll( new CellEvent( name , CellEvent.CELL_CREATED_EVENT ) ) ; |
78 | } |
79 | |
80 | void setSystemNucleus(CellNucleus nucleus) |
81 | { |
82 | _systemNucleus = nucleus; |
83 | } |
84 | |
85 | CellNucleus getSystemNucleus() |
86 | { |
87 | return _systemNucleus; |
88 | } |
89 | |
90 | String [] [] getClassProviders(){ return _classLoader.getProviders() ; } |
91 | |
92 | void setClassProvider( String selection , String provider ){ |
93 | String type = null ; |
94 | String value = null ; |
95 | int pos = provider.indexOf(':') ; |
96 | if( pos < 0 ){ |
97 | if( provider.indexOf('/') >= 0 ){ |
98 | type = "dir" ; |
99 | value = provider ; |
100 | }else if( provider.indexOf( '@' ) >= 0 ){ |
101 | type = "cells" ; |
102 | value = provider ; |
103 | }else if( provider.equals( "system" ) ){ |
104 | type = "system" ; |
105 | }else if( provider.equals( "none" ) ){ |
106 | type = "none" ; |
107 | }else |
108 | throw new |
109 | IllegalArgumentException( "Can't determine provider type" ) ; |
110 | }else{ |
111 | type = provider.substring( 0 , pos ) ; |
112 | value = provider.substring( pos+1 ) ; |
113 | } |
114 | if( type.equals( "dir" ) ){ |
115 | File file = new File( value ) ; |
116 | if( ! file.isDirectory() ) |
117 | throw new |
118 | IllegalArgumentException( "Not a directory : "+value ) ; |
119 | _classLoader.addFileProvider( selection , new File( value ) ) ; |
120 | }else if( type.equals( "cell" ) ){ |
121 | _classLoader.addCellProvider( selection , |
122 | _systemNucleus , |
123 | new CellPath( value ) ) ; |
124 | }else if( type.equals( "system" ) ){ |
125 | _classLoader.addSystemProvider( selection ); |
126 | }else if( type.equals( "none" ) ){ |
127 | _classLoader.removeSystemProvider( selection ); |
128 | }else |
129 | throw new |
130 | IllegalArgumentException( "Provider type not supported : "+type ) ; |
131 | |
132 | } |
133 | synchronized void export( CellNucleus cell ){ |
134 | |
135 | sendToAll( new CellEvent( cell.getCellName() , |
136 | CellEvent.CELL_EXPORTED_EVENT ) ) ; |
137 | } |
138 | private Class _loadClass( String className ) throws ClassNotFoundException { |
139 | return _classLoader.loadClass( className ) ; |
140 | } |
141 | public Class loadClass( String className ) throws ClassNotFoundException { |
142 | return _classLoader.loadClass( className ) ; |
143 | } |
144 | Object _newInstance( String className , |
145 | String cellName , |
146 | Object [] args , |
147 | boolean systemOnly ) |
148 | throws ClassNotFoundException , |
149 | NoSuchMethodException , |
150 | SecurityException , |
151 | InstantiationException , |
152 | InvocationTargetException , |
153 | IllegalAccessException , |
154 | ClassCastException { |
155 | |
156 | Class newClass = null ; |
157 | if( systemOnly ) |
158 | newClass = Class.forName( className ) ; |
159 | else |
160 | newClass = _loadClass( className ) ; |
161 | |
162 | Object [] arguments = new Object[args.length+1] ; |
163 | arguments[0] = cellName ; |
164 | for( int i = 0 ; i < args.length ; i++ ) |
165 | arguments[i+1] = args[i] ; |
166 | Class [] argClass = new Class[arguments.length] ; |
167 | for( int i = 0 ; i < arguments.length ; i++ ) |
168 | argClass[i] = arguments[i].getClass() ; |
169 | |
170 | return newClass.getConstructor( argClass ). |
171 | newInstance( arguments ) ; |
172 | |
173 | } |
174 | Object _newInstance( String className , |
175 | String cellName , |
176 | String [] argsClassNames , |
177 | Object [] args , |
178 | boolean systemOnly ) |
179 | throws ClassNotFoundException , |
180 | NoSuchMethodException , |
181 | SecurityException , |
182 | InstantiationException , |
183 | InvocationTargetException , |
184 | IllegalAccessException , |
185 | ClassCastException { |
186 | |
187 | Class newClass = null ; |
188 | if( systemOnly ) |
189 | newClass = Class.forName( className ) ; |
190 | else |
191 | newClass = _loadClass( className ) ; |
192 | |
193 | Object [] arguments = new Object[args.length+1] ; |
194 | arguments[0] = cellName ; |
195 | |
196 | for( int i = 0 ; i < args.length ; i++ ) |
197 | arguments[i+1] = args[i] ; |
198 | |
199 | Class [] argClasses = new Class[arguments.length] ; |
200 | |
201 | ClassLoader loader = newClass.getClassLoader() ; |
202 | argClasses[0] = java.lang.String.class ; |
203 | if( loader == null ){ |
204 | for( int i = 1 ; i < argClasses.length ; i++ ) |
205 | argClasses[i] = Class.forName( argsClassNames[i-1] ) ; |
206 | }else{ |
207 | for( int i = 1 ; i < argClasses.length ; i++ ) |
208 | argClasses[i] = loader.loadClass( argsClassNames[i-1] ) ; |
209 | } |
210 | |
211 | return newClass.getConstructor( argClasses ). |
212 | newInstance( arguments ) ; |
213 | |
214 | } |
215 | |
216 | Map<String, Object> getCellContext() |
217 | { |
218 | return _cellContext; |
219 | } |
220 | |
221 | Object getCellContext( String str ){ |
222 | return _cellContext.get( str ) ; |
223 | } |
224 | CellDomainInfo getCellDomainInfo(){ |
225 | CellDomainInfo info = new CellDomainInfo(_cellDomainName) ; |
226 | // info.setCellDomainName( _cellDomainName ) ; |
227 | return info ; |
228 | } |
229 | public void routeAdd( CellRoute route ){ |
230 | _routingTable.add( route ) ; |
231 | sendToAll( new CellEvent( route , CellEvent.CELL_ROUTE_ADDED_EVENT ) ) ; |
232 | } |
233 | public void routeDelete( CellRoute route ){ |
234 | _routingTable.delete( route ) ; |
235 | sendToAll( new CellEvent( route , CellEvent.CELL_ROUTE_DELETED_EVENT ) ) ; |
236 | } |
237 | CellRoutingTable getRoutingTable(){ return _routingTable ; } |
238 | CellRoute [] getRoutingList(){ return _routingTable.getRoutingList() ; } |
239 | synchronized CellTunnelInfo [] getCellTunnelInfos(){ |
240 | |
241 | List<CellTunnelInfo> v = new ArrayList<CellTunnelInfo>() ; |
242 | |
243 | for( CellNucleus cellNucleus : _cellList.values() ){ |
244 | |
245 | Cell c = cellNucleus.getThisCell() ; |
246 | |
247 | if( c instanceof CellTunnel ){ |
248 | v.add( ((CellTunnel)c).getCellTunnelInfo() ) ; |
249 | } |
250 | } |
251 | |
252 | return v.toArray( new CellTunnelInfo[v.size()] ) ; |
253 | |
254 | } |
255 | synchronized String [] getCellNames(){ |
256 | int size = _cellList.size() + _killedCellList.size() ; |
257 | |
258 | List<String> allCells = new ArrayList<String>(size); |
259 | |
260 | allCells.addAll(_cellList.keySet()); |
261 | allCells.addAll(_killedCellList.keySet()); |
262 | |
263 | return allCells.toArray(new String[size]); |
264 | |
265 | } |
266 | |
267 | int getUnique(){ return _uniqueCounter.incrementAndGet() ; } |
268 | |
269 | CellInfo getCellInfo( String name ){ |
270 | CellNucleus nucleus = _cellList.get( name ) ; |
271 | if( nucleus == null ){ |
272 | nucleus = _killedCellList.get( name ) ; |
273 | if( nucleus == null )return null ; |
274 | } |
275 | return nucleus._getCellInfo() ; |
276 | } |
277 | Thread [] getThreads( String name ){ |
278 | CellNucleus nucleus = _cellList.get( name ) ; |
279 | if( nucleus == null ){ |
280 | nucleus = _killedCellList.get( name ) ; |
281 | if( nucleus == null )return null ; |
282 | } |
283 | return nucleus.getThreads() ; |
284 | } |
285 | private void sendToAll( CellEvent event ){ |
286 | // |
287 | // inform our event listener |
288 | // |
289 | |
290 | for( List<CellEventListener> listners: _cellEventListener.values() ){ |
291 | |
292 | for( CellEventListener hallo : listners ){ |
293 | |
294 | if( hallo == null ){ |
295 | say( "event distributor found NULL" ) ; |
296 | continue ; |
297 | } |
298 | try{ |
299 | switch( event.getEventType() ){ |
300 | case CellEvent.CELL_CREATED_EVENT : |
301 | hallo.cellCreated( event ) ; |
302 | break ; |
303 | case CellEvent.CELL_EXPORTED_EVENT : |
304 | hallo.cellExported( event ) ; |
305 | break ; |
306 | case CellEvent.CELL_DIED_EVENT : |
307 | hallo.cellDied( event ) ; |
308 | break ; |
309 | case CellEvent.CELL_ROUTE_ADDED_EVENT : |
310 | hallo.routeAdded( event ) ; |
311 | break ; |
312 | case CellEvent.CELL_ROUTE_DELETED_EVENT : |
313 | hallo.routeDeleted( event ) ; |
314 | break ; |
315 | } |
316 | }catch( Exception anye ){ |
317 | say( "Exception while sending "+event + " ex : "+anye ) ; |
318 | } |
319 | } |
320 | |
321 | } |
322 | |
323 | } |
324 | |
325 | void setPrintoutLevel( int level ){ _printoutLevel = level ; } |
326 | int getPrintoutLevel(){ return _printoutLevel ; } |
327 | int getDefaultPrintoutLevel(){ return _defPrintoutLevel ; } |
328 | void setPrintoutLevel( String cellName , int level ){ |
329 | |
330 | if( cellName.equals("CellGlue") ){ |
331 | setPrintoutLevel(level) ; |
332 | return ; |
333 | }else if( cellName.equals("default") ){ |
334 | _defPrintoutLevel = level ; |
335 | return ; |
336 | } |
337 | |
338 | CellNucleus nucleus = _cellList.get( cellName ) ; |
339 | if( nucleus != null )nucleus.setPrintoutLevel( level ) ; |
340 | } |
341 | int getPrintoutLevel( String cellName ){ |
342 | |
343 | if( cellName.equals("CellGlue") )return getPrintoutLevel() ; |
344 | if( cellName.equals("default") )return getDefaultPrintoutLevel() ; |
345 | CellNucleus nucleus = _cellList.get( cellName ) ; |
346 | |
347 | if( nucleus != null )return nucleus.getPrintoutLevel() ; |
348 | |
349 | return -1 ; |
350 | } |
351 | |
352 | void say(String str){ |
353 | if( ( _printoutLevel & CellNucleus.PRINT_NUCLEUS ) != 0 ) { |
354 | _logGlue.warn(str); |
355 | } else { |
356 | _logGlue.info(str); |
357 | } |
358 | } |
359 | |
360 | void esay( String str ){ |
361 | if( ( _printoutLevel & CellNucleus.PRINT_NUCLEUS ) != 0 ) { |
362 | _logGlue.error(str); |
363 | } else { |
364 | _logGlue.info(str); |
365 | } |
366 | } |
367 | String getCellDomainName(){ return _cellDomainName ; } |
368 | void kill( CellNucleus nucleus ){ |
369 | _kill( nucleus , nucleus , 0 ) ; |
370 | } |
371 | void kill( CellNucleus sender , String cellName ) |
372 | throws IllegalArgumentException { |
373 | CellNucleus nucleus = _cellList.get( cellName ) ; |
374 | if( nucleus == null ) |
375 | throw new IllegalArgumentException( "Cell Not Found : "+cellName ) ; |
376 | _kill( sender , nucleus , 0 ) ; |
377 | |
378 | } |
379 | |
380 | /** |
381 | * Returns a named cell. This method also returns cells that have |
382 | * been killed, but which are not dead yet. |
383 | * |
384 | * @param cellName the name of the cell |
385 | * @return The cell with the given name or null if there is no such |
386 | * cell. |
387 | */ |
388 | CellNucleus getCell(String cellName) |
389 | { |
390 | CellNucleus nucleus = _cellList.get(cellName); |
391 | if (nucleus == null) { |
392 | nucleus = _killedCellList.get(cellName); |
393 | } |
394 | return nucleus; |
395 | } |
396 | |
397 | /** |
398 | * Blocks until the given cell is dead. |
399 | * |
400 | * @param cellName the name of the cell |
401 | * @param timeout the time to wait in milliseconds. A timeout |
402 | * of 0 means to wait forever. |
403 | * @throws InterruptedException if another thread interrupted the |
404 | * current thread before or while the current thread was |
405 | * waiting for a notification. The interrupted status of |
406 | * the current thread is cleared when this exception is |
407 | * thrown. |
408 | * @return True if the cell died, false in case of a timeout. |
409 | */ |
410 | synchronized boolean join(String cellName, long timeout) throws InterruptedException |
411 | { |
412 | if (timeout == 0) { |
413 | while (getCell(cellName) != null) { |
414 | wait(); |
415 | } |
416 | return true; |
417 | } else { |
418 | while (getCell(cellName) != null && timeout > 0) { |
419 | long time = System.currentTimeMillis(); |
420 | wait(timeout); |
421 | timeout = timeout - (System.currentTimeMillis() - time); |
422 | } |
423 | return (timeout > 0); |
424 | } |
425 | } |
426 | |
427 | synchronized void destroy( CellNucleus nucleus ){ |
428 | String name = nucleus.getCellName() ; |
429 | _killedCellList.remove( name ) ; |
430 | say( "destroy : sendToAll : killed"+name ) ; |
431 | notifyAll(); |
432 | // |
433 | // CELL_DIED_EVENT moved to _kill. Otherwise |
434 | // we have bouncing message because the WELL_KNOWN_ROUTE |
435 | // is still there but the entry in the ps list is not. |
436 | // |
437 | // sendToAll( new CellEvent( name , CellEvent.CELL_DIED_EVENT ) ) ; |
438 | return ; |
439 | } |
440 | private synchronized void _kill( CellNucleus source , |
441 | CellNucleus destination , |
442 | long to ) { |
443 | |
444 | _cellEventListener.remove( destination.getCellName() ) ; |
445 | |
446 | CellPath sourceAddr = new CellPath( source.getCellName() , |
447 | getCellDomainName() ) ; |
448 | |
449 | KillEvent killEvent = new KillEvent( sourceAddr , to ) ; |
450 | |
451 | String cellToKill = destination.getCellName() ; |
452 | |
453 | CellNucleus destNucleus = _cellList.remove( cellToKill ) ; |
454 | |
455 | sendToAll( new CellEvent( cellToKill , CellEvent.CELL_DIED_EVENT ) ) ; |
456 | |
457 | if( destNucleus == null ){ |
458 | esay( "Warning : (name not found in _kill) "+cellToKill ) ; |
459 | return ; |
460 | } |
461 | _killedCellList.put( destNucleus.getCellName() , destNucleus ) ; |
462 | destNucleus.sendKillEvent( killEvent ) ; |
463 | } |
464 | private static final int MAX_ROUTE_LEVELS = 16 ; |
465 | |
466 | void sendMessage( CellNucleus nucleus , CellMessage msg ) |
467 | throws SerializationException, |
468 | NoRouteToCellException { |
469 | |
470 | sendMessage( nucleus , msg , true , true ) ; |
471 | |
472 | } |
473 | void sendMessage( CellNucleus nucleus , |
474 | CellMessage msg , |
475 | boolean resolveLocally , |
476 | boolean resolveRemotely ) |
477 | throws SerializationException, |
478 | NoRouteToCellException { |
479 | |
480 | boolean firstSend = ! msg.isStreamMode() ; |
481 | |
482 | CellMessage transponder = msg ; |
483 | if( firstSend ){ |
484 | // |
485 | // this is the original send command |
486 | // - so we have to set the UOID ( sender needs it ) |
487 | // - we have to convert the message to stream. |
488 | // - and we have to set our address to find the way back |
489 | // |
490 | transponder = new CellMessage( msg ) ; |
491 | transponder.addSourceAddress( nucleus.getThisAddress() ) ; |
492 | } |
493 | |
494 | if( transponder.getSourcePath().hops() > 30 ){ |
495 | esay( "Hop count exceeds 30, dumping : "+transponder ) ; |
496 | return ; |
497 | } |
498 | CellPath destination = transponder.getDestinationPath() ; |
499 | CellAddressCore destCore = destination.getCurrent() ; |
500 | String cellName = destCore.getCellName() ; |
501 | String domainName = destCore.getCellDomainName(); |
502 | |
503 | say( "sendMessage : "+transponder.getUOID()+" send to "+destination); |
504 | if( _logMessages.isDebugEnabled() ) { |
505 | |
506 | CellMessage messageToSend; |
507 | |
508 | if( transponder.isStreamMode() ) { |
509 | messageToSend = new CellMessage(transponder); |
510 | }else{ |
511 | messageToSend = transponder; |
512 | } |
513 | |
514 | String messageObject = messageToSend.getMessageObject() == null? "NULL" : messageToSend.getMessageObject().getClass().getName(); |
515 | _logMessages.debug("glueSendMessage src=" + messageToSend.getSourceAddress() + |
516 | " dest=" + messageToSend.getDestinationAddress() + " [" + messageObject + "] UOID=" + messageToSend.getUOID().toString() ); |
517 | } |
518 | // |
519 | // if the cellname is an *, ( stream mode only ) we can skip |
520 | // this address, because it was needed to reach our domain, |
521 | // which hopefully happened. |
522 | // |
523 | if( ( ! firstSend ) && cellName.equals("*") ){ |
524 | say( "sendMessage : * detected ; skipping destination" ); |
525 | destination.next() ; |
526 | destCore = destination.getCurrent() ; |
527 | } |
528 | |
529 | |
530 | transponder.isRouted( false ) ; |
531 | // |
532 | // this is the big iteration loop |
533 | // |
534 | for( int iter = 0 ; iter < MAX_ROUTE_LEVELS ; iter ++ ){ |
535 | cellName = destCore.getCellName() ; |
536 | domainName = destCore.getCellDomainName() ; |
537 | say( "sendMessage : next hop at "+iter+" : "+cellName+"@"+domainName ) ; |
538 | |
539 | // |
540 | // now we try to find the destination cell in our domain |
541 | // |
542 | CellNucleus destNucleus = _cellList.get( cellName ) ; |
543 | if( domainName.equals( _cellDomainName ) ){ |
544 | if( cellName.equals("*") ){ |
545 | say( "sendMessagex : * detected ; skipping destination" ); |
546 | destination.next() ; |
547 | destCore = destination.getCurrent() ; |
548 | continue ; |
549 | } |
550 | // |
551 | // the domain name was specified ( other then 'local' ) |
552 | // and points to our domain. |
553 | // |
554 | if( destNucleus == null ){ |
555 | // say( "sendMessage : Not found : "+destination ) ; |
556 | if( firstSend ){ |
557 | throw new |
558 | NoRouteToCellException( |
559 | transponder.getUOID(), |
560 | destination, |
561 | "Initial Send"); |
562 | }else{ |
563 | sendException( nucleus , transponder , destination , cellName ) ; |
564 | return ; |
565 | } |
566 | } |
567 | if( iter == 0 ){ |
568 | // |
569 | // here we really found the destination cell ( no router ) |
570 | // |
571 | // say( "sendMessage : message "+transponder.getUOID()+ |
572 | // " addToEventQueue of "+cellName ) ; |
573 | destNucleus.addToEventQueue( new MessageEvent( transponder ) ) ; |
574 | }else{ |
575 | // |
576 | // this is a router, so we have to prepare the message for |
577 | // routing |
578 | // |
579 | // destNucleus.addToEventQueue( new RoutedMessageEvent( transponder ) ) ; |
580 | transponder.isRouted( true ) ; |
581 | transponder.addSourceAddress( |
582 | new CellAddressCore( "*" , _cellDomainName ) ) ; |
583 | // say( "sendMessage : message "+transponder.getUOID()+ |
584 | // " forwarded addToEventQueue of "+cellName ) ; |
585 | destNucleus.addToEventQueue( new RoutedMessageEvent( transponder ) ) ; |
586 | } |
587 | return ; |
588 | }else if( domainName.equals( "local" ) && |
589 | ( resolveLocally || ( iter != 0 ) ) ){ |
590 | // |
591 | // the domain name was 'local' AND |
592 | // ( we are assumed to deliver locally || |
593 | // we are already in the routing part ) |
594 | // |
595 | if( destNucleus != null ){ |
596 | // say( "sendMessage : locally delivered : "+destination ) ; |
597 | if( iter == 0 ){ |
598 | // say( "sendMessage : message "+transponder.getUOID()+ |
599 | // " addToEventQueue of "+cellName ) ; |
600 | destNucleus.addToEventQueue( new MessageEvent( transponder ) ) ; |
601 | }else{ |
602 | transponder.isRouted( true ) ; |
603 | transponder.addSourceAddress( |
604 | new CellAddressCore( "*" , _cellDomainName ) ) ; |
605 | // say( "sendMessage : message "+transponder.getUOID()+ |
606 | // " forwarded addToEventQueue of "+cellName ) ; |
607 | destNucleus.addToEventQueue( new RoutedMessageEvent( transponder ) ) ; |
608 | } |
609 | return ; |
610 | }else if( iter == MAX_ROUTE_LEVELS ){ |
611 | say( "sendMessage : max route iteration reached : "+destination ) ; |
612 | if( firstSend ){ |
613 | throw new |
614 | NoRouteToCellException( |
615 | transponder.getUOID(), |
616 | destination , |
617 | "Initial Send"); |
618 | }else{ |
619 | sendException( nucleus , transponder , destination , cellName ) ; |
620 | return ; |
621 | } |
622 | } |
623 | // |
624 | // destNuclues == null , is no problem in our case because |
625 | // 'wellknowncells' also use local as keyword. |
626 | // |
627 | }else if( domainName.equals( "local" ) && |
628 | ( ! resolveRemotely ) && |
629 | ( iter == 0 ) ){ |
630 | // |
631 | // the domain is specified AND |
632 | // we are assumed not to deliver remotely AND |
633 | // we are not yet in the routing part |
634 | // |
635 | throw new |
636 | NoRouteToCellException( |
637 | transponder.getUOID(), |
638 | destination, |
639 | " ! resolve remotely : "+destCore); |
640 | |
641 | } |
642 | // |
643 | // so, the destination cell wasn't found locally. |
644 | // let's consult the routes |
645 | // |
646 | CellRoute route = _routingTable.find( destCore ) ; |
647 | if( ( route == null ) || ( iter == MAX_ROUTE_LEVELS )){ |
648 | say( "sendMessage : no route destination for : "+destCore ) ; |
649 | if( firstSend ){ |
650 | throw new |
651 | NoRouteToCellException( |
652 | transponder.getUOID(), |
653 | destination, |
654 | "Missing routing entry for "+destCore); |
655 | }else{ |
656 | sendException( nucleus , transponder , destination , destCore.toString() ) ; |
657 | return ; |
658 | } |
659 | } |
660 | say( "sendMessage : using route : "+route ) ; |
661 | destCore = route.getTarget() ; |
662 | if( route.getRouteType() == CellRoute.ALIAS ) |
663 | destination.replaceCurrent( destCore ) ; |
664 | } |
665 | // end of big iteration loop |
666 | |
667 | } |
668 | private void sendException( CellNucleus nucleus , |
669 | CellMessage msg , |
670 | CellPath destination , |
671 | String routeTarget ) |
672 | throws SerializationException, |
673 | NoRouteToCellException { |
674 | // |
675 | // here we try to inform the last sender that we are |
676 | // not able to deliver the packet. |
677 | // |
678 | say( "sendMessage : Route target Not found : "+routeTarget ) ; |
679 | NoRouteToCellException exception = |
680 | new NoRouteToCellException( |
681 | msg.getUOID() , |
682 | destination , |
683 | "Tunnel cell >"+routeTarget+ |
684 | "< not found at >"+_cellDomainName+"<" ) ; |
685 | CellPath retAddr = (CellPath)msg.getSourcePath().clone() ; |
686 | retAddr.revert() ; |
687 | CellExceptionMessage ret = |
688 | new CellExceptionMessage( retAddr , exception ) ; |
689 | esay( "Sending CellException to "+retAddr ) ; |
690 | ret.setLastUOID( msg.getUOID() ) ; |
691 | sendMessage( nucleus , ret ) ; |
692 | |
693 | } |
694 | |
695 | void addCellEventListener(CellNucleus nucleus, CellEventListener listener) |
696 | { |
697 | List<CellEventListener> v; |
698 | if ((v = _cellEventListener.get(nucleus.getCellName())) == null) { |
699 | v = CollectionFactory.newCopyOnWriteArrayList(); |
700 | _cellEventListener.put(nucleus.getCellName(), v); |
701 | } |
702 | v.add(listener); |
703 | } |
704 | |
705 | @Override |
706 | public String toString(){ return _cellDomainName ; } |
707 | |
708 | } |