Source code: com/flexstor/common/gateway/Gateway.java
1 /*
2 * Gateway.java
3 *
4 * Copyright $Date: 2003/08/11 02:22:29 $ FLEXSTOR.net Inc.
5 *
6 * This work is licensed for use and distribution under license terms found at
7 * http://www.flexstor.org/license.html
8 *
9 */
10
11 package com.flexstor.common.gateway;
12
13 import java.io.InterruptedIOException;
14 import java.rmi.RemoteException;
15 import java.util.Vector;
16
17 import com.flexstor.common.constants.EjbHomeInterfacesI;
18 import com.flexstor.common.exceptions.ejb.EjbException;
19 import com.flexstor.common.gateway.debug.GatewayDebugOutput;
20 import com.flexstor.common.gateway.debug.GatewayDebugUtil;
21 import com.flexstor.common.gateway.engine.GatewayEngineI;
22 import com.flexstor.common.gateway.exceptions.GatewayInitException;
23 import com.flexstor.common.gateway.exceptions.TransactionFailedException;
24 import com.flexstor.common.resources.Resources;
25 import com.flexstor.ejb.EjbHome;
26 import com.flexstor.ejb.EjbObject;
27
28 /**
29 * Core class of the Server Gateway Framework
30 * @author Dan Schroeder
31 * @version 3.0
32 */
33 public abstract class Gateway
34 implements EjbHomeInterfacesI
35 {
36 /** Refrence to the current engine */
37 protected static GatewayEngineI engine = null;
38
39 /** True if the gateway framework has been initialized */
40 protected static boolean bInitialized = false;
41
42 /** Debug objects */
43 protected static boolean bSaveObjects = false;
44 protected static boolean bLoadObjects = false;
45 protected static GatewayDebugUtil util = null;
46
47 /** Manages gateway heartbeats. */
48 private static long nBeatDuration = 120000; // 2 Min.
49 private static HeartbeatManager heartbeat = null;
50
51
52 /**
53 * Returns the name of the home interface.
54 * @return the home interface name
55 */
56 protected abstract String getHomeName ( );
57
58
59 /**
60 * Returns the instance of the current bean, or null if the bean has not been created.
61 * @return an instance of EjbObject.
62 */
63 protected abstract EjbObject getBeanObject ( );
64
65 /**
66 * Checks to see if the gateway framework has been properly initialized.
67 * @return true if the gateway has been initalized.
68 */
69 public static boolean isInitalized ( )
70 {
71 return bInitialized;
72 }
73
74 /**
75 * Returns the home interface for the specified published name.
76 * @param sPubName the name of the home interface to retrieve.
77 * @return the home interface
78 * @throws Exception throws if sPubName is not found,
79 */
80 protected EjbHome getHome ( )
81 throws Exception
82 {
83 // Check to see if the gateway was initialized.
84 if ( !bInitialized )
85 throw new GatewayInitException ( "Gateway not initialized." );
86
87 return engine.getHome ( getHomeName() );
88 }
89
90 /**
91 * Reformats the given exception to a TransactionFailedException.
92 * This method also performs error logging, so it is important that this method be called
93 * whenever an incoming exception occurs.
94 * @param The generic exception.
95 * @return The TransactionFailedException.
96 */
97 protected TransactionFailedException buildException ( Throwable e )
98 {
99 return buildException( e, "", "" );
100 }
101
102 /**
103 * Reformats the given exception to a TransactionFailedException.
104 * This method also performs error logging, so it is important that this method be called
105 * whenever an incoming exception occurs.
106 * @param e The generic exception.
107 * @param sSourceModule The Source Module where the exception was originated.
108 * @param sClassIndentifier The Identifier for the Class where the exception was originated.
109 * @return The TransactionFailedException.
110 */
111 protected TransactionFailedException buildException ( Throwable e, String sSourceModule, String sClassIdentifier )
112 {
113 String sMessage = null;
114
115 if ( e instanceof EjbException )
116 {
117 EjbException ejb = (EjbException)e;
118 int nResource = ejb.getResourceId();
119 Vector vParams = ejb.getParmeters();
120
121 String sa[] = { "", "", "", "", "" };
122 if ( vParams != null )
123 vParams.copyInto ( sa );
124
125 sMessage = Resources.get ( nResource, true, sa[0], sa[1], sa[2], sa[3], sa[4] );
126 }
127 else if ( e instanceof Error )
128 sMessage = Resources.get ( 5839, true );
129 else
130 sMessage = Resources.get ( 5840, true );
131
132 if ( e instanceof RemoteException && ((RemoteException)e).detail instanceof InterruptedIOException )
133 Thread.currentThread().interrupt(); // reassert the interrupt
134 else
135 {
136 // Send error to Diagnostic
137 GatewayDebugOutput.printStackTrace ( sMessage, e );
138
139 // Log error
140 GatewayDebugOutput.logError( sMessage, e, sSourceModule, sClassIdentifier );
141 }
142
143 // Future code should reformat this exception.
144 return new TransactionFailedException ( e );
145 }
146
147
148 /**
149 * Shuts down the gatway framework by stopping the heartbeat thread and closing all open JNDI contexts.
150 */
151 protected void shutdown ( )
152 {
153 if ( heartbeat != null )
154 heartbeat.terminate();
155
156 engine.closeAllContexts();
157 }
158
159
160 /**
161 * Cleans up the gateway.
162 * NOTE: This method MUST be called to stop heartbeats from going to the EJB if beginHeartbeats() has been called.
163 * NOTE: This methos MUST be called if you wish the server to immediately cleanup (passivate) this EJB.
164 */
165 public void dispose ( )
166 {
167 try
168 {
169 // Get the object.
170 EjbObject o = getBeanObject();
171
172 // Debug message.
173 if ( o != null )
174 {
175 GatewayDebugOutput.println ( 4, "Dispose " + EBJObjectToString(o) );
176
177 // Stop heartbeats if they are on.
178 if ( heartbeat != null )
179 heartbeat.removeObject ( o );
180
181
182 // This code is disabled due to bugs in Oracle 8i. This code should be enabled when
183 // oracle stops throwing exceptions on a remove().
184 if ( !canLoadObject() )
185 o.remove();
186 }
187 }
188 catch ( Throwable e ) { }
189 }
190
191
192 /**
193 * Enables debugging (serialization of objects to files).
194 * @param sBasePath the platform specific path of the directory to store objects in.
195 * @param bSave incoming objects are saved if true.
196 * @param bLoad loads objects from files instead of getting them from the server.
197 * @throws GatewayInitException if both bSave and bLoad are true.
198 */
199 public static void enableDebugging ( String sBasePath, boolean bSave, boolean bLoad )
200 throws GatewayInitException
201 {
202 if ( bSaveObjects && bLoadObjects )
203 throw new GatewayInitException ( "Cannot save and load objects in same debug session." );
204
205 util = new GatewayDebugUtil ( sBasePath, 4096 );
206 bSaveObjects = bSave;
207 bLoadObjects = bLoad;
208 }
209
210
211 /**
212 * Returns true if object saving is on.
213 */
214 protected boolean canSaveObject ( )
215 {
216 return bSaveObjects;
217 }
218
219
220 /**
221 * Returns true if object loading is on.
222 */
223 protected boolean canLoadObject ( )
224 {
225 return bLoadObjects;
226 }
227
228
229 /**
230 * Stores an object to a file.
231 * @param sName a unique name for the object.
232 * @param o the object to store.
233 * @param bUpdate update the CSO Database if true.
234 */
235 protected void storeObject ( String sName, Object o, boolean bUpdate )
236 throws Throwable
237 {
238 util.storeObject ( sName, o, bUpdate );
239 }
240
241
242 /**
243 * Stores an object to a file.
244 * @param sName a unique name for the object.
245 * @param o the object to store.
246 */
247 protected void storeObject ( String sName, Object o )
248 throws Throwable
249 {
250 util.storeObject ( sName, o, true );
251 }
252
253
254 /**
255 * Loads an object from a file.
256 * @param sName a unique name for the object.
257 * @return the object.
258 */
259 protected Object retrieveObject ( String sName )
260 throws Throwable
261 {
262 return util.retrieveObject ( sName );
263 }
264
265
266 /**
267 * Converts an ROEJBObject reference to a String and limits it to 100 characters.
268 * @param o the EjbObject
269 * @return the string form of o
270 */
271 public String EBJObjectToString ( EjbObject o )
272 {
273 String s = "" + o;
274 if ( s.length() > 100 )
275 s = s.substring ( 0, 100 );
276
277 return s;
278 }
279
280
281 /**
282 * Starts sending heartbeats to the EJB server for the specified object. Call dispose()
283 * to stop the heartbeats for this bean.
284 *
285 * This method does not cause the heartbeat to be sent right away. In the worst case it will take the
286 * full heartbeat duration (nBeatDuration) before a heartbeat is sent.
287 */
288 public void beginHeartbeats ( )
289 {
290 if ( heartbeat == null )
291 heartbeat = new HeartbeatManager ( nBeatDuration );
292
293 heartbeat.addObject ( getBeanObject() );
294 }
295
296
297 /**
298 * Manages heartbeats for all instances of the server gateway framework.
299 */
300 private class HeartbeatManager
301 extends Thread
302 {
303 private boolean bStop;
304 private long nBeatDuration;
305 private Vector vObjects;
306
307 public HeartbeatManager ( long nBeatDuration )
308 {
309 super ( "Server Gateway Heartbeat Thread" );
310 setPriority ( NORM_PRIORITY - 1 );
311
312 GatewayDebugOutput.println ( 6, "Initalizing Server Gateway Heartbeat Manager" );
313
314 this.bStop = false;
315 this.vObjects = new Vector();
316 this.nBeatDuration = nBeatDuration;
317 this.start();
318 }
319
320 public void run ( )
321 {
322 if ( canLoadObject() )
323 return;
324
325 while ( !bStop )
326 {
327 service();
328
329 try
330 {
331 sleep ( nBeatDuration );
332 }
333 catch ( InterruptedException e )
334 {
335 GatewayDebugOutput.println ( 6, "Heartbeat thread was interrupted." );
336 }
337 }
338 }
339
340 public void service ( )
341 {
342 // Broadcast heartbeats.
343 GatewayDebugOutput.println ( 6, "Servicing heartbeat thread..." );
344
345 EjbObject o;
346 for ( int i = 0; i < vObjects.size(); i++ )
347 {
348 o = (EjbObject)vObjects.elementAt(i);
349 GatewayDebugOutput.println ( 6, "Calling keepAlive() for " + EBJObjectToString(o) + "." );
350
351 try
352 {
353 o.keepAlive();
354 }
355 catch ( Throwable t )
356 {
357 GatewayDebugOutput.printStackTrace ( "keepAlive() failed!!!", t );
358 }
359 }
360 }
361
362 private synchronized void terminate ( )
363 {
364 GatewayDebugOutput.println ( 6, "Terminating heartbeat thread..." );
365 bStop = true;
366 interrupt();
367
368 // Make sure that dispose() is called on all the active beans.
369 EjbObject o;
370 for ( int i = 0; i < vObjects.size(); i++ )
371 {
372 o = (EjbObject)vObjects.elementAt(i);
373
374 try
375 {
376 o.remove();
377 GatewayDebugOutput.println ( 6, "Heartbeat manager disposed of " + EBJObjectToString(o) );
378 }
379 catch ( Exception e )
380 {
381 GatewayDebugOutput.println ( 6, "Heartbeat manager could not dispose of " + EBJObjectToString(o) );
382 }
383 }
384 }
385
386 public synchronized void addObject ( EjbObject o )
387 {
388 if ( canLoadObject() )
389 return;
390
391 GatewayDebugOutput.println ( 6, "Adding heartbeat for " + EBJObjectToString(o) + "." );
392 if ( !vObjects.contains(o) )
393 vObjects.addElement ( o );
394 }
395
396 public synchronized void removeObject ( EjbObject o )
397 {
398 if ( vObjects.contains(o) )
399 {
400 GatewayDebugOutput.println ( 6, "Removing heartbeat for " + EBJObjectToString(o) + "." );
401 vObjects.removeElement ( o );
402 }
403 }
404 }
405 }