FileDocCategorySizeDatePackage
RMIClient.javaAPI DocGlassfish v2 API21563Mon Jun 11 13:33:22 BST 2007com.sun.enterprise.admin.server.core.channel

RMIClient

public class RMIClient extends Object implements Runnable
RMI client is used to send admin channel messages over RMI.

Fields Summary
private File
stubFile
private File
seedFile
private long
stubFileTs
private byte[]
key
private RemoteAdminChannel
stub
private boolean
autoRefresh
private long
autoRefreshInterval
private Thread
autoRefreshThread
private static com.sun.enterprise.util.i18n.StringManager
localStrings
private static final String
CLIENT_NULLARGS_ERRCODE
private static final String
CLIENT_NULLARGS_ERRMSG
private static final String
CLIENT_INIT_ERROR
private static final String
EVENT_NOTIFY_ERROR
private static final String
EVENT_RENOTIFY_ERROR
private static final String
AUTO_REFRESH_INTR
private static final String
CHANNEL_COMM_ERROR
private static final String
INVALID_AUTO_REFRESH_INTERVAL
static final String
FILE_READ_ERROR
static final String
SEED_FILE_OLDER
static Logger
logger
Constructors Summary
RMIClient(String stubFile, String seedFile)
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 AdminChannel.getRMIClient() 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.


                                                                                       
        
        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();
        }
        if (AdminChannel.getClientAutoRefreshEnabled()) {
            startAutoRefreshThread(
                    AdminChannel.getClientAutoRefreshInterval());
        }
    
public RMIClient(boolean isDebug, String stubFile, String seedFile)
Constructor for local mode

        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();
        }
    
Methods Summary
private booleancheckServerStatus()
Check status of server stub file and refresh if needed.

        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;
    
static voiddebug(java.lang.String s)

        logger.fine(s);
    
static voiddebug(java.lang.String msgkey, java.lang.String obj1)

        logger.log(Level.FINE, msgkey, obj1);
    
static voiddebug(java.lang.String msgkey, java.lang.Object[] objarr)

        logger.log(Level.FINE, msgkey, objarr);
    
static voiddebug(java.lang.Throwable t)

        logger.log(Level.FINE, t.getMessage(), t);
    
public intgetConflictedPort()
Get the port where the conflict occurs.

return
A valid port number.0 If there is any error in processing

        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;
    
public intgetInstanceStatusCode()
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 kInstanceStartingCode, kInstanceRunningCode, kInstanceStoppingCode or kInstanceNotRunningCode from the class com.sun.enterprise.admin.common.Status.

return
an int denoting the status of server starting, running, stopping or not running.

        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;
    
public booleanhasRestartedSince(long ts)
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.

        return hasRestartedSince(ts, false);
    
public booleanhasRestartedSince(long ts, boolean refreshStub)
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.

        if (refreshStub) {
            boolean gotNew = checkServerStatus();
        }
        boolean restarted = false;
        if (stubFile != null) {
            if (stubFileTs > ts) {
                restarted = true;
            }
        }
        return restarted;
    
public booleanisAlive()
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 this server instance is alive.

        return isAlive(false);
    
public booleanisAlive(boolean refreshStub)
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 this object is responding, false otherwise.


        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 );
    
public booleanisRestartNeeded()
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.

        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;
    
private byte[]readSeed()
Read shared secret from file.

        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;
    
private RemoteAdminChannelreadStub()
Read stub from stub file

        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;
    
public voidrun()
Auto refresh this rmi client.

        while (autoRefresh) {
            try {
                Thread.sleep(autoRefreshInterval);
            } catch (InterruptedException ie) {
                warn(AUTO_REFRESH_INTR);
                autoRefresh = false;
            }
            if (autoRefresh) {
                checkServerStatus();
            }
        }
    
public com.sun.enterprise.admin.event.AdminEventResultsendNotification(com.sun.enterprise.admin.event.AdminEvent event)
Send specified event notification over admin channel

        // 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;
    
public voidsetRestartNeeded(boolean 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.

        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);
            }
        }
    
voidstartAutoRefreshThread(long interval)
Start auto refresh thread. The auto refresh thread refreshes the remote stub if the stub file has changed on the disk.

        if (interval <= 0) {
            throw new IllegalArgumentException(INVALID_AUTO_REFRESH_INTERVAL);
        }
        autoRefresh = true;
        autoRefreshInterval = interval;
        if (autoRefreshThread != null && autoRefreshThread.isAlive()) {
            return;
        } else {
            autoRefreshThread = new Thread(this);
            autoRefreshThread.start();
        }
    
voidstopAutoRefreshThread()
Stop auto refresh thread.

        autoRefresh = false;
    
static voidtrace(java.lang.Throwable t)

        logger.log(Level.FINEST, t.getMessage(), t);
    
public voidtriggerServerExit()
Triggers exit of the server VM. Server VM will client that got the conflicted port number calls this method.

        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);
            }
        }
    
static voidwarn(java.lang.String s)

        logger.warning(s);
    
static voidwarn(java.lang.String msgkey, java.lang.String obj1)

        logger.log(Level.WARNING, msgkey, obj1);