Glacier2.Application Maven / Gradle / Ivy
//
// Copyright (c) ZeroC, Inc. All rights reserved.
//
package Glacier2;
/**
* An extension of Ice.Application that makes it easy to write
* Glacier2 applications.
*
* Applications must create a derived class that implements the
* {@link #createSession} and {@link #runWithSession} methods.
*
* 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 static class RestartSessionException extends Exception
{
}
/**
* Initializes an instance that calls 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.
**/
public
Application(Ice.SignalPolicy signalPolicy)
{
super(signalPolicy);
}
/**
* Creates a new Glacier2 session. A call to
* createSession
always precedes a call to
* runWithSession
. If Ice.LocalException
* is thrown from this method, the application is terminated.
*
* @return The Glacier2 session.
**/
abstract public Glacier2.SessionPrx
createSession();
/**
* Called once the communicator has been initialized and the Glacier2 session
* has been established. A derived class must implement runWithSession
,
* which is the application's starting method.
*
* @param args The argument vector for the application. Application
* scans the argument vector passed to main
for options that are
* specific to the Ice run time and removes them; therefore, the vector passed
* to run
is free from Ice-related options and contains only options
* and arguments that are application-specific.
*
* @return The runWithSession
method should return zero for successful
* termination, and non-zero otherwise. Application.main
returns the
* value returned by runWithSession
.
*
* @throws RestartSessionException If the session should be restarted.
**/
public abstract int
runWithSession(String[] args)
throws RestartSessionException;
/**
* Called when the session refresh thread 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. This method is called
* according to the Ice invocation dipsatch rules (in other words, it
* uses the same rules as an servant upcall or AMI callback).
**/
public void
sessionDestroyed()
{
}
/**
* Run should not be overridden for Glacier2.Application. Instead
* runWithSession
should be used.
*/
@Override
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. The exception produce an application restart
* when called from the Application main thread.
*
* @throws RestartSessionException This exception is always thrown.
**/
public static void
restart()
throws RestartSessionException
{
throw new RestartSessionException();
}
/**
* 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 static String
categoryForClient()
throws SessionNotExistException
{
if(_router == null)
{
throw new SessionNotExistException();
}
return _category;
}
/**
* Create a new Ice identity for callback objects with the given
* identity name field.
* @param name The identity name.
* @return The identity with the given name and a unique category.
* @throws SessionNotExistException No session exists.
**/
public static 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 static 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 static Ice.ObjectAdapter
objectAdapter()
throws SessionNotExistException
{
if(_router == null)
{
throw new SessionNotExistException();
}
synchronized(_mutex)
{
if(_adapter == null)
{
_adapter = communicator().createObjectAdapterWithRouter("", _router);
_adapter.activate();
}
}
return _adapter;
}
private class CloseCallbackI implements Ice.CloseCallback
{
@Override
public void closed(Ice.Connection con)
{
sessionDestroyed();
}
}
@Override
protected int
doMain(Ice.StringSeqHolder argHolder, Ice.InitializationData initData)
{
//
// Set the default properties for all Glacier2 applications.
//
initData.properties.setProperty("Ice.RetryIntervals", "-1");
boolean restart;
Ice.Holder ret = new Ice.Holder();
do
{
//
// A copy of the initialization data and the string array
// needs to be passed to doMainInternal, as these can be
// changed by the application.
//
Ice.InitializationData id = 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.Holder 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;
boolean sessionCreated = false;
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();
sessionCreated = true;
}
catch(Ice.LocalException ex)
{
Ice.Util.getProcessLogger().error(IceInternal.Ex.toString(ex));
status.value = 1;
}
if(sessionCreated)
{
int acmTimeout = 0;
try
{
acmTimeout = _router.getACMTimeout();
}
catch(Ice.OperationNotExistException ex)
{
}
if(acmTimeout <= 0)
{
acmTimeout = (int)_router.getSessionTimeout();
}
if(acmTimeout > 0)
{
Ice.Connection connection = _router.ice_getCachedConnection();
assert(connection != null);
connection.setACM(new Ice.IntOptional(acmTimeout),
null,
new Ice.Optional(Ice.ACMHeartbeat.HeartbeatAlways));
connection.setCloseCallback(new CloseCallbackI());
}
_category = _router.getCategoryForClient();
status.value = runWithSession(argHolder.value);
}
}
}
//
// We want to restart on those exceptions that indicate a
// break down in communications, but not those exceptions that
// indicate a programming logic error (i.e., 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:\n" + 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:\n" + 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(sessionCreated && _router != null)
{
try
{
_router.destroySession();
}
catch(Ice.ConnectionLostException ex)
{
//
// Expected if another thread invoked on an object from the session concurrently.
//
}
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)
{
_communicator.destroy();
_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;
_category = null;
return restart;
}
private static Ice.ObjectAdapter _adapter;
private static Glacier2.RouterPrx _router;
private static Glacier2.SessionPrx _session;
private static String _category;
}