KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > enterprise > admin > server > core > channel > RMIClient


1 /*
2  * The contents of this file are subject to the terms
3  * of the Common Development and Distribution License
4  * (the License). You may not use this file except in
5  * compliance with the License.
6  *
7  * You can obtain a copy of the license at
8  * https://glassfish.dev.java.net/public/CDDLv1.0.html or
9  * glassfish/bootstrap/legal/CDDLv1.0.txt.
10  * See the License for the specific language governing
11  * permissions and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL
14  * Header Notice in each file and include the License file
15  * at glassfish/bootstrap/legal/CDDLv1.0.txt.
16  * If applicable, add the following below the CDDL Header,
17  * with the fields enclosed by brackets [] replaced by
18  * you own identifying information:
19  * "Portions Copyrighted [year] [name of copyright owner]"
20  *
21  * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
22  */

23
24 /**
25  * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
26  *
27  * Copyright 2001-2002 by iPlanet/Sun Microsystems, Inc.,
28  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
29  * All rights reserved.
30  */

31 package com.sun.enterprise.admin.server.core.channel;
32
33 import java.io.File JavaDoc;
34 import java.io.FileInputStream JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.ObjectInputStream JavaDoc;
37 import java.rmi.RemoteException JavaDoc;
38 import java.rmi.ServerException JavaDoc;
39 import java.util.logging.Level JavaDoc;
40 import java.util.logging.Logger JavaDoc;
41 import java.util.logging.Handler JavaDoc;
42
43 import com.sun.enterprise.admin.common.constant.AdminConstants;
44 import com.sun.enterprise.admin.common.ServerInstanceStatus;
45 import com.sun.enterprise.admin.common.Status;
46 import com.sun.enterprise.admin.event.AdminEvent;
47 import com.sun.enterprise.admin.event.AdminEventResult;
48
49 //i18n import
50
import com.sun.enterprise.util.i18n.StringManager;
51
52 /**
53  * RMI client is used to send admin channel messages over RMI.
54  */

55 public class RMIClient implements Runnable JavaDoc {
56
57     private File JavaDoc stubFile;
58     private File JavaDoc seedFile;
59     private long stubFileTs = 0;
60     private byte[] key;
61     private RemoteAdminChannel stub;
62     private boolean autoRefresh;
63     private long autoRefreshInterval;
64     private Thread JavaDoc autoRefreshThread;
65
66     /**
67      * Create a new RMI client using specified stub file and use the specified
68      * byte array (seed) for all calls to the remote object. To obtain an
69      * instance of RMIClient please use the public method
70      * <code>AdminChannel.getRMIClient()</code> which ensure that all calls to
71      * a particular server instance go through the same object instance
72      * (of RMIClient).
73      * @param stubFile name of the RMI stub file
74      * @param seedFile name of the shared secret file
75      * @throws IllegalArgumentException if either stubFile or seedFile is null.
76      */

77     RMIClient(String JavaDoc stubFile, String JavaDoc seedFile) {
78         if (stubFile == null || seedFile == null) {
79             warn(CLIENT_NULLARGS_ERRCODE);
80             throw new IllegalArgumentException JavaDoc(CLIENT_NULLARGS_ERRMSG);
81         }
82         this.stubFile = new File JavaDoc(stubFile);
83         this.seedFile = new File JavaDoc(seedFile);
84         if (this.stubFile.exists()) {
85             stub = readStub();
86         }
87         if (AdminChannel.getClientAutoRefreshEnabled()) {
88             startAutoRefreshThread(
89                     AdminChannel.getClientAutoRefreshInterval());
90         }
91     }
92
93     /**
94      * Constructor for local mode
95      */

96     public RMIClient(boolean isDebug, String JavaDoc stubFile, String JavaDoc seedFile) {
97     if (! isDebug) {
98             logger.setLevel(java.util.logging.Level.SEVERE);
99     }
100         if (stubFile == null || seedFile == null) {
101             throw new IllegalArgumentException JavaDoc(CLIENT_NULLARGS_ERRMSG);
102         }
103         this.stubFile = new File JavaDoc(stubFile);
104         this.seedFile = new File JavaDoc(seedFile);
105         if (this.stubFile.exists()) {
106             stub = readStub();
107         }
108     }
109
110     /**
111      * Start auto refresh thread. The auto refresh thread refreshes the remote
112      * stub if the stub file has changed on the disk.
113      */

114     void startAutoRefreshThread(long interval) {
115         if (interval <= 0) {
116             throw new IllegalArgumentException JavaDoc(INVALID_AUTO_REFRESH_INTERVAL);
117         }
118         autoRefresh = true;
119         autoRefreshInterval = interval;
120         if (autoRefreshThread != null && autoRefreshThread.isAlive()) {
121             return;
122         } else {
123             autoRefreshThread = new Thread JavaDoc(this);
124             autoRefreshThread.start();
125         }
126     }
127
128     /**
129      * Stop auto refresh thread.
130      */

131     void stopAutoRefreshThread() {
132         autoRefresh = false;
133     }
134
135     /**
136      * Auto refresh this rmi client.
137      */

138     public void run() {
139         while (autoRefresh) {
140             try {
141                 Thread.sleep(autoRefreshInterval);
142             } catch (InterruptedException JavaDoc ie) {
143                 warn(AUTO_REFRESH_INTR);
144                 autoRefresh = false;
145             }
146             if (autoRefresh) {
147                 checkServerStatus();
148             }
149         }
150     }
151
152     /**
153      * Send specified event notification over admin channel
154      */

155     public AdminEventResult sendNotification(AdminEvent event) {
156         // Normal handling, send the event
157
boolean doRetry = true;
158         AdminEventResult result = null;
159         if (stub != null) {
160             try {
161                 result = stub.sendNotification(key, event);
162                 doRetry = false;
163             } catch (ServerException JavaDoc re) {
164                 if ((re.detail != null) &&
165                         (re.detail instanceof java.lang.IllegalArgumentException JavaDoc
166                         || re.detail instanceof java.lang.SecurityException JavaDoc)) {
167                     doRetry = false;
168                     warn(EVENT_NOTIFY_ERROR);
169                     debug(re.detail);
170                 } else {
171                     if (re.detail != null) {
172                         debug(re.detail);
173                     }
174                     debug(re);
175                 }
176             } catch (RemoteException JavaDoc re) {
177                 if (re.detail != null) {
178                     debug(re.detail);
179                 }
180                 debug(re);
181             }
182         }
183         if (doRetry) {
184             // Normal processing did not work, try to get stub again and then
185
// attempt to send the event
186
boolean gotNew = checkServerStatus();
187             if (stub != null && gotNew) {
188                 try {
189                     result = stub.sendNotification(key, event);
190                 } catch (RemoteException JavaDoc re) {
191                     warn(EVENT_RENOTIFY_ERROR);
192                     if (re.detail != null) {
193                         debug(re.detail);
194                     }
195                     debug(re);
196                 }
197             }
198         }
199         if (result == null) {
200             // Still couldn't communicate, set result appropriately
201
result = new AdminEventResult(event.getSequenceNumber());
202             result.setResultCode(AdminEventResult.TRANSMISSION_ERROR);
203             if (stub == null) {
204                 result.addMessage(event.getEffectiveDestination(),
205                     "Remote Stub is null");
206             }
207         }
208         return result;
209     }
210
211     /** Determines wheter the instance with given name is alive.
212      * Really speaking, checks whether the RMI channel is responsive.
213      * The method returns immediately with the status without any retries.
214      * @return boolean indicating whether the RMIServer Object
215      * that <code> this </code> server instance is alive.
216      */

217     public boolean isAlive() {
218         return isAlive(false);
219     }
220
221     /**
222      * Determines whether the instance represented by this object is alive.
223      * Unless the parameter refreshStub is true, the responsiveness of
224      * instance is checked by using cached stub (if any) and if there is no
225      * cached stub the method returns false.
226      * @param refreshStub if true, refresh remote stub if it has changed
227      * @return true if the instance represented by <code>this</code> object
228      * is responding, false otherwise.
229      */

230     public boolean isAlive(boolean refreshStub) {
231
232         if (refreshStub) {
233             boolean gotNew = checkServerStatus();
234         }
235
236         boolean isAlive = true;
237
238         if (stub != null) {
239             try {
240                 stub.pingServer(key);
241             }
242             catch(RemoteException JavaDoc re) {
243                 debug(re);
244                 isAlive = false;
245             }
246         }
247         else {
248             isAlive = false;
249         }
250         return ( isAlive );
251     }
252
253     /**
254      * Get server instance status code. If the instance can not be contacted
255      * over rmi channel then the method reports that instance is not running.
256      * The return value of this method is one of the constants <code>
257      * kInstanceStartingCode, kInstanceRunningCode, kInstanceStoppingCode or
258      * kInstanceNotRunningCode</code> from the class <code>
259      * com.sun.enterprise.admin.common.Status</code>.
260      * @return an int denoting the status of server starting, running, stopping
261      * or not running.
262      */

263     public int getInstanceStatusCode() {
264         boolean gotNew = checkServerStatus();
265         int statusCode = Status.kInstanceNotRunningCode;
266         if (stub != null) {
267             try {
268                 statusCode = stub.getServerStatusCode(key);
269             } catch (RemoteException JavaDoc re) {
270                 debug(CHANNEL_COMM_ERROR, stubFile.getName());
271                 if (re.detail != null) {
272                     trace(re.detail);
273                 }
274                 trace(re);
275             } catch (IllegalArgumentException JavaDoc iae) {
276                 debug(CHANNEL_COMM_ERROR, stubFile.getName());
277                 trace(iae);
278                 // This means that the key did not match. Attempt to read
279
// the key from the disk again to work around the race
280
// condition when the file is read on the client before the
281
// server has finished writing (and hence client has partial
282
// key). Another read updates the shared key on the client.
283
byte[] newKey = null;
284                 try {
285                     newKey = readSeed();
286                 } catch (IOException JavaDoc ioe) {
287                     debug(FILE_READ_ERROR, seedFile.getName());
288                     trace(ioe);
289                 }
290                 if (newKey != null) {
291                     key = newKey;
292                 }
293                 throw iae;
294             }
295         }
296         return statusCode;
297     }
298
299     /**
300      * Get the port where the conflict occurs.
301      *
302      * @return A valid port number.0 If there is any error in processing
303      */

304     public int getConflictedPort() {
305         int conflictedPort = 0;
306         boolean gotNew = checkServerStatus();
307         if (stub != null) {
308             try {
309                 conflictedPort = stub.getConflictedPort(key);
310             } catch (RemoteException JavaDoc re) {
311                 debug(CHANNEL_COMM_ERROR, stubFile.getName());
312                 if (re.detail != null) {
313                     trace(re.detail);
314                 }
315                 trace(re);
316             }
317         }
318         return conflictedPort;
319     }
320
321     /**
322      * Triggers exit of the server VM. Server VM will client
323      * that got the conflicted port number calls this method.
324      */

325     public void triggerServerExit() {
326         boolean gotNew = checkServerStatus();
327         if (stub != null) {
328             try {
329                 stub.triggerServerExit(key);
330             } catch (RemoteException JavaDoc re) {
331                 debug(CHANNEL_COMM_ERROR, stubFile.getName());
332                 if (re.detail != null) {
333                     trace(re.detail);
334                 }
335                 trace(re);
336             }
337         }
338     }
339
340     /**
341      * Is restart needed on the instance. The status is set by admin server and
342      * instance just keeps track of it across admin server restarts. If the
343      * instance has already restarted since admin server set the status, the
344      * instance does not require restart (as expected).
345      * @return true if the instance requires restart, false otherwise.
346      */

347     public boolean isRestartNeeded() {
348         boolean restartNeeded = false;
349         boolean gotNew = checkServerStatus();
350         if (stub != null) {
351             try {
352                 restartNeeded = stub.isRestartNeeded(key);
353             } catch (RemoteException JavaDoc re) {
354                 debug(CHANNEL_COMM_ERROR, stubFile.getName());
355                 if (re.detail != null) {
356                     trace(re.detail);
357                 }
358                 trace(re);
359             }
360         }
361         return restartNeeded;
362     }
363
364     /**
365      * Set restart needed status for a server instance. If the instance is not
366      * running or if there is an error in communicating, the instance restart
367      * status will not be changed. The status set by this method is preserved
368      * in the instance across admin server restarts.
369      * @param restartNeeded true if instance restart is needed, false otherwise.
370      */

371     public void setRestartNeeded(boolean restartNeeded) {
372         boolean gotNew = checkServerStatus();
373         if (stub != null) {
374             try {
375                 stub.setRestartNeeded(key, restartNeeded);
376             } catch (RemoteException JavaDoc re) {
377                 debug(CHANNEL_COMM_ERROR, stubFile.getName());
378                 if (re.detail != null) {
379                     trace(re.detail);
380                 }
381                 trace(re);
382             }
383         }
384     }
385
386     /**
387      * Check status of server stub file and refresh if needed.
388      */

389     private boolean checkServerStatus() {
390         boolean gotNew = false;
391         if (stubFile.exists()) {
392             long ts = stubFile.lastModified();
393             if (ts > stubFileTs) {
394                 if (stubFile.canRead()) {
395                     RemoteAdminChannel obj = readStub();
396                     if (obj != null) {
397                         gotNew = true;
398                         stub = obj;
399                     }
400                 } else {
401                     warn(FILE_READ_ERROR, stubFile.getName());
402                 }
403             }
404         } else {
405             if (stub != null) {
406                 stub = null;
407             }
408         }
409         return gotNew;
410     }
411
412     /**
413      * Read stub from stub file
414      */

415     private RemoteAdminChannel readStub() {
416         RemoteAdminChannel obj = null;
417         FileInputStream JavaDoc fis = null;
418         try {
419             stubFileTs = stubFile.lastModified();
420             fis = new FileInputStream JavaDoc(stubFile);
421             ObjectInputStream JavaDoc ois = new ObjectInputStream JavaDoc(fis);
422             obj = (RemoteAdminChannel)ois.readObject();
423         } catch (IOException JavaDoc ioe) {
424             warn(CLIENT_INIT_ERROR);
425             debug(ioe);
426         } catch (ClassNotFoundException JavaDoc cnfe) {
427             warn(CLIENT_INIT_ERROR);
428             debug(cnfe);
429         } finally {
430             if (fis != null) {
431                 try {
432                     fis.close();
433                 } catch (IOException JavaDoc ioe) {
434                 }
435             }
436         }
437         try {
438             key = readSeed();
439         } catch (IOException JavaDoc ioe) {
440             warn(CLIENT_INIT_ERROR);
441             debug(ioe);
442             obj = null;
443         }
444         if (obj == null) {
445             stubFileTs = 0;
446         }
447         return obj;
448     }
449
450     /**
451      * Read shared secret from file.
452      */

453     private byte[] readSeed() throws IOException JavaDoc {
454         byte[] seed = null;
455         if (seedFile.exists() && seedFile.canRead()) {
456             // Seed file is updated after creating stub file and therefore
457
// it should only be read only if it has been modified since stub
458
// file was modified. NOTE: This relies on the fact that the
459
// server always (on every startup) writes seed file after stubfile.
460
long seedFileTs = seedFile.lastModified();
461             if (seedFileTs >= stubFileTs) {
462                 FileInputStream JavaDoc fis = null;
463                 try {
464                     fis = new FileInputStream JavaDoc(seedFile);
465                     seed = new byte[AdminChannel.SEED_LENGTH];
466                     fis.read(seed);
467                 } catch (IOException JavaDoc ioe) {
468                     warn(AdminChannel.KEY_READ_ERROR);
469                     debug(ioe);
470                     seed = null;
471                 } finally {
472                     if (fis != null) {
473                         try {
474                             fis.close();
475                         } catch (IOException JavaDoc ioe) {
476                         }
477                     }
478                 }
479             } else {
480                 debug(SEED_FILE_OLDER,
481                         new Long JavaDoc[] {new Long JavaDoc(seedFileTs), new Long JavaDoc(stubFileTs)});
482             }
483         } else {
484             warn(AdminChannel.KEY_READ_ERROR);
485             debug(FILE_READ_ERROR, seedFile.getName());
486         }
487         if (seed == null) {
488             String JavaDoc msg = localStrings.getString( "admin.server.core.channel.unable_initializing_key", seedFile );
489             throw new IOException JavaDoc( msg );
490         }
491         return seed;
492     }
493
494     /**
495      * Has the server instance restarted since specified timestamp. If instance
496      * is not running, the method will return false. The return value is
497      * accurate within the timespan as specified in getClientRefreshInterval()
498      * of AdminChannel -- meaning that if the time period since instance restart
499      * is less than the specified timespan then the method may return false
500      * instead of true.
501      * @param ts Timestamp to check for
502      * @return true if the instance has restarted since specified timestamp,
503      * false otherwise.
504      */

505     public boolean hasRestartedSince(long ts) {
506         return hasRestartedSince(ts, false);
507     }
508
509     /**
510      * Has the server instance restarted since specified timestamp. If instance
511      * is not running, the method will return false. If refreshStub is true
512      * then the method will attempt to read newer stub (if any) and will report
513      * status using that. If refreshStub is false then the stub is not re-read
514      * and return value is dependent on the cached stub (if any).
515      * @param ts Timestamp to check for
516      * @param refreshStub if true, refresh remote stub if it has changed
517      * @return true if the instance has restarted since specified timestamp,
518      * false otherwise.
519      */

520     public boolean hasRestartedSince(long ts, boolean refreshStub) {
521         if (refreshStub) {
522             boolean gotNew = checkServerStatus();
523         }
524         boolean restarted = false;
525         if (stubFile != null) {
526             if (stubFileTs > ts) {
527                 restarted = true;
528             }
529         }
530         return restarted;
531     }
532
533     //
534
// logger methods copied from AdminChannel
535
//
536

537     static void trace(Throwable JavaDoc t) {
538         logger.log(Level.FINEST, t.getMessage(), t);
539     }
540
541     static void warn(String JavaDoc s) {
542         logger.warning(s);
543     }
544
545     static void warn(String JavaDoc msgkey, String JavaDoc obj1) {
546         logger.log(Level.WARNING, msgkey, obj1);
547     }
548
549     static void debug(String JavaDoc s) {
550         logger.fine(s);
551     }
552
553     static void debug(String JavaDoc msgkey, String JavaDoc obj1) {
554         logger.log(Level.FINE, msgkey, obj1);
555     }
556
557     static void debug(String JavaDoc msgkey, Object JavaDoc[] objarr) {
558         logger.log(Level.FINE, msgkey, objarr);
559     }
560
561     static void debug(Throwable JavaDoc t) {
562         logger.log(Level.FINE, t.getMessage(), t);
563     }
564
565     // i18n StringManager
566
private static StringManager localStrings =
567         StringManager.getManager( RMIClient.class );
568
569     private static final String JavaDoc CLIENT_NULLARGS_ERRCODE =
570             "channel.client_nullargs";
571     private static final String JavaDoc CLIENT_NULLARGS_ERRMSG =
572             localStrings.getString( "admin.server.core.channel.attempt_initializing_channel_client_with_null_arguments" );
573     private static final String JavaDoc CLIENT_INIT_ERROR = "channel.client_init_error";
574     private static final String JavaDoc EVENT_NOTIFY_ERROR =
575             "channel.event_notify_error";
576     private static final String JavaDoc EVENT_RENOTIFY_ERROR =
577             "channel.event_renotify_error";
578     private static final String JavaDoc AUTO_REFRESH_INTR = "channel.auto_refresh_intr";
579     private static final String JavaDoc CHANNEL_COMM_ERROR = "channel.comm_error";
580     private static final String JavaDoc INVALID_AUTO_REFRESH_INTERVAL =
581             localStrings.getString(
582                     "admin.server.core.channel.invalid_auto_refresh_interval");
583
584     static final String JavaDoc FILE_READ_ERROR = "channel.file_read_error";
585     static final String JavaDoc SEED_FILE_OLDER = "channel.seed_file_older";
586
587     static Logger JavaDoc logger = Logger.getLogger(AdminConstants.kLoggerName);
588 }
589
Popular Tags