summaryrefslogtreecommitdiff
path: root/java/src
diff options
context:
space:
mode:
authorJose <jose@zeroc.com>2009-10-02 02:23:52 +0200
committerJose <jose@zeroc.com>2009-10-02 02:23:52 +0200
commit1d9f29e281770ecdad4a245271f2b828bd64a32f (patch)
treeac083f28b06a444e484c24f8fcf1b12a36202c84 /java/src
parentUpdated demo README (diff)
downloadice-1d9f29e281770ecdad4a245271f2b828bd64a32f.tar.bz2
ice-1d9f29e281770ecdad4a245271f2b828bd64a32f.tar.xz
ice-1d9f29e281770ecdad4a245271f2b828bd64a32f.zip
3772. Recovering from Glacier2 / Ice router session failure.
Diffstat (limited to 'java/src')
-rw-r--r--java/src/Glacier2/Application.java552
-rw-r--r--java/src/Glacier2/SessionFactoryHelper.java355
-rw-r--r--java/src/Glacier2/SessionHelper.java496
-rw-r--r--java/src/Ice/Application.java29
-rw-r--r--java/src/IceInternal/Util.java16
5 files changed, 1430 insertions, 18 deletions
diff --git a/java/src/Glacier2/Application.java b/java/src/Glacier2/Application.java
new file mode 100644
index 00000000000..fd0812d9958
--- /dev/null
+++ b/java/src/Glacier2/Application.java
@@ -0,0 +1,552 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package Glacier2;
+
+/**
+ * An extension of Ice.Application that makes it easy to write
+ * Glacier2 applications.
+ *
+ * <p> Applications must create a derived class that implements the
+ * {@link #createSession} and {@link #runWithSession} methods.<p>
+ *
+ * The base class invokes {@link #createSession} to create a new
+ * Glacier2 session and then invokes {@link #runWithSession} in
+ * which the subclass performs its application logic. The base class
+ * automatically destroys the session when {@link #runWithSession}
+ * returns.
+ *
+ * If {@link #runWithSession} calls {@link #restart} or raises any of
+ * the exceptions Ice.ConnectionRefusedException,
+ * Ice.ConnectionLostException, Ice.UnknownLocalException,
+ * Ice.RequestFailedException, or Ice.TimeoutException, the base
+ * class destroys the current session and restarts the application
+ * with another call to {@link #createSession} followed by
+ * {@link #runWithSession}.
+ *
+ * The application can optionally override the {@link #sessionDestroyed}
+ * callback method if it needs to take action when connectivity with
+ * the Glacier2 router is lost.
+ *
+ * A program can contain only one instance of this class.
+ *
+ * @see Ice.Application
+ * @see Glacier2.Router
+ * @see Glacier2.Session
+ * @see Ice.Communicator
+ * @see Ice.Logger
+ * @see #runWithSession
+ **/
+public abstract class Application extends Ice.Application
+{
+ /**
+ * This exception is raised if the session should be restarted.
+ */
+ public class RestartSessionException extends Exception
+ {
+ }
+
+ /**
+ * Initializes an instance that calls {@link Communicator#shutdown} if
+ * a signal is received.
+ **/
+ public
+ Application()
+ {
+ }
+
+ /**
+ * Initializes an instance that handles signals according to the signal
+ * policy.
+ *
+ * @param signalPolicy Determines how to respond to signals.
+ *
+ * @see SignalPolicy
+ **/
+ public
+ Application(Ice.SignalPolicy signalPolicy)
+ {
+ super(signalPolicy);
+ }
+
+
+ /**
+ * Called once the communicator has been initialized and the Glacier2 session
+ * has been established. A derived class must implement <code>runWithSession</code>,
+ * which is the application's starting method.
+ *
+ * @param args The argument vector for the application. <code>Application</code>
+ * scans the argument vector passed to <code>main</code> for options that are
+ * specific to the Ice run time and removes them; therefore, the vector passed
+ * to <code>run</code> is free from Ice-related options and contains only options
+ * and arguments that are application-specific.
+ *
+ * @return The <code>runWithSession</code> method should return zero for successful
+ * termination, and non-zero otherwise. <code>Application.main</code> returns the
+ * value returned by <code>runWithSession</code>.
+ **/
+ public abstract int
+ runWithSession(String[] args)
+ throws RestartSessionException;
+
+ /**
+ * Run should not be overridden for Glacier2.Application. Instead
+ * <code>runWithSession</code> should be used.
+ */
+ final public int
+ run(String[] args)
+ {
+ // This shouldn't be called.
+ assert false;
+ return 0;
+ }
+
+ /**
+ * Called to restart the application's Glacier2 session. This
+ * method never returns.
+ *
+ * @throws RestartSessionException This exception is always thrown.
+ **/
+ public void
+ restart()
+ throws RestartSessionException
+ {
+ throw new RestartSessionException();
+ }
+
+ /**
+ * Creates a new Glacier2 session. A call to
+ * <code>createSession</code> always precedes a call to
+ * <code>runWithSession</code>. If <code>Ice.LocalException</code>
+ * is thrown from this method, the application is terminated.
+
+ * @return The Glacier2 session.
+ **/
+ abstract public Glacier2.SessionPrx
+ createSession();
+
+ /**
+ * Called when the base class detects that the session has been destroyed.
+ * A subclass can override this method to take action after the loss of
+ * connectivity with the Glacier2 router.
+ **/
+ public void
+ sessionDestroyed()
+ {
+ }
+
+ /**
+ * Returns the Glacier2 router proxy
+ * @return The router proxy.
+ **/
+ public static Glacier2.RouterPrx
+ router()
+ {
+ return _router;
+ }
+
+ /**
+ * Returns the Glacier2 session proxy
+ * @return The session proxy.
+ **/
+ public static Glacier2.SessionPrx
+ session()
+ {
+ return _session;
+ }
+
+ /**
+ * Returns the category to be used in the identities of all of the client's
+ * callback objects. Clients must use this category for the router to
+ * forward callback requests to the intended client.
+ * @return The category.
+ * @throws SessionNotExistException No session exists.
+ **/
+ public String
+ categoryForClient() throws SessionNotExistException
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+ return _router.getCategoryForClient();
+ }
+
+ /**
+ * Create a new Ice identity for callback objects with the given
+ * identity name field.
+ * @return The identity.
+ * @throws SessionNotExistException No session exists.
+ **/
+ public Ice.Identity
+ createCallbackIdentity(String name) throws SessionNotExistException
+ {
+ return new Ice.Identity(name, categoryForClient());
+ }
+
+ /**
+ * Adds a servant to the callback object adapter's Active Servant Map with a UUID.
+ * @param servant The servant to add.
+ * @return The proxy for the servant.
+ * @throws SessionNotExistException No session exists.
+ **/
+ public Ice.ObjectPrx
+ addWithUUID(Ice.Object servant) throws SessionNotExistException
+ {
+ return objectAdapter().add(servant, createCallbackIdentity(java.util.UUID.randomUUID().toString()));
+ }
+
+ /**
+ * Creates an object adapter for callback objects.
+ * @return The object adapter.
+ * @throws SessionNotExistException No session exists.
+ */
+ public synchronized Ice.ObjectAdapter
+ objectAdapter() throws SessionNotExistException
+ {
+ if(_adapter == null)
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+ // TODO: Depending on the resolution of
+ // http://bugzilla/bugzilla/show_bug.cgi?id=4264 the OA
+ // name could be an empty string.
+ String uuid = java.util.UUID.randomUUID().toString();
+ _adapter = communicator().createObjectAdapterWithRouter(uuid, _router);
+ _adapter.activate();
+ }
+ return _adapter;
+ }
+
+ private class SessionPingThread extends Thread
+ {
+ SessionPingThread(Glacier2.RouterPrx router, long period)
+ {
+ _router = router;
+ _period = period;
+ _done = false;
+ }
+
+ synchronized public void
+ run()
+ {
+ while(true)
+ {
+ _router.refreshSession_async(new Glacier2.AMI_Router_refreshSession()
+ {
+ public void
+ ice_response()
+ {
+ }
+
+ public void
+ ice_exception(Ice.LocalException ex)
+ {
+ // Here the session has gone. The thread
+ // terminates, and we notify the
+ // application that the session has been
+ // destroyed.
+ done();
+ sessionDestroyed();
+ }
+
+ public void
+ ice_exception(Ice.UserException ex)
+ {
+ // Here the session has gone. The thread
+ // terminates, and we notify the
+ // application that the session has been
+ // destroyed.
+ done();
+ sessionDestroyed();
+ }
+ });
+
+ if(!_done)
+ {
+ try
+ {
+ wait(_period);
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+
+ if(_done)
+ {
+ break;
+ }
+ }
+ }
+
+ public synchronized void
+ done()
+ {
+ if(!_done)
+ {
+ _done = true;
+ notify();
+ }
+ }
+
+ private final Glacier2.RouterPrx _router;
+ private final long _period;
+ private boolean _done = false;
+ }
+
+ protected int
+ doMain(Ice.StringSeqHolder argHolder, Ice.InitializationData initData)
+ {
+ // Set the default properties for all Glacier2 applications.
+ initData.properties.setProperty("Ice.ACM.Client", "0");
+ initData.properties.setProperty("Ice.RetryIntervals", "-1");
+
+ boolean restart;
+ Ice.IntHolder ret = new Ice.IntHolder();
+ do
+ {
+ // A copy of the initialization data and the string seq
+ // needs to be passed to doMainInternal, as these can be
+ // changed by the application.
+ Ice.InitializationData id = (Ice.InitializationData)initData.clone();
+ id.properties = id.properties._clone();
+ Ice.StringSeqHolder h = new Ice.StringSeqHolder();
+ h.value = argHolder.value.clone();
+
+ restart = doMain(h, id, ret);
+ }
+ while(restart);
+ return ret.value;
+ }
+
+ private boolean
+ doMain(Ice.StringSeqHolder argHolder, Ice.InitializationData initData, Ice.IntHolder status)
+ {
+ // Reset internal state variables from Ice.Application. The
+ // remainder are reset at the end of this method.
+ _callbackInProgress = false;
+ _destroyed = false;
+ _interrupted = false;
+
+ boolean restart = false;
+ status.value = 0;
+
+ SessionPingThread ping = null;
+ try
+ {
+ _communicator = Ice.Util.initialize(argHolder, initData);
+
+ _router = Glacier2.RouterPrxHelper.uncheckedCast(communicator().getDefaultRouter());
+ if(_router == null)
+ {
+ Ice.Util.getProcessLogger().error("no glacier2 router configured");
+ status.value = 1;
+ }
+ else
+ {
+ //
+ // The default is to destroy when a signal is received.
+ //
+ if(_signalPolicy == Ice.SignalPolicy.HandleSignals)
+ {
+ destroyOnInterrupt();
+ }
+
+ // If createSession throws, we're done.
+ try
+ {
+ _session = createSession();
+ _createdSession = true;
+ }
+ catch(Ice.LocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ status.value = 1;
+ }
+
+ if(_createdSession)
+ {
+ ping = new SessionPingThread(_router, (_router.getSessionTimeout() * 1000) / 2);
+ ping.start();
+ status.value = runWithSession(argHolder.value);
+ }
+ }
+ }
+ // We want to restart on those exceptions which indicate a
+ // break down in communications, but not those exceptions that
+ // indicate a programming logic error (ie: marshal, protocol
+ // failure, etc).
+ catch(RestartSessionException ex)
+ {
+ restart = true;
+ }
+ catch(Ice.ConnectionRefusedException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ restart = true;
+ }
+ catch(Ice.ConnectionLostException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ restart = true;
+ }
+ catch(Ice.UnknownLocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ restart = true;
+ }
+ catch(Ice.RequestFailedException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ restart = true;
+ }
+ catch(Ice.TimeoutException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ restart = true;
+ }
+ catch(Ice.LocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ status.value = 1;
+ }
+ catch(java.lang.Exception ex)
+ {
+ Ice.Util.getProcessLogger().error("unknown exception" + IceInternal.Ex.toString(ex));
+ status.value = 1;
+ }
+ catch(java.lang.Error err)
+ {
+ //
+ // We catch Error to avoid hangs in some non-fatal situations
+ //
+ Ice.Util.getProcessLogger().error("Java error " + IceInternal.Ex.toString(err));
+ status.value = 1;
+ }
+
+ // This clears any set interrupt.
+ if(_signalPolicy == Ice.SignalPolicy.HandleSignals)
+ {
+ defaultInterrupt();
+ }
+
+ synchronized(_mutex)
+ {
+ while(_callbackInProgress)
+ {
+ try
+ {
+ _mutex.wait();
+ }
+ catch(java.lang.InterruptedException ex)
+ {
+ }
+ }
+
+ if(_destroyed)
+ {
+ _communicator = null;
+ }
+ else
+ {
+ _destroyed = true;
+ //
+ // And _communicator != null, meaning will be
+ // destroyed next, _destroyed = true also ensures that
+ // any remaining callback won't do anything
+ //
+ }
+ }
+
+ if(ping != null)
+ {
+ ping.done();
+ while(true)
+ {
+ try
+ {
+ ping.join();
+ break;
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+ ping = null;
+ }
+
+ if(_createdSession && _router != null)
+ {
+ try
+ {
+ _router.destroySession();
+ }
+ catch(Ice.ConnectionLostException ex)
+ {
+ // Expected: the router closed the connection.
+ }
+ catch(Glacier2.SessionNotExistException ex)
+ {
+ // This can also occur.
+ }
+ catch(Throwable ex)
+ {
+ // Not expected.
+ Ice.Util.getProcessLogger().error("unexpected exception when destroying the session:\n" +
+ IceInternal.Ex.toString(ex));
+ }
+ _router = null;
+ }
+
+ if(_communicator != null)
+ {
+ try
+ {
+ _communicator.destroy();
+ }
+ catch(Ice.LocalException ex)
+ {
+ Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
+ status.value = 1;
+ }
+ catch(java.lang.Exception ex)
+ {
+ Ice.Util.getProcessLogger().error("unknown exception" + IceInternal.Ex.toString(ex));
+ status.value = 1;
+ }
+ _communicator = null;
+ }
+
+ synchronized(_mutex)
+ {
+ if(_appHook != null)
+ {
+ _appHook.done();
+ }
+ }
+
+ // Reset internal state. We cannot reset the Application state
+ // here, since _destroyed must remain true until we re-run
+ // this method.
+ _adapter = null;
+ _router = null;
+ _session = null;
+ _createdSession = false;
+
+ return restart;
+ }
+
+ private static Ice.ObjectAdapter _adapter;
+ private static Glacier2.RouterPrx _router;
+ private static Glacier2.SessionPrx _session;
+ private static boolean _createdSession = false;
+}
diff --git a/java/src/Glacier2/SessionFactoryHelper.java b/java/src/Glacier2/SessionFactoryHelper.java
new file mode 100644
index 00000000000..ac77170b677
--- /dev/null
+++ b/java/src/Glacier2/SessionFactoryHelper.java
@@ -0,0 +1,355 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+
+package Glacier2;
+
+/**
+ * A helper class for using Glacier2 with GUI applications.
+ *
+ * Applications should create a session factory for each Glacier2 router to which the application will
+ * connect. To connect with the Glacier2 router, call {@link SessionFactory#connect}. The callback object is
+ * notified of the various life cycle events. Once the session is torn down for whatever reason, the application
+ * can use the session factory to create another connection.
+ */
+public class SessionFactoryHelper
+{
+ /**
+ * A callback class to get notifications of status changes in the Glacier2 session.
+ * All callbacks on the <code>Callback</code> interface occur in the main swing thread.
+ */
+ public interface Callback
+ {
+ /**
+ * Notifies the application that the communicator was created.
+ *
+ * @param session The Glacier2 session.
+ */
+ void
+ createdCommunicator(SessionHelper session);
+
+ /**
+ * Notifies the application that the Glacier2 session has been established.
+ *
+ * @param session The established session.
+ */
+
+ void
+ connected(SessionHelper session)
+ throws SessionNotExistException;
+
+ /**
+ * Notifies the application that the Glacier2 session has been disconnected.
+ *
+ * @param session The disconnected session.
+ */
+ void
+ disconnected(SessionHelper session);
+
+ /**
+ * Notifies the application that the Glacier2 session establishment failed.
+ *
+ * @param session The session reporting the connection
+ * failure.
+ * @param ex The exception.
+ */
+ void
+ connectFailed(SessionHelper session, Throwable ex);
+ }
+
+ /**
+ * Creates a SessionFactory object.
+ *
+ * @param callback The callback object for notifications.
+ * @throws {@link Ice.InitializationException}
+ */
+ public
+ SessionFactoryHelper(Callback callback) throws Ice.InitializationException
+ {
+ initialize(callback, new Ice.InitializationData(), Ice.Util.createProperties());
+ }
+
+ /**
+ * Creates a SessionFactory object.
+ *
+ * @param initData The initialization data to use when creating the communicator.
+ * @param callback The callback object for notifications.
+ * @throws {@link Ice.InitializationException}
+ */
+ public
+ SessionFactoryHelper(Ice.InitializationData initData, Callback callback) throws Ice.InitializationException
+ {
+ initialize(callback, initData, initData.properties);
+ }
+
+ /**
+ * Creates a SessionFactory object.
+ *
+ * @param properties The properties to use when creating the communicator.
+ * @param callback The callback object for notifications.
+ * @throws {@link Ice.InitializationException}
+ */
+ public
+ SessionFactoryHelper(Ice.Properties properties, Callback callback) throws Ice.InitializationException
+ {
+ initialize(callback, new Ice.InitializationData(), properties);
+ }
+
+ private void
+ initialize(Callback callback, Ice.InitializationData initData, Ice.Properties properties)
+ throws Ice.InitializationException
+ {
+ if(callback == null)
+ {
+ throw new Ice.InitializationException("Attempt to create a SessionFactoryHelper with a null Callback" +
+ "argument");
+ }
+
+ if(initData == null)
+ {
+ throw new Ice.InitializationException("Attempt to create a SessionFactoryHelper with a null " +
+ "InitializationData argument");
+ }
+
+ if(properties == null)
+ {
+ throw new Ice.InitializationException("Attempt to create a SessionFactoryHelper with a null Properties " +
+ "argument");
+ }
+
+ _callback = callback;
+ _initData = initData;
+ _initData.properties = properties;
+
+ //
+ // Set default properties;
+ //
+ _initData.properties.setProperty("Ice.ACM.Client", "0");
+ _initData.properties.setProperty("Ice.RetryIntervals", "-1");
+ }
+
+ /**
+ * Set the router object identity.
+ *
+ * @return The Glacier2 router's identity.
+ */
+ synchronized public void
+ setRouterIdentity(Ice.Identity identity)
+ {
+ _identity = identity;
+ }
+
+ /**
+ * Returns the object identity of the Glacier2 router.
+ *
+ * @return The Glacier2 router's identity.
+ */
+ synchronized public Ice.Identity
+ getRouterIdentity()
+ {
+ return _identity;
+ }
+
+ /**
+ * Sets the host on which the Glacier2 router runs.
+ *
+ * @param hostname The host name (or IP address) of the router host.
+ */
+ synchronized public void
+ setRouterHost(String hostname)
+ {
+ _routerHost = hostname;
+ }
+
+ /**
+ * Returns the host on which the Glacier2 router runs.
+ *
+ * @return The Glacier2 router host.
+ */
+ synchronized public String
+ getRouterHost()
+ {
+ return _routerHost;
+ }
+
+ /**
+ * Sets whether to connect with the Glacier2 router securely.
+ *
+ * @param secure If <code>true</code>, the client connects to the router
+ * via SSL; otherwise, the client connects via TCP.
+ */
+ synchronized public void
+ setSecure(boolean secure)
+ {
+ _secure = secure;
+ }
+
+ /**
+ * Returns whether the session factory will establish a secure connection to the Glacier2 router.
+ *
+ * @return The secure flag.
+ */
+ synchronized public boolean
+ getSecure()
+ {
+ return _secure;
+ }
+
+ /**
+ * Sets the connect and connection timeout for the Glacier2 router.
+ *
+ * @param timeoutMillisecs The timeout in milliseconds. A zero
+ * or negative timeout value indicates that the router proxy has no associated timeout.
+ */
+ synchronized public void
+ setTimeout(int timeoutMillisecs)
+ {
+ _timeout = timeoutMillisecs;
+ }
+
+ /**
+ * Returns the connect and connection timeout associated with the Glacier2 router.
+ *
+ * @return The timeout.
+ */
+ synchronized public int
+ getTimeout()
+ {
+ return _timeout;
+ }
+
+ /**
+ * Sets the Glacier2 router port to connect to.
+ *
+ * @param port The port. If 0, then the default port (4063 for TCP or 4064 for SSL) is used.
+ */
+ synchronized public void
+ setPort(int port)
+ {
+ _port = port;
+ }
+
+ /**
+ * Returns the Glacier2 router port to connect to.
+ *
+ * @return The port.
+ */
+ synchronized public int
+ getPort()
+ {
+ return _port == 0 ? (_secure ? GLACIER2_TCP_PORT : GLACIER2_SSL_PORT) : _port;
+ }
+
+ /**
+ * Returns the initialization data used to initialize the communicator.
+ *
+ * @return The initialization data.
+ */
+ synchronized public Ice.InitializationData
+ getInitializationData()
+ {
+ return _initData;
+ }
+
+ /**
+ * Connects to the Glacier2 router using the associated SSL credentials.
+ *
+ * Once the connection is established, {@link Callback#connected} is called on the callback object;
+ * upon failure, {@link Callback#connectFailed} is called with the exception.
+ *
+ * @return The connected session.
+ */
+ synchronized public SessionHelper
+ connect()
+ {
+ SessionHelper session = new SessionHelper(_callback, createInitData());
+ session.connect();
+ return session;
+ }
+
+ /**
+ * Connect the Glacier2 session using user name and password credentials.
+ *
+ * Once the connection is established, {@link Callback#connected} is called on the callback object;
+ * upon failure, {@link Callback#connectFailed) is called with the exception.
+ *
+ * @param username The user name.
+ * @param password The password.
+ * @return The connected session.
+ */
+ synchronized public SessionHelper
+ connect(final String username, final String password)
+ {
+ SessionHelper session = new SessionHelper(_callback, createInitData());
+ session.connect(username, password);
+ return session;
+ }
+
+ private Ice.InitializationData
+ createInitData()
+ {
+ // Clone the initialization data and properties.
+ Ice.InitializationData initData = (Ice.InitializationData)_initData.clone();
+ initData.properties = initData.properties._clone();
+
+ if(initData.properties.getProperty("Ice.Default.Router").length() == 0)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("\"");
+ sb.append(Ice.Util.identityToString(_identity));
+ sb.append("\"");
+ sb.append(":");
+
+ if(_secure)
+ {
+ sb.append("ssl -p ");
+ }
+ else
+ {
+ sb.append("tcp -p ");
+ }
+
+ if(_port != 0)
+ {
+ sb.append(_port);
+ }
+ else
+ {
+ if(_secure)
+ {
+ sb.append(GLACIER2_SSL_PORT);
+ }
+ else
+ {
+ sb.append(GLACIER2_TCP_PORT);
+ }
+ }
+
+ sb.append(" -h ");
+ sb.append(_routerHost);
+ if(_timeout > 0)
+ {
+ sb.append(" -t ");
+ sb.append(_timeout);
+ }
+
+ initData.properties.setProperty("Ice.Default.Router", sb.toString());
+ }
+ return initData;
+ }
+
+ private Callback _callback;
+ private String _routerHost = "127.0.0.1";
+ private Ice.InitializationData _initData;
+ private Ice.Identity _identity = new Ice.Identity("router", "Glacier2");
+ private boolean _secure = true;
+ private int _port = 0;
+ private int _timeout = 10000;
+ private static final int GLACIER2_SSL_PORT = 4064;
+ private static final int GLACIER2_TCP_PORT = 4063;
+}
diff --git a/java/src/Glacier2/SessionHelper.java b/java/src/Glacier2/SessionHelper.java
new file mode 100644
index 00000000000..bea4a5dec15
--- /dev/null
+++ b/java/src/Glacier2/SessionHelper.java
@@ -0,0 +1,496 @@
+// **********************************************************************
+//
+// Copyright (c) 2003-2009 ZeroC, Inc. All rights reserved.
+//
+// This copy of Ice is licensed to you under the terms described in the
+// ICE_LICENSE file included in this distribution.
+//
+// **********************************************************************
+package Glacier2;
+
+import javax.swing.SwingUtilities;
+
+import Glacier2.SessionFactoryHelper.Callback;
+
+/**
+ * A helper class for using Glacier2 with GUI applications.
+ */
+public class SessionHelper
+{
+ private class SessionRefreshThread extends Thread
+ {
+ SessionRefreshThread(Glacier2.RouterPrx router, long period)
+ {
+ _router = router;
+ _period = period;
+ _done = false;
+ }
+
+ synchronized public void
+ run()
+ {
+ while(true)
+ {
+ _router.refreshSession_async(new Glacier2.AMI_Router_refreshSession()
+ {
+ public void ice_response()
+ {
+ }
+
+ public void ice_exception(Ice.LocalException ex)
+ {
+ done();
+ SessionHelper.this.destroy();
+ }
+
+ public void ice_exception(Ice.UserException ex)
+ {
+ done();
+ SessionHelper.this.destroy();
+ }
+ });
+ if(!_done)
+ {
+ try
+ {
+ wait(_period);
+ }
+ catch(InterruptedException ex)
+ {
+ }
+ }
+ if(_done)
+ {
+ break;
+ }
+ }
+ }
+
+ public synchronized void
+ done()
+ {
+ if(!_done)
+ {
+ _done = true;
+ notify();
+ }
+ }
+
+ private final Glacier2.RouterPrx _router;
+ private final long _period;
+ private boolean _done = false;
+ }
+
+ /**
+ * Creates a Glacier2 session.
+ *
+ * @param callback The callback for notifications about session establishment.
+ * @param initData The {@link Ice.InitializationData} for initializing the communicator.
+ */
+ public SessionHelper(SessionFactoryHelper.Callback callback, Ice.InitializationData initData)
+ {
+ _callback = callback;
+ _initData = initData;
+ }
+
+ /**
+ * Destroys the Glacier2 session.
+ *
+ * Once the session has been destroyed, {@link Callback.disconnected} is called on
+ * the associated callback object.
+ */
+ synchronized public void
+ destroy()
+ {
+ if(_destroy)
+ {
+ return;
+ }
+ _destroy = true;
+ if(_refreshThread == null)
+ {
+ // In this case a connecting session is being
+ // destroyed. The communicator and session will be
+ // destroyed when the connection establishment has
+ // completed.
+ return;
+ }
+ _session = null;
+
+ try
+ {
+ Runtime.getRuntime().removeShutdownHook(_shutdownHook);
+ }
+ catch(IllegalStateException ex)
+ {
+ // Ignore
+ }
+ catch(SecurityException ex)
+ {
+ // Ignore
+ }
+
+ // Run the destroyInternal in a thread. This is because it
+ // destroyInternal makes remote invocations.
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ destroyInternal();
+ }
+ }).start();
+ }
+
+ /**
+ * Returns the session's communicator object.
+ * @return The communicator.
+ */
+ synchronized public Ice.Communicator
+ communicator()
+ {
+ return _communicator;
+ }
+
+ /**
+ * Returns the category to be used in the identities of all of the client's
+ * callback objects. Clients must use this category for the router to
+ * forward callback requests to the intended client.
+ * @return The category.
+ * @throws SessionNotExistException No session exists.
+ **/
+ synchronized public String
+ categoryForClient()
+ throws SessionNotExistException
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+
+ return _router.getCategoryForClient();
+ }
+
+ /**
+ * Adds a servant to the callback object adapter's Active Servant Map with a UUID.
+ * @param servant The servant to add.
+ * @return The proxy for the servant.
+ * @throws SessionNotExistException No session exists.
+ **/
+ public synchronized Ice.ObjectPrx
+ addWithUUID(Ice.Object servant)
+ throws SessionNotExistException
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+ return internalObjectAdapter().add(servant, new Ice.Identity(java.util.UUID.randomUUID().toString(),
+ _router.getCategoryForClient()));
+ }
+
+ /**
+ * Returns the Glacier2 session proxy. If the session hasn't been established yet,
+ * or the session has already been destroyed, throws SessionNotExistException.
+ * @return The session proxy, or throws SessionNotExistException if no session exists.
+ * @throws SessionNotExistException No session exists.
+ */
+ synchronized public Glacier2.SessionPrx
+ session()
+ throws SessionNotExistException
+ {
+ if(_session == null)
+ {
+ throw new SessionNotExistException();
+ }
+
+ return _session;
+ }
+
+ /**
+ * Returns true if there is an active session, otherwise returns false.
+ * @return <code>true</code>if session exists or false if no session exists.
+ */
+ public boolean
+ isConnected()
+ {
+ synchronized(this)
+ {
+ return _connected;
+ }
+ }
+
+ /**
+ * Creates an object adapter for callback objects.
+ * @return The object adapter.
+ * @throws SessionNotExistException No session exists.
+ */
+ synchronized public Ice.ObjectAdapter
+ objectAdapter()
+ throws SessionNotExistException
+ {
+ return internalObjectAdapter();
+ }
+
+ // Only call this method when the calling thread owns the lock
+ private Ice.ObjectAdapter
+ internalObjectAdapter()
+ throws SessionNotExistException
+ {
+ if(_router == null)
+ {
+ throw new SessionNotExistException();
+ }
+ if(_adapter == null)
+ {
+ // TODO: Depending on the resolution of
+ // http://bugzilla/bugzilla/show_bug.cgi?id=4264 the OA
+ // name could be an empty string.
+ _adapter = _communicator.createObjectAdapterWithRouter(java.util.UUID.randomUUID().toString(), _router);
+ _adapter.activate();
+ }
+ return _adapter;
+ }
+
+ private interface ConnectStrategy
+ {
+ Glacier2.SessionPrx
+ connect(Glacier2.RouterPrx router)
+ throws CannotCreateSessionException, PermissionDeniedException;
+ }
+
+ /**
+ * Connects to the Glacier2 router using the associated SSL credentials.
+ *
+ * Once the connection is established, {@link Callback#connected} is called on the callback object;
+ * upon failure, {@link Callback#exception} is called with the exception.
+ */
+ synchronized protected void
+ connect()
+ {
+ connectImpl(new ConnectStrategy()
+ {
+ public SessionPrx connect(RouterPrx router)
+ throws CannotCreateSessionException, PermissionDeniedException
+ {
+ return router.createSessionFromSecureConnection();
+ }
+ });
+ }
+
+ /**
+ * Connects a Glacier2 session using user name and password credentials.
+ *
+ * Once the connection is established, {@link Callback#connected} is called on the callback object;
+ * upon failure {@link Callback.exception} is called with the exception.
+ *
+ * @param username The user name.
+ * @param password The password.
+ */
+ synchronized protected void
+ connect(final String username, final String password)
+ {
+ connectImpl(new ConnectStrategy()
+ {
+ public SessionPrx connect(RouterPrx router)
+ throws CannotCreateSessionException, PermissionDeniedException
+ {
+ return router.createSession(username, password);
+ }
+ });
+ }
+
+ synchronized private void
+ connected(RouterPrx router, SessionPrx session)
+ {
+ _router = router;
+
+ if(_destroy)
+ {
+ destroyInternal();
+ return;
+ }
+
+ // Assign the session after _destroy is checked.
+ _session = session;
+ _connected = true;
+
+ assert _refreshThread == null;
+ _refreshThread = new SessionRefreshThread(_router, (_router.getSessionTimeout() * 1000)/2);
+ _refreshThread.start();
+
+ _shutdownHook = new Thread("Shutdown hook")
+ {
+ public void run()
+ {
+ SessionHelper.this.destroy();
+ }
+ };
+
+ try
+ {
+ Runtime.getRuntime().addShutdownHook(_shutdownHook);
+ }
+ catch(IllegalStateException e)
+ {
+ //
+ // Shutdown in progress, ignored
+ //
+ }
+ catch(SecurityException ex)
+ {
+ // Ignore. Unsigned applets cannot registered shutdown
+ // hooks.
+ }
+
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ _callback.connected(SessionHelper.this);
+ }
+ catch(SessionNotExistException ex)
+ {
+ SessionHelper.this.destroy();
+ }
+ }
+ });
+ }
+
+ synchronized private void
+ destroyInternal()
+ {
+ assert _destroy;
+
+ try
+ {
+ _router.destroySession();
+ }
+ catch(Ice.ConnectionLostException e)
+ {
+ // Expected
+ }
+ catch(SessionNotExistException e)
+ {
+ // This can also occur.
+ }
+ catch(Throwable e)
+ {
+ // Not expected.
+ _communicator.getLogger().warning("SessionHelper: unexpected exception when destroying the session:\n" + e);
+ }
+ _router = null;
+ _connected = false;
+
+ if(_refreshThread != null)
+ {
+ _refreshThread.done();
+ while(true)
+ {
+ try
+ {
+ _refreshThread.join();
+ break;
+ }
+ catch(InterruptedException e)
+ {
+ }
+ }
+ _refreshThread = null;
+ }
+
+ try
+ {
+ _communicator.destroy();
+ }
+ catch(Throwable ex)
+ {
+ }
+ _communicator = null;
+
+ // Notify the callback that the session is gone.
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ _callback.disconnected(SessionHelper.this);
+ }
+ });
+ }
+
+ private void
+ connectImpl(final ConnectStrategy factory)
+ {
+ assert !_destroy;
+
+ try
+ {
+ _communicator = Ice.Util.initialize(_initData);
+ }
+ catch(final Ice.LocalException ex)
+ {
+ _destroy = true;
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ _callback.connectFailed(SessionHelper.this, ex);
+ }
+ });
+ return;
+ }
+
+ new Thread(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ SwingUtilities.invokeAndWait(new Runnable()
+ {
+ public void run()
+ {
+ _callback.createdCommunicator(SessionHelper.this);
+ }
+ });
+
+ Glacier2.RouterPrx routerPrx = Glacier2.RouterPrxHelper.uncheckedCast(
+ _communicator.getDefaultRouter());
+ Glacier2.SessionPrx session = factory.connect(routerPrx);
+ connected(routerPrx, session);
+ }
+ catch (final Exception ex)
+ {
+ try
+ {
+ _communicator.destroy();
+ }
+ catch(Throwable ex1)
+ {
+ }
+
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ _callback.connectFailed(SessionHelper.this, ex);
+ }
+ });
+ }
+ }
+ }).start();
+ }
+
+ private Ice.InitializationData _initData;
+ private Ice.Communicator _communicator;
+ private Ice.ObjectAdapter _adapter;
+ private Glacier2.RouterPrx _router;
+ private Glacier2.SessionPrx _session;
+
+ private SessionRefreshThread _refreshThread;
+ private SessionFactoryHelper.Callback _callback;
+ private boolean _destroy = false;
+ private boolean _connected = false;
+ private Thread _shutdownHook;
+}
diff --git a/java/src/Ice/Application.java b/java/src/Ice/Application.java
index 01b42196f8c..6bf0697681c 100644
--- a/java/src/Ice/Application.java
+++ b/java/src/Ice/Application.java
@@ -177,6 +177,12 @@ public abstract class Application
Util.setProcessLogger(new LoggerI(initData.properties.getProperty("Ice.ProgramName"), ""));
}
+ return doMain(argHolder, initData);
+ }
+
+ protected int
+ doMain(StringSeqHolder argHolder, Ice.InitializationData initData)
+ {
int status = 0;
try
@@ -427,7 +433,7 @@ public abstract class Application
}
/**
- * Clears any shutdownn hooks, including any hook established with {@link #destroyOnInterrupt}code> or
+ * Clears any shutdown hooks, including any hook established with {@link #destroyOnInterrupt}code> or
* {@link #shutdownOnInterrupt}.
**/
public static void
@@ -524,9 +530,10 @@ public abstract class Application
}
}
- static class AppHook extends Thread
+ // For use by Glacier2.Application
+ static public class AppHook extends Thread
{
- void
+ public void
done()
{
synchronized(_doneMutex)
@@ -642,12 +649,12 @@ public abstract class Application
private Thread _hook;
}
- private static String _appName;
- private static Communicator _communicator;
- private static AppHook _appHook;
- private static java.lang.Object _mutex = new java.lang.Object();
- private static boolean _callbackInProgress = false;
- private static boolean _destroyed = false;
- private static boolean _interrupted = false;
- private static SignalPolicy _signalPolicy = SignalPolicy.HandleSignals;
+ protected static String _appName;
+ protected static Communicator _communicator;
+ protected static AppHook _appHook;
+ protected static java.lang.Object _mutex = new java.lang.Object();
+ protected static boolean _callbackInProgress = false;
+ protected static boolean _destroyed = false;
+ protected static boolean _interrupted = false;
+ protected static SignalPolicy _signalPolicy = SignalPolicy.HandleSignals;
}
diff --git a/java/src/IceInternal/Util.java b/java/src/IceInternal/Util.java
index a9eebf126d2..17c53bfa3e6 100644
--- a/java/src/IceInternal/Util.java
+++ b/java/src/IceInternal/Util.java
@@ -138,14 +138,16 @@ public final class Util
loadClass(String className, ClassLoader cl)
throws LinkageError
{
- assert(cl != null);
- try
- {
- return cl.loadClass(className);
- }
- catch(ClassNotFoundException ex)
+ if(cl != null)
{
- // Ignore
+ try
+ {
+ return cl.loadClass(className);
+ }
+ catch(ClassNotFoundException ex)
+ {
+ // Ignore
+ }
}
return null;