1 | package dmg.cells.nucleus ; |
2 | import dmg.util.*; |
3 | import dmg.util.logback.FilterShell; |
4 | import java.io.*; |
5 | import java.util.List; |
6 | import java.util.ArrayList; |
7 | import org.slf4j.Logger; |
8 | import org.slf4j.LoggerFactory; |
9 | |
10 | /** |
11 | * |
12 | * |
13 | * @author Patrick Fuhrmann |
14 | * @version 0.1, 15 Feb 1998 |
15 | */ |
16 | public class SystemCell |
17 | extends CellAdapter |
18 | implements Runnable, Thread.UncaughtExceptionHandler |
19 | { |
20 | private final static Logger _log = LoggerFactory.getLogger(SystemCell.class); |
21 | |
22 | private final CellShell _cellShell ; |
23 | private final CellNucleus _nucleus ; |
24 | private int _packetsReceived = 0 , |
25 | _packetsAnswered = 0 , |
26 | _packetsForwarded = 0 , |
27 | _packetsReplayed = 0 , |
28 | _exceptionCounter = 0 ; |
29 | private DomainInterruptHandler _interruptHandler = null ; |
30 | private Thread _interruptThread = null ; |
31 | private long _interruptTimer = 2000 ; |
32 | private final Runtime _runtime = Runtime.getRuntime() ; |
33 | private final Gate _shutdownLock = new Gate(false); |
34 | |
35 | private class TheKiller extends Thread { |
36 | public void run(){ |
37 | _log.info("Running shutdown sequence"); |
38 | kill() ; |
39 | _log.info("Kill done, waiting for shutdown lock"); |
40 | _shutdownLock.check() ; |
41 | _log.info("Killer done"); |
42 | } |
43 | } |
44 | public SystemCell( String cellDomainName ){ |
45 | super( cellDomainName ) ; |
46 | |
47 | _nucleus = getNucleus() ; |
48 | _cellShell = new CellShell( getNucleus() ) ; |
49 | _cellShell.addCommandListener(new LogbackShell()); |
50 | _cellShell.addCommandListener(new FilterShell(_nucleus.getLoggingThresholds())); |
51 | useInterpreter( false ) ; |
52 | |
53 | _runtime.addShutdownHook( new TheKiller() ) ; |
54 | |
55 | Thread.setDefaultUncaughtExceptionHandler(this); |
56 | // setPrintoutLevel(0xff); |
57 | |
58 | // addCellEventListener() ; |
59 | } |
60 | |
61 | // |
62 | // interface from Cell |
63 | // |
64 | public String toString(){ |
65 | long fm = _runtime.freeMemory() ; |
66 | long tm = _runtime.totalMemory() ; |
67 | return getCellDomainName()+ |
68 | ":IOrec="+_packetsReceived+ |
69 | ";IOexc="+_exceptionCounter+ |
70 | ";MEM="+(tm-fm) ; |
71 | } |
72 | public int enableInterrupts( String handlerName ){ |
73 | Class handlerClass = null ; |
74 | try{ |
75 | handlerClass = Class.forName( handlerName ) ; |
76 | }catch( ClassNotFoundException cnfe ){ |
77 | _log.warn( "Couldn't install interrupt handler ("+ |
78 | handlerName+") : "+cnfe ) ; |
79 | return -1 ; |
80 | } |
81 | try{ |
82 | _interruptHandler = (DomainInterruptHandler)handlerClass.newInstance() ; |
83 | }catch( Exception ee ){ |
84 | _log.warn( "Couldn't install interrupt handler ("+ |
85 | handlerName+") : "+ee ) ; |
86 | return -2 ; |
87 | } |
88 | _interruptThread = _nucleus.newThread( this ) ; |
89 | _interruptThread.start() ; |
90 | return 0 ; |
91 | } |
92 | public void run(){ |
93 | while( true ){ |
94 | try{ |
95 | Thread.sleep( _interruptTimer ) ; |
96 | if( _interruptHandler.interruptPending() )break ; |
97 | }catch( InterruptedException ie ){ |
98 | _log.info( "Interrupt loop was interrupted" ) ; |
99 | break ; |
100 | } |
101 | } |
102 | _log.info( "Interrupt loop stopped (shutting down system now)" ) ; |
103 | kill() ; |
104 | } |
105 | private void shutdownSystem() |
106 | { |
107 | String [] names = _nucleus.getCellNames(); |
108 | List<String> nonSystem = new ArrayList<String>(names.length); |
109 | List<String> system = new ArrayList<String>(names.length); |
110 | |
111 | for (int i = 0; i < names.length; i++) { |
112 | CellInfo info = _nucleus.getCellInfo(names[i]); |
113 | if (info == null) continue; |
114 | String cellName = info.getCellName(); |
115 | if (cellName.equals("System")) { |
116 | // Don't kill the system cell |
117 | } else if (info.getCellType().equals("System")) { |
118 | system.add(cellName); |
119 | } else { |
120 | nonSystem.add(cellName); |
121 | } |
122 | } |
123 | |
124 | _log.info("Will try to shutdown non-system cells " + nonSystem); |
125 | shutdownCells(nonSystem, 3000); |
126 | |
127 | _log.info("Will try to shutdown remaining cells " + system); |
128 | shutdownCells(system, 5000); |
129 | } |
130 | |
131 | /** |
132 | * Shuts downs named cells. The method will block until the cells |
133 | * are dead or until a timeout has occurred. |
134 | * |
135 | * @param cells List of names of cells to kill. |
136 | * @param timeout Time in milliseconds to wait for a cell to die. |
137 | */ |
138 | private void shutdownCells(List<String> cells, long timeout) |
139 | { |
140 | for (String cellName : cells) { |
141 | try { |
142 | _nucleus.kill(cellName); |
143 | } catch (IllegalArgumentException e) { |
144 | _log.info("Problem killing : " + cellName + " -> " + e.getMessage()); |
145 | } |
146 | } |
147 | |
148 | for (String cellName : cells) { |
149 | try { |
150 | if (_nucleus.join(cellName, timeout)) { |
151 | _log.info("Killed " + cellName); |
152 | } else { |
153 | _log.warn("Timeout waiting for " + cellName); |
154 | break; |
155 | } |
156 | } catch (InterruptedException e) { |
157 | _log.warn("Problem killing : " + cellName + " -> " + e.getMessage()); |
158 | break; |
159 | } |
160 | } |
161 | } |
162 | |
163 | public void cleanUp(){ |
164 | shutdownSystem() ; |
165 | _log.info("Opening shutdown lock") ; |
166 | _shutdownLock.open(); |
167 | System.exit(0) ; |
168 | } |
169 | public void getInfo( PrintWriter pw ){ |
170 | pw.println( " CellDomainName = "+getCellDomainName() ) ; |
171 | pw.print( " I/O rcv="+_packetsReceived ) ; |
172 | pw.print( ";asw="+_packetsAnswered ) ; |
173 | pw.print( ";frw="+_packetsForwarded ) ; |
174 | pw.print( ";rpy="+_packetsReplayed ) ; |
175 | pw.println( ";exc="+_exceptionCounter ) ; |
176 | long fm = _runtime.freeMemory() ; |
177 | long tm = _runtime.totalMemory() ; |
178 | |
179 | pw.println( " Memory : tot="+tm+";free="+fm+";used="+(tm-fm) ) ; |
180 | pw.println( " Cells (Threads)" ) ; |
181 | // |
182 | // count the threads |
183 | // |
184 | String [] names = _nucleus.getCellNames() ; |
185 | for( int i = 0 ; i < names.length ; i++ ){ |
186 | pw.print( " "+names[i]+"(" ) ; |
187 | Thread [] threads = _nucleus.getThreads(names[i]) ; |
188 | if( threads != null ){ |
189 | for( int j = 0 ; j < threads.length ; j++ ) |
190 | pw.print( threads[j].getName()+"," ) ; |
191 | } |
192 | pw.println(")"); |
193 | } |
194 | } |
195 | public void messageToForward( CellMessage msg ){ |
196 | msg.nextDestination() ; |
197 | try{ |
198 | sendMessage( msg ) ; |
199 | _packetsForwarded ++ ; |
200 | }catch( Exception eee ){ |
201 | _exceptionCounter ++ ; |
202 | } |
203 | } |
204 | public void messageArrived( CellMessage msg ){ |
205 | _log.info( "Message arrived : "+msg ) ; |
206 | _packetsReceived ++ ; |
207 | if( msg.isReply() ){ |
208 | _log.warn("Seems to a bounce : "+msg); |
209 | return ; |
210 | } |
211 | Object obj = msg.getMessageObject() ; |
212 | if( obj instanceof String ){ |
213 | String command = (String)obj ; |
214 | if( command.length() < 1 )return ; |
215 | Object reply = null ; |
216 | _log.info( "Command : "+command ) ; |
217 | reply = _cellShell.objectCommand2( command ) ; |
218 | _log.info( "Reply : "+reply ) ; |
219 | msg.setMessageObject( reply ) ; |
220 | _packetsAnswered ++ ; |
221 | }else if( obj instanceof AuthorizedString ){ |
222 | AuthorizedString as = (AuthorizedString)obj ; |
223 | String command = as.toString() ; |
224 | if( command.length() < 1 )return ; |
225 | Object reply = null ; |
226 | _log.info( "Command(p="+as.getAuthorizedPrincipal()+") : "+command ) ; |
227 | reply = _cellShell.objectCommand2( command ) ; |
228 | _log.info( "Reply : "+reply ) ; |
229 | msg.setMessageObject( reply ) ; |
230 | _packetsAnswered ++ ; |
231 | }else if( obj instanceof CommandRequestable ){ |
232 | CommandRequestable request = (CommandRequestable)obj ; |
233 | Object reply = null ; |
234 | try{ |
235 | _log.info( "Command : "+request.getRequestCommand() ) ; |
236 | reply = _cellShell.command( request ) ; |
237 | }catch( CommandException cee ){ |
238 | reply = cee ; |
239 | } |
240 | _log.info( "Reply : "+reply ) ; |
241 | msg.setMessageObject( reply ) ; |
242 | _packetsAnswered ++ ; |
243 | } |
244 | try{ |
245 | msg.revertDirection() ; |
246 | sendMessage( msg ) ; |
247 | _log.info( "Sending : "+msg ) ; |
248 | _packetsReplayed ++ ; |
249 | }catch( Exception e ){ |
250 | _exceptionCounter ++ ; |
251 | } |
252 | } |
253 | |
254 | public void uncaughtException(Thread t, Throwable e) |
255 | { |
256 | /* In case of fatal errors we shut down. The wrapper script |
257 | * will restart the domain. Notice that there is no guarantee |
258 | * that the fatal error will not reoccur during shutdown and |
259 | * in that case the shutdown may fail. We may want to consider |
260 | * refining the shutdown logic such that in recovers if the |
261 | * fatal error reoccurs. |
262 | */ |
263 | if (e instanceof VirtualMachineError) { |
264 | _log.error("Fatal JVM error", e); |
265 | _log.error("Shutting down..."); |
266 | kill(); |
267 | } |
268 | |
269 | _log.error("Uncaught exception in thread " + t.getName(), e); |
270 | } |
271 | } |