/*
* Copyright (C) 2013 Glencoe Software, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package ome.services.blitz.impl;
import java.util.NoSuchElementException;
import ome.api.ServiceInterface;
import ome.api.StatefulServiceInterface;
import ome.services.blitz.util.BlitzExecutor;
import ome.services.blitz.util.UnregisterServantMessage;
import ome.util.messages.InternalMessage;
import omero.ShutdownInProgress;
import omero.api.AMD_StatefulServiceInterface_close;
import omero.util.CloseableServant;
import omero.util.IceMapper;
import Ice.ObjectAdapterDeactivatedException;
/**
* Base class for all servants that must guarantee proper clean-up of held
* resources on close.
*
* @author Josh Moore, josh at glencoesoftware.com
* @since 4.4.9
*/
public abstract class AbstractCloseableAmdServant extends AbstractAmdServant
implements CloseableServant {
public AbstractCloseableAmdServant(ServiceInterface service, BlitzExecutor be) {
super(service, be);
}
public final void close(Ice.Current __current) {
final RuntimeException[] re = new RuntimeException[1];
AMD_StatefulServiceInterface_close cb =
new AMD_StatefulServiceInterface_close() {
public void ice_exception(Exception ex) {
if (ex instanceof RuntimeException) {
re[0] = (RuntimeException) ex;
} else {
re[0] = new RuntimeException(ex);
}
}
public void ice_response() {
// ok.
}
};
close_async(cb, __current);
if (re[0] != null) {
throw re[0];
}
}
/**
* {@link ome.tools.hibernate.SessionHandler} also
* specially catches close() calls, but cannot remove the servant
* from the {@link Ice.ObjectAdapter} and thereby prevent any
* further communication. Once the invocation is finished, though,
* it is possible to raise the message and have the servant
* cleaned up.
*
* @see <a href="http://trac.openmicroscopy.org.uk/ome/ticket/1855">ticket:1855</a>
*/
public final void close_async(AMD_StatefulServiceInterface_close __cb,
Ice.Current __current) {
Throwable t = null;
// First we call close on the object
try {
preClose(__current);
if (service instanceof StatefulServiceInterface) {
StatefulServiceInterface ss = (StatefulServiceInterface) service;
ss.close();
}
} catch (NoSuchElementException nsee) {
log.info("NoSuchElementException: Login is already gone");
t = nsee;
} catch (Throwable t1) {
log.error("Error on close, stage1", t1);
t = t1;
}
// Then we publish the close event
try {
InternalMessage msg = new UnregisterServantMessage(this, __current, holder);
ctx.publishMessage(msg);
} catch (ObjectAdapterDeactivatedException oade) {
log.warn("ObjectAdapter deactivated!");
ShutdownInProgress sip = new ShutdownInProgress();
IceMapper.fillServerError(sip, oade);
t = sip;
} catch (Throwable t2) {
log.error("Error on close, stage2", t2);
t = t2;
}
// Now we've finished that, let's return control to the user.
try {
if (t == null) {
__cb.ice_response();
} else {
__cb.ice_exception(new IceMapper().handleException(t, ctx));
}
} finally {
postClose(__current);
}
}
protected abstract void preClose(Ice.Current current) throws Throwable;
/**
* Should not throw any exceptions which should be detected by clients
* since it is called in a finally block after the client thread has been
* released.
*/
protected abstract void postClose(Ice.Current current);
}