admin@glassfish.java.net

Re: code review: com.sun.enterprise.admin.server.core.channel.RMIClient

From: Lloyd L Chambers <Lloyd.Chambers_at_Sun.COM>
Date: Fri, 02 Feb 2007 15:27:16 -0800

I'm going to hold off...seems there's some real concern and I have
enough fish to fry right now.

Lloyd

On Feb 2, 2007, at 2:03 PM, kedar wrote:

> Lloyd,
>
> I'd suggest to start with basic testing with a cluster or two
> comprising
> of two-three instances and scripting the start/stop-cluster
> operations.
>
> I believe you can use 2 computers in a LAN for this purpose.
>
> As you know, QL does not test cluster creation/startup/shutdown.
>
> Thanks,
> Kedar
>
> Lloyd L Chambers wrote:
>> Thanks for the feedback Byron. Who in SQE might be able to test
>> it for me?
>>
>> Lloyd
>>
>> On Feb 2, 2007, at 11:51 AM, Byron Nevins wrote:
>>
>>> Changing RMIClient carries extreme risk Have you done multi-
>>> machine tests with plenty of instances and a cluster or two and
>>> repeated starts and stops of everything? If not, then I
>>> recommend doing it, asking QE to do it, or not committing the
>>> changes.
>>>
>>> Lloyd Chambers wrote:
>>>> TIMEOUT: 17:00 PST Feb 2, 2007
>>>>
>>>> https://glassfish.dev.java.net/issues/show_bug.cgi?id=2273
>>>>
>>>> Diffs and whole file follow. To make thread safe:
>>>>
>>>> - static and instance variables 'final' wherever possible
>>>>
>>>> - constructor changed to allow instance variables to be final
>>>> (prefetch booleans, allowing assignment once to final variable)
>>>>
>>>> - 'synchronized' and 'volatile' used for mutable state
>>>>
>>>> Lloyd
>>>>
>>>>
>>>> ----------------
>>>> MB2:/gf/build/glassfish/appserv-core lloyd$ cvs diff -u 10 -w
>>>> src/java/com/sun/enterprise/admin/server/core/channel/
>>>> RMIClient.java
>>>> cvs server: I know nothing about 10
>>>> cvs server: I know nothing about -w
>>>> Index: src/java/com/sun/enterprise/admin/server/core/channel/
>>>> RMIClient.java
>>>> ===================================================================
>>>> RCS file: /cvs/glassfish/appserv-core/src/java/com/sun/
>>>> enterprise/admin/server/core/channel/RMIClient.java,v
>>>> retrieving revision 1.3
>>>> diff -u -r1.3 RMIClient.java
>>>> --- src/java/com/sun/enterprise/admin/server/core/channel/
>>>> RMIClient.java 25 Dec 2005 04:14:23 -0000 1.3
>>>> +++ src/java/com/sun/enterprise/admin/server/core/channel/
>>>> RMIClient.java 2 Feb 2007 19:18:16 -0000
>>>> @@ -52,16 +52,15 @@
>>>> /**
>>>> * RMI client is used to send admin channel messages over RMI.
>>>> */
>>>> -public class RMIClient implements Runnable {
>>>> -
>>>> - private File stubFile;
>>>> - private File seedFile;
>>>> - private long stubFileTs = 0;
>>>> - private byte[] key;
>>>> - private RemoteAdminChannel stub;
>>>> - private boolean autoRefresh;
>>>> - private long autoRefreshInterval;
>>>> - private Thread autoRefreshThread;
>>>> +public final class RMIClient implements Runnable {
>>>> + private final File stubFile;
>>>> + private final File seedFile;
>>>> + private volatile long stubFileTs = 0;
>>>> + private volatile byte[] key;
>>>> + private volatile RemoteAdminChannel stub;
>>>> + private volatile boolean autoRefresh;
>>>> + private final long autoRefreshInterval;
>>>> + private final Thread autoRefreshThread;
>>>> /**
>>>> * Create a new RMI client using specified stub file and
>>>> use the specified
>>>> @@ -84,19 +83,19 @@
>>>> if (this.stubFile.exists()) {
>>>> stub = readStub();
>>>> }
>>>> - if (AdminChannel.getClientAutoRefreshEnabled()) {
>>>> - startAutoRefreshThread(
>>>> - AdminChannel.getClientAutoRefreshInterval());
>>>> - }
>>>> +
>>>> + autoRefresh = AdminChannel.getClientAutoRefreshEnabled();
>>>> + autoRefreshInterval = autoRefresh ?
>>>> AdminChannel.getClientAutoRefreshInterval() : 0;
>>>> + autoRefreshThread = autoRefresh ?
>>>> startAutoRefreshThread() : null;
>>>> }
>>>> /**
>>>> * Constructor for local mode
>>>> */
>>>> public RMIClient(boolean isDebug, String stubFile, String
>>>> seedFile) {
>>>> - if (! isDebug) {
>>>> - logger.setLevel(java.util.logging.Level.SEVERE);
>>>> - }
>>>> + if (! isDebug) {
>>>> + logger.setLevel(java.util.logging.Level.SEVERE);
>>>> + }
>>>> if (stubFile == null || seedFile == null) {
>>>> throw new IllegalArgumentException
>>>> (CLIENT_NULLARGS_ERRMSG);
>>>> }
>>>> @@ -105,24 +104,25 @@
>>>> if (this.stubFile.exists()) {
>>>> stub = readStub();
>>>> }
>>>> +
>>>> + autoRefresh = false;
>>>> + autoRefreshInterval = 0;
>>>> + autoRefreshThread = null;
>>>> }
>>>> /**
>>>> * Start auto refresh thread. The auto refresh thread
>>>> refreshes the remote
>>>> * stub if the stub file has changed on the disk.
>>>> */
>>>> - void startAutoRefreshThread(long interval) {
>>>> - if (interval <= 0) {
>>>> + private Thread startAutoRefreshThread() {
>>>> + if ( autoRefreshInterval <= 0 || ! autoRefresh ) {
>>>> throw new IllegalArgumentException
>>>> (INVALID_AUTO_REFRESH_INTERVAL);
>>>> }
>>>> - autoRefresh = true;
>>>> - autoRefreshInterval = interval;
>>>> - if (autoRefreshThread != null &&
>>>> autoRefreshThread.isAlive()) {
>>>> - return;
>>>> - } else {
>>>> - autoRefreshThread = new Thread(this);
>>>> - autoRefreshThread.start();
>>>> - }
>>>> +
>>>> + final Thread theThread = new Thread(this);
>>>> + theThread.start();
>>>> +
>>>> + return theThread;
>>>> }
>>>> /**
>>>> @@ -386,7 +386,7 @@
>>>> /**
>>>> * Check status of server stub file and refresh if needed.
>>>> */
>>>> - private boolean checkServerStatus() {
>>>> + private synchronized boolean checkServerStatus() {
>>>> boolean gotNew = false;
>>>> if (stubFile.exists()) {
>>>> long ts = stubFile.lastModified();
>>>> @@ -563,7 +563,7 @@
>>>> }
>>>> // i18n StringManager
>>>> - private static StringManager localStrings =
>>>> + private static final StringManager localStrings =
>>>> StringManager.getManager( RMIClient.class );
>>>> private static final String CLIENT_NULLARGS_ERRCODE =
>>>> @@ -584,5 +584,5 @@
>>>> static final String FILE_READ_ERROR =
>>>> "channel.file_read_error";
>>>> static final String SEED_FILE_OLDER =
>>>> "channel.seed_file_older";
>>>> - static Logger logger = Logger.getLogger
>>>> (AdminConstants.kLoggerName);
>>>> + static final Logger logger = Logger.getLogger
>>>> (AdminConstants.kLoggerName);
>>>> }
>>>> MB2:/gf/build/glassfish/appserv-core lloyd$
>>>>
>>>> --------------------
>>>>
>>>> public final class RMIClient implements Runnable {
>>>> private final File stubFile;
>>>> private final File seedFile;
>>>> private volatile long stubFileTs = 0;
>>>> private volatile byte[] key;
>>>> private volatile RemoteAdminChannel stub;
>>>> private volatile boolean autoRefresh;
>>>> private final long autoRefreshInterval;
>>>> private final Thread autoRefreshThread;
>>>>
>>>> /**
>>>> * Create a new RMI client using specified stub file and use
>>>> the specified
>>>> * byte array (seed) for all calls to the remote object. To
>>>> obtain an
>>>> * instance of RMIClient please use the public method
>>>> * <code>AdminChannel.getRMIClient()</code> which ensure
>>>> that all calls to
>>>> * a particular server instance go through the same object
>>>> instance
>>>> * (of RMIClient).
>>>> * @param stubFile name of the RMI stub file
>>>> * @param seedFile name of the shared secret file
>>>> * @throws IllegalArgumentException if either stubFile or
>>>> seedFile is null.
>>>> */
>>>> RMIClient(String stubFile, String seedFile) {
>>>> if (stubFile == null || seedFile == null) {
>>>> warn(CLIENT_NULLARGS_ERRCODE);
>>>> throw new IllegalArgumentException
>>>> (CLIENT_NULLARGS_ERRMSG);
>>>> }
>>>> this.stubFile = new File(stubFile);
>>>> this.seedFile = new File(seedFile);
>>>> if (this.stubFile.exists()) {
>>>> stub = readStub();
>>>> }
>>>>
>>>> autoRefresh = AdminChannel.getClientAutoRefreshEnabled();
>>>> autoRefreshInterval = autoRefresh ?
>>>> AdminChannel.getClientAutoRefreshInterval() : 0;
>>>> autoRefreshThread = autoRefresh ?
>>>> startAutoRefreshThread() : null;
>>>> }
>>>>
>>>> /**
>>>> * Constructor for local mode
>>>> */
>>>> public RMIClient(boolean isDebug, String stubFile, String
>>>> seedFile) {
>>>> if (! isDebug) {
>>>> logger.setLevel(java.util.logging.Level.SEVERE);
>>>> }
>>>> if (stubFile == null || seedFile == null) {
>>>> throw new IllegalArgumentException
>>>> (CLIENT_NULLARGS_ERRMSG);
>>>> }
>>>> this.stubFile = new File(stubFile);
>>>> this.seedFile = new File(seedFile);
>>>> if (this.stubFile.exists()) {
>>>> stub = readStub();
>>>> }
>>>>
>>>> autoRefresh = false;
>>>> autoRefreshInterval = 0;
>>>> autoRefreshThread = null;
>>>> }
>>>>
>>>> /**
>>>> * Start auto refresh thread. The auto refresh thread
>>>> refreshes the remote
>>>> * stub if the stub file has changed on the disk.
>>>> */
>>>> private Thread startAutoRefreshThread() {
>>>> if ( autoRefreshInterval <= 0 || ! autoRefresh ) {
>>>> throw new IllegalArgumentException
>>>> (INVALID_AUTO_REFRESH_INTERVAL);
>>>> }
>>>>
>>>> final Thread theThread = new Thread(this);
>>>> theThread.start();
>>>>
>>>> return theThread;
>>>> }
>>>>
>>>> /**
>>>> * Stop auto refresh thread.
>>>> */
>>>> void stopAutoRefreshThread() {
>>>> autoRefresh = false;
>>>> }
>>>>
>>>> /**
>>>> * Auto refresh this rmi client.
>>>> */
>>>> public void run() {
>>>> while (autoRefresh) {
>>>> try {
>>>> Thread.sleep(autoRefreshInterval);
>>>> } catch (InterruptedException ie) {
>>>> warn(AUTO_REFRESH_INTR);
>>>> autoRefresh = false;
>>>> }
>>>> if (autoRefresh) {
>>>> checkServerStatus();
>>>> }
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Send specified event notification over admin channel
>>>> */
>>>> public AdminEventResult sendNotification(AdminEvent event) {
>>>> // Normal handling, send the event
>>>> boolean doRetry = true;
>>>> AdminEventResult result = null;
>>>> if (stub != null) {
>>>> try {
>>>> result = stub.sendNotification(key, event);
>>>> doRetry = false;
>>>> } catch (ServerException re) {
>>>> if ((re.detail != null) &&
>>>> (re.detail instanceof
>>>> java.lang.IllegalArgumentException
>>>> || re.detail instanceof
>>>> java.lang.SecurityException)) {
>>>> doRetry = false;
>>>> warn(EVENT_NOTIFY_ERROR);
>>>> debug(re.detail);
>>>> } else {
>>>> if (re.detail != null) {
>>>> debug(re.detail);
>>>> }
>>>> debug(re);
>>>> }
>>>> } catch (RemoteException re) {
>>>> if (re.detail != null) {
>>>> debug(re.detail);
>>>> }
>>>> debug(re);
>>>> }
>>>> }
>>>> if (doRetry) {
>>>> // Normal processing did not work, try to get stub
>>>> again and then
>>>> // attempt to send the event
>>>> boolean gotNew = checkServerStatus();
>>>> if (stub != null && gotNew) {
>>>> try {
>>>> result = stub.sendNotification(key, event);
>>>> } catch (RemoteException re) {
>>>> warn(EVENT_RENOTIFY_ERROR);
>>>> if (re.detail != null) {
>>>> debug(re.detail);
>>>> }
>>>> debug(re);
>>>> }
>>>> }
>>>> }
>>>> if (result == null) {
>>>> // Still couldn't communicate, set result appropriately
>>>> result = new AdminEventResult(event.getSequenceNumber
>>>> ());
>>>> result.setResultCode
>>>> (AdminEventResult.TRANSMISSION_ERROR);
>>>> if (stub == null) {
>>>> result.addMessage(event.getEffectiveDestination(),
>>>> "Remote Stub is null");
>>>> }
>>>> }
>>>> return result;
>>>> }
>>>>
>>>> /** Determines wheter the instance with given name is alive.
>>>> * Really speaking, checks whether the RMI channel is
>>>> responsive.
>>>> * The method returns immediately with the status without
>>>> any retries.
>>>> * @return boolean indicating whether the RMIServer Object
>>>> * that <code> this </code> server instance is alive.
>>>> */
>>>> public boolean isAlive() {
>>>> return isAlive(false);
>>>> }
>>>>
>>>> /**
>>>> * Determines whether the instance represented by this
>>>> object is alive.
>>>> * Unless the parameter refreshStub is true, the
>>>> responsiveness of
>>>> * instance is checked by using cached stub (if any) and if
>>>> there is no
>>>> * cached stub the method returns false.
>>>> * @param refreshStub if true, refresh remote stub if it has
>>>> changed
>>>> * @return true if the instance represented by <code>this</
>>>> code> object
>>>> * is responding, false otherwise.
>>>> */
>>>> public boolean isAlive(boolean refreshStub) {
>>>>
>>>> if (refreshStub) {
>>>> boolean gotNew = checkServerStatus();
>>>> }
>>>>
>>>> boolean isAlive = true;
>>>>
>>>> if (stub != null) {
>>>> try {
>>>> stub.pingServer(key);
>>>> }
>>>> catch(RemoteException re) {
>>>> debug(re);
>>>> isAlive = false;
>>>> }
>>>> }
>>>> else {
>>>> isAlive = false;
>>>> }
>>>> return ( isAlive );
>>>> }
>>>>
>>>> /**
>>>> * Get server instance status code. If the instance can not
>>>> be contacted
>>>> * over rmi channel then the method reports that instance is
>>>> not running.
>>>> * The return value of this method is one of the constants
>>>> <code>
>>>> * kInstanceStartingCode, kInstanceRunningCode,
>>>> kInstanceStoppingCode or
>>>> * kInstanceNotRunningCode</code> from the class <code>
>>>> * com.sun.enterprise.admin.common.Status</code>.
>>>> * @return an int denoting the status of server starting,
>>>> running, stopping
>>>> * or not running.
>>>> */
>>>> public int getInstanceStatusCode() {
>>>> boolean gotNew = checkServerStatus();
>>>> int statusCode = Status.kInstanceNotRunningCode;
>>>> if (stub != null) {
>>>> try {
>>>> statusCode = stub.getServerStatusCode(key);
>>>> } catch (RemoteException re) {
>>>> debug(CHANNEL_COMM_ERROR, stubFile.getName());
>>>> if (re.detail != null) {
>>>> trace(re.detail);
>>>> }
>>>> trace(re);
>>>> } catch (IllegalArgumentException iae) {
>>>> debug(CHANNEL_COMM_ERROR, stubFile.getName());
>>>> trace(iae);
>>>> // This means that the key did not match.
>>>> Attempt to read
>>>> // the key from the disk again to work around
>>>> the race
>>>> // condition when the file is read on the client
>>>> before the
>>>> // server has finished writing (and hence client
>>>> has partial
>>>> // key). Another read updates the shared key on
>>>> the client.
>>>> byte[] newKey = null;
>>>> try {
>>>> newKey = readSeed();
>>>> } catch (IOException ioe) {
>>>> debug(FILE_READ_ERROR, seedFile.getName());
>>>> trace(ioe);
>>>> }
>>>> if (newKey != null) {
>>>> key = newKey;
>>>> }
>>>> throw iae;
>>>> }
>>>> }
>>>> return statusCode;
>>>> }
>>>>
>>>> /**
>>>> * Get the port where the conflict occurs.
>>>> *
>>>> * @return A valid port number.0 If there is any error in
>>>> processing
>>>> */
>>>> public int getConflictedPort() {
>>>> int conflictedPort = 0;
>>>> boolean gotNew = checkServerStatus();
>>>> if (stub != null) {
>>>> try {
>>>> conflictedPort = stub.getConflictedPort(key);
>>>> } catch (RemoteException re) {
>>>> debug(CHANNEL_COMM_ERROR, stubFile.getName());
>>>> if (re.detail != null) {
>>>> trace(re.detail);
>>>> }
>>>> trace(re);
>>>> }
>>>> }
>>>> return conflictedPort;
>>>> }
>>>>
>>>> /**
>>>> * Triggers exit of the server VM. Server VM will client
>>>> * that got the conflicted port number calls this method.
>>>> */
>>>> public void triggerServerExit() {
>>>> boolean gotNew = checkServerStatus();
>>>> if (stub != null) {
>>>> try {
>>>> stub.triggerServerExit(key);
>>>> } catch (RemoteException re) {
>>>> debug(CHANNEL_COMM_ERROR, stubFile.getName());
>>>> if (re.detail != null) {
>>>> trace(re.detail);
>>>> }
>>>> trace(re);
>>>> }
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Is restart needed on the instance. The status is set by
>>>> admin server and
>>>> * instance just keeps track of it across admin server
>>>> restarts. If the
>>>> * instance has already restarted since admin server set the
>>>> status, the
>>>> * instance does not require restart (as expected).
>>>> * @return true if the instance requires restart, false
>>>> otherwise.
>>>> */
>>>> public boolean isRestartNeeded() {
>>>> boolean restartNeeded = false;
>>>> boolean gotNew = checkServerStatus();
>>>> if (stub != null) {
>>>> try {
>>>> restartNeeded = stub.isRestartNeeded(key);
>>>> } catch (RemoteException re) {
>>>> debug(CHANNEL_COMM_ERROR, stubFile.getName());
>>>> if (re.detail != null) {
>>>> trace(re.detail);
>>>> }
>>>> trace(re);
>>>> }
>>>> }
>>>> return restartNeeded;
>>>> }
>>>>
>>>> /**
>>>> * Set restart needed status for a server instance. If the
>>>> instance is not
>>>> * running or if there is an error in communicating, the
>>>> instance restart
>>>> * status will not be changed. The status set by this method
>>>> is preserved
>>>> * in the instance across admin server restarts.
>>>> * @param restartNeeded true if instance restart is needed,
>>>> false otherwise.
>>>> */
>>>> public void setRestartNeeded(boolean restartNeeded) {
>>>> boolean gotNew = checkServerStatus();
>>>> if (stub != null) {
>>>> try {
>>>> stub.setRestartNeeded(key, restartNeeded);
>>>> } catch (RemoteException re) {
>>>> debug(CHANNEL_COMM_ERROR, stubFile.getName());
>>>> if (re.detail != null) {
>>>> trace(re.detail);
>>>> }
>>>> trace(re);
>>>> }
>>>> }
>>>> }
>>>>
>>>> /**
>>>> * Check status of server stub file and refresh if needed.
>>>> */
>>>> private synchronized boolean checkServerStatus() {
>>>> boolean gotNew = false;
>>>> if (stubFile.exists()) {
>>>> long ts = stubFile.lastModified();
>>>> if (ts > stubFileTs) {
>>>> if (stubFile.canRead()) {
>>>> RemoteAdminChannel obj = readStub();
>>>> if (obj != null) {
>>>> gotNew = true;
>>>> stub = obj;
>>>> }
>>>> } else {
>>>> warn(FILE_READ_ERROR, stubFile.getName());
>>>> }
>>>> }
>>>> } else {
>>>> if (stub != null) {
>>>> stub = null;
>>>> }
>>>> }
>>>> return gotNew;
>>>> }
>>>>
>>>> /**
>>>> * Read stub from stub file
>>>> */
>>>> private RemoteAdminChannel readStub() {
>>>> RemoteAdminChannel obj = null;
>>>> FileInputStream fis = null;
>>>> try {
>>>> stubFileTs = stubFile.lastModified();
>>>> fis = new FileInputStream(stubFile);
>>>> ObjectInputStream ois = new ObjectInputStream(fis);
>>>> obj = (RemoteAdminChannel)ois.readObject();
>>>> } catch (IOException ioe) {
>>>> warn(CLIENT_INIT_ERROR);
>>>> debug(ioe);
>>>> } catch (ClassNotFoundException cnfe) {
>>>> warn(CLIENT_INIT_ERROR);
>>>> debug(cnfe);
>>>> } finally {
>>>> if (fis != null) {
>>>> try {
>>>> fis.close();
>>>> } catch (IOException ioe) {
>>>> }
>>>> }
>>>> }
>>>> try {
>>>> key = readSeed();
>>>> } catch (IOException ioe) {
>>>> warn(CLIENT_INIT_ERROR);
>>>> debug(ioe);
>>>> obj = null;
>>>> }
>>>> if (obj == null) {
>>>> stubFileTs = 0;
>>>> }
>>>> return obj;
>>>> }
>>>>
>>>> /**
>>>> * Read shared secret from file.
>>>> */
>>>> private byte[] readSeed() throws IOException {
>>>> byte[] seed = null;
>>>> if (seedFile.exists() && seedFile.canRead()) {
>>>> // Seed file is updated after creating stub file and
>>>> therefore
>>>> // it should only be read only if it has been
>>>> modified since stub
>>>> // file was modified. NOTE: This relies on the fact
>>>> that the
>>>> // server always (on every startup) writes seed file
>>>> after stubfile.
>>>> long seedFileTs = seedFile.lastModified();
>>>> if (seedFileTs >= stubFileTs) {
>>>> FileInputStream fis = null;
>>>> try {
>>>> fis = new FileInputStream(seedFile);
>>>> seed = new byte[AdminChannel.SEED_LENGTH];
>>>> fis.read(seed);
>>>> } catch (IOException ioe) {
>>>> warn(AdminChannel.KEY_READ_ERROR);
>>>> debug(ioe);
>>>> seed = null;
>>>> } finally {
>>>> if (fis != null) {
>>>> try {
>>>> fis.close();
>>>> } catch (IOException ioe) {
>>>> }
>>>> }
>>>> }
>>>> } else {
>>>> debug(SEED_FILE_OLDER,
>>>> new Long[] {new Long(seedFileTs), new
>>>> Long(stubFileTs)});
>>>> }
>>>> } else {
>>>> warn(AdminChannel.KEY_READ_ERROR);
>>>> debug(FILE_READ_ERROR, seedFile.getName());
>>>> }
>>>> if (seed == null) {
>>>> String msg = localStrings.getString
>>>> ( "admin.server.core.channel.unable_initializing_key", seedFile );
>>>> throw new IOException( msg );
>>>> }
>>>> return seed;
>>>> }
>>>>
>>>> /**
>>>> * Has the server instance restarted since specified
>>>> timestamp. If instance
>>>> * is not running, the method will return false. The return
>>>> value is
>>>> * accurate within the timespan as specified in
>>>> getClientRefreshInterval()
>>>> * of AdminChannel -- meaning that if the time period since
>>>> instance restart
>>>> * is less than the specified timespan then the method may
>>>> return false
>>>> * instead of true.
>>>> * @param ts Timestamp to check for
>>>> * @return true if the instance has restarted since
>>>> specified timestamp,
>>>> * false otherwise.
>>>> */
>>>> public boolean hasRestartedSince(long ts) {
>>>> return hasRestartedSince(ts, false);
>>>> }
>>>>
>>>> /**
>>>> * Has the server instance restarted since specified
>>>> timestamp. If instance
>>>> * is not running, the method will return false. If
>>>> refreshStub is true
>>>> * then the method will attempt to read newer stub (if any)
>>>> and will report
>>>> * status using that. If refreshStub is false then the stub
>>>> is not re-read
>>>> * and return value is dependent on the cached stub (if any).
>>>> * @param ts Timestamp to check for
>>>> * @param refreshStub if true, refresh remote stub if it has
>>>> changed
>>>> * @return true if the instance has restarted since
>>>> specified timestamp,
>>>> * false otherwise.
>>>> */
>>>> public boolean hasRestartedSince(long ts, boolean
>>>> refreshStub) {
>>>> if (refreshStub) {
>>>> boolean gotNew = checkServerStatus();
>>>> }
>>>> boolean restarted = false;
>>>> if (stubFile != null) {
>>>> if (stubFileTs > ts) {
>>>> restarted = true;
>>>> }
>>>> }
>>>> return restarted;
>>>> }
>>>>
>>>> //
>>>> // logger methods copied from AdminChannel
>>>> //
>>>>
>>>> static void trace(Throwable t) {
>>>> logger.log(Level.FINEST, t.getMessage(), t);
>>>> }
>>>>
>>>> static void warn(String s) {
>>>> logger.warning(s);
>>>> }
>>>>
>>>> static void warn(String msgkey, String obj1) {
>>>> logger.log(Level.WARNING, msgkey, obj1);
>>>> }
>>>>
>>>> static void debug(String s) {
>>>> logger.fine(s);
>>>> }
>>>>
>>>> static void debug(String msgkey, String obj1) {
>>>> logger.log(Level.FINE, msgkey, obj1);
>>>> }
>>>>
>>>> static void debug(String msgkey, Object[] objarr) {
>>>> logger.log(Level.FINE, msgkey, objarr);
>>>> }
>>>>
>>>> static void debug(Throwable t) {
>>>> logger.log(Level.FINE, t.getMessage(), t);
>>>> }
>>>>
>>>> // i18n StringManager
>>>> private static final StringManager localStrings =
>>>> StringManager.getManager( RMIClient.class );
>>>>
>>>> private static final String CLIENT_NULLARGS_ERRCODE =
>>>> "channel.client_nullargs";
>>>> private static final String CLIENT_NULLARGS_ERRMSG =
>>>> localStrings.getString
>>>> ( "admin.server.core.channel.attempt_initializing_channel_client_wi
>>>> th_null_arguments" );
>>>> private static final String CLIENT_INIT_ERROR =
>>>> "channel.client_init_error";
>>>> private static final String EVENT_NOTIFY_ERROR =
>>>> "channel.event_notify_error";
>>>> private static final String EVENT_RENOTIFY_ERROR =
>>>> "channel.event_renotify_error";
>>>> private static final String AUTO_REFRESH_INTR =
>>>> "channel.auto_refresh_intr";
>>>> private static final String CHANNEL_COMM_ERROR =
>>>> "channel.comm_error";
>>>> private static final String INVALID_AUTO_REFRESH_INTERVAL =
>>>> localStrings.getString(
>>>>
>>>> "admin.server.core.channel.invalid_auto_refresh_interval");
>>>>
>>>> static final String FILE_READ_ERROR =
>>>> "channel.file_read_error";
>>>> static final String SEED_FILE_OLDER =
>>>> "channel.seed_file_older";
>>>>
>>>> static final Logger logger = Logger.getLogger
>>>> (AdminConstants.kLoggerName);
>>>> }
>>>>
>>>>
>>>> -------------------------------------------------------------------
>>>> --
>>>> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net
>>>> For additional commands, e-mail: admin-help_at_glassfish.dev.java.net
>>>>
>>>
>>> --------------------------------------------------------------------
>>> -
>>> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net
>>> For additional commands, e-mail: admin-help_at_glassfish.dev.java.net
>>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net
>> For additional commands, e-mail: admin-help_at_glassfish.dev.java.net
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: admin-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: admin-help_at_glassfish.dev.java.net
>