/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2003 Danet GmbH (www.danet.de), GS-AN.
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: StandardWorkflowService.java 2930 2009-02-16 16:20:07Z drmlipp $
*
* $Log$
* Revision 1.14 2007/10/07 18:40:10 mlipp
* Removed superfluous imports.
*
* Revision 1.13 2007/02/27 14:34:20 drmlipp
* Some refactoring to reduce cyclic dependencies.
*
* Revision 1.12 2007/02/21 21:32:29 mlipp
* Using pooled JMS connections when in EJB now.
*
* Revision 1.11 2007/02/17 21:22:56 mlipp
* Improved service caching and topic connection handling.
*
* Revision 1.10 2007/02/16 21:43:23 mlipp
* Improved.
*
* Revision 1.9 2007/02/15 14:28:29 drmlipp
* Even more improvements.
*
* Revision 1.8 2007/02/15 14:09:45 drmlipp
* Improved resource releasing.
*
* Revision 1.7 2007/02/15 13:52:37 drmlipp
* Fixed channel release problem.
*
* Revision 1.6 2006/09/29 12:32:09 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.5 2006/09/21 14:20:42 drmlipp
* New method for retrieving current user.
*
* Revision 1.4 2005/08/17 21:22:20 mlipp
* Removed deprecated method (as announced in 1.3).
*
* Revision 1.3 2005/08/17 21:15:31 mlipp
* Synchronized with 1.3.1p3.
*
* Revision 1.1.1.1.6.3 2005/08/17 20:39:12 drmlipp
* Removed usage of RAS on client side.
*
* Revision 1.2 2005/04/08 11:28:05 drmlipp
* Merged changes from 1.3 branch up to 1.3p6.
*
* Revision 1.1.1.1.6.2 2005/04/07 12:13:03 drmlipp
* Added event subscriber with filter.
*
* Revision 1.1.1.1.6.1 2005/04/06 15:42:06 drmlipp
* Added additional support for accessing the event queue to
* WorkflowService.
*
* Revision 1.1.1.1 2004/08/18 15:17:38 drmlipp
* Update to 1.2
*
* Revision 1.5 2004/07/11 19:56:51 lipp
* Adapted to JOnAS 4.1.2 naming scheme.
*
* Revision 1.4 2004/07/08 14:42:30 lipp
* Providing support for separated connection factories.
*
* Revision 1.3 2004/07/06 11:45:20 lipp
* Asure usability in various application servers.
*
* Revision 1.2 2004/06/14 19:37:20 lipp
* Fixed assignment functions and cleaned up assignment related
* interfaces.
*
* Revision 1.1 2004/02/21 21:31:00 lipp
* Some more refactoring to resolve cyclic dependencies.
*
* Revision 1.28 2004/02/12 13:10:38 lipp
* Renamed openChannel to getChannel (channels have no open state).
*
* Revision 1.27 2004/01/30 14:36:30 lipp
* Partial implementation of message receipt.
*
* Revision 1.26 2004/01/28 16:11:38 lipp
* Re-implementation of chabacc, Sender working.
*
* Revision 1.25 2004/01/23 12:49:26 lipp
* Fixes to WorkflowService[Factory] implementation/documentation.
*
* Revision 1.24 2004/01/22 16:10:50 lipp
* Channel message queue not available yet.
*
* Revision 1.23 2004/01/22 15:06:09 lipp
* Clarified serializability of workflow service.
*
* Revision 1.22 2003/11/21 14:53:50 lipp
* Create topic connection on client side, support initial context
* override.
*
* Revision 1.21 2003/10/06 15:20:27 lipp
* Made doFinish available in WorkflowService.
*
* Revision 1.20 2003/06/27 08:51:45 lipp
* Fixed copyright/license information.
*
* Revision 1.19 2003/06/01 20:58:50 lipp
* Moved toSAX to batch.
*
* Revision 1.18 2003/05/02 15:28:29 lipp
* Resolved some more package dependencies.
*
* Revision 1.17 2003/05/02 14:55:58 lipp
* Resolved some more package dependencies.
*
* Revision 1.16 2003/04/26 16:11:14 lipp
* Moved some classes to reduce package dependencies.
*
* Revision 1.15 2003/04/22 16:35:25 lipp
* Made SAXEventBuffer outer class.
*
* Revision 1.14 2003/03/31 16:50:28 huaiyang
* Logging using common-logging.
*
* Revision 1.13 2003/02/25 17:08:05 lipp
* Reorganized requester implementation.
*
* Revision 1.12 2003/02/11 08:50:41 lipp
* Updated comment.
*
* Revision 1.11 2003/02/07 15:56:19 lipp
* Implemented Requester notifications.
*
* Revision 1.10 2003/02/06 12:47:14 lipp
* Implemented Requester (no event handling yet).
*
* Revision 1.9 2003/02/05 15:57:06 lipp
* Replaced DummyRequester with DefaultRequester.
*
* Revision 1.8 2002/12/19 21:37:42 lipp
* Reorganized interfaces.
*
* Revision 1.7 2002/12/19 16:23:46 lipp
* Resolved illegal dependency between apis and danet.an.util.
*
* Revision 1.6 2002/12/10 11:21:05 lipp
* Added batch processing as "generic DTO".
*
* Revision 1.5 2002/11/22 09:56:15 lipp
* Clarified usage of the danet utility bean for user preferences.
*
* Revision 1.4 2002/09/19 14:37:37 lipp
* Using WorkflowService.release now and optimized process definition
* storage.
*
* Revision 1.3 2002/09/18 21:26:51 lipp
* Removed SAXFacade (integrated with WorkflowEngine).
*
* Revision 1.2 2002/09/18 20:48:21 lipp
* Cleanly separated workflow engine and service.
*
* Revision 1.1 2002/09/18 14:29:44 lipp
* Partial workflow service implementation added.
*
*/
package de.danet.an.workflow.ejbs.client;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.rmi.RemoteException;
import java.security.Principal;
import javax.jms.ConnectionConsumer;
import javax.jms.ConnectionFactory;
import javax.jms.ConnectionMetaData;
import javax.jms.Destination;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
import javax.jms.ServerSessionPool;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
import javax.naming.Context;
import javax.naming.NamingException;
import de.danet.an.util.EJBUtil;
import de.danet.an.util.logging.RequestLog;
import de.danet.an.workflow.omgcore.CannotCompleteException;
import de.danet.an.workflow.omgcore.InvalidDataException;
import de.danet.an.workflow.omgcore.InvalidPerformerException;
import de.danet.an.workflow.omgcore.ProcessData;
import de.danet.an.workflow.omgcore.WfActivity;
import de.danet.an.workflow.omgcore.WfAuditEvent;
import de.danet.an.workflow.omgcore.WfAuditHandler;
import de.danet.an.workflow.omgcore.WfObject;
import de.danet.an.workflow.omgcore.WfProcess;
import de.danet.an.workflow.omgcore.WfRequester;
import de.danet.an.workflow.omgcore.WfResource;
import de.danet.an.workflow.api.Batch;
import de.danet.an.workflow.api.Channel;
import de.danet.an.workflow.api.Configuration;
import de.danet.an.workflow.api.EventSubscriber;
import de.danet.an.workflow.api.InvalidKeyException;
import de.danet.an.workflow.api.Process;
import de.danet.an.workflow.api.ProcessDefinitionDirectory;
import de.danet.an.workflow.api.ProcessDirectory;
import de.danet.an.workflow.api.WorkflowService;
import de.danet.an.workflow.apix.ExtProcessDirectory;
import de.danet.an.workflow.ejbs.WorkflowEngine;
/**
* This class provides the implementation of
* {@link WorkflowService <code>WorkflowService</code>}.<P>
*
* If loglevel is <code>DEBUG</code>, every event subscriber created
* with {@link #createEventSubscriber
* <code>createEventReceiver</code>} logs the received events.
*
* @author <a href="mailto:lipp@danet.de"></a>
* @version $Revision: 2930 $
*/
public class StandardWorkflowService
implements WorkflowService, WfAuditHandler {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog
(StandardWorkflowService.class);
private Map serviceProperties = null;
private Context initialContext = null;
private Boolean jmsConnectionReusable = null;
private TopicConnectionFactory topConFacCache = null;
private TopicConnection topConUnwrappedCache = null;
private TopicConnection topConCache = null;
private Thread connectionCleanupThread = null;
private Topic eventService = null;
private Topic channelMessageOutTopic = null;
private EventSubscriber reqEvtRec = null;
private Map reqsByProcKey = null;
private Map procKeysByReq = null;
private Collection ignoredProcs = null;
private ReferenceQueue reqRefQueue = null;
private Thread reqRefCleaner = null;
private WorkflowEngine engine = null;
/**
* Creates an instance of <code>StandardWorkflowService</code>
* with all attributes initialized to default values.
*
* @param props the service properties
* @param ic the initial context to be used for lookup of server
* resources
* @param e the workflow engine
*/
public StandardWorkflowService (Map props, Context ic, WorkflowEngine e) {
serviceProperties = props;
initialContext = ic;
engine = e;
}
/**
* Return the underlying workflow engine. Only for internal use.
* @return the engine
*/
public WorkflowEngine engine() {
return engine;
}
private void initJmsSetup ()
throws RemoteException, JMSException {
if (topConFacCache != null) {
return;
}
Object[] esd = engine.eventServiceData ();
try {
// This is a hack, but if anybody knowns a better way to
// adapt to the application server used, please tell
// me. This will eventually go away when JBoss gets a
// client container, as we have application server
// specific binding on the client side then.
String conFacName = (String)esd[0];
String topicConFacName = (String)esd[2];
ConnectionFactory jbossInternalConFac = null;
try {
jbossInternalConFac = (ConnectionFactory)
initialContext.lookup ("java:/JmsXA");
} catch (NamingException e) {
// deliberately ignored
}
if (jbossInternalConFac == null) {
try {
jbossInternalConFac = (ConnectionFactory)
initialContext.lookup ("java:XAConnectionFactory");
} catch (NamingException e) {
// deliberately ignored
}
}
// Comparison to "null" is workaround for JOnAS bug #300555
if (jbossInternalConFac != null) {
topConFacCache = (TopicConnectionFactory)jbossInternalConFac;
} else if (conFacName != null && !conFacName.equals ("null")) {
// Use this if your AS provides a factory that
// implements both Queue- and TopicConnectionFactory
topConFacCache = (TopicConnectionFactory)
initialContext.lookup (conFacName);
} else {
if (topicConFacName == null
|| topicConFacName.equals ("null")) {
if (engine.getClass().getName().startsWith
("de.danet.an.workflow.ejbs.JOnASWorkflowEngine")) {
topicConFacName = "JTCF";
} else {
// popular default
topicConFacName = "ConnectionFactory";
}
}
topConFacCache = (TopicConnectionFactory)
initialContext.lookup(topicConFacName);
}
eventService = (Topic)initialContext.lookup ((String)esd[3]);
channelMessageOutTopic = (Topic)
initialContext.lookup ((String)esd[4]);
} catch (NamingException e) {
logger.error (e.getMessage (), e);
throw new IllegalStateException (e.getMessage ());
}
}
/**
* Return a started topic connection.
* @return the connection
* @throws RemoteException if a system-level error occurs
* @throws JMSException if the connection cannot be created
*/
TopicConnection topicConnection()
throws RemoteException, JMSException {
synchronized (this) {
if (topConCache != null) {
return topConCache;
}
if (jmsConnectionReusable == null) {
initJmsSetup();
// Crude, but currently the only known way to find out
// whether we're running in server or client container.
// And we need to know because of J2EE 1.4 spec, J2EE.6.6.
TopicConnection topCon
= topConFacCache.createTopicConnection();
topCon.start ();
jmsConnectionReusable = Boolean.FALSE;
TopicSession ts1 = null;
TopicSession ts2 = null;
try {
ts1 = topCon.createTopicSession
(false, Session.AUTO_ACKNOWLEDGE);
ts2 = topCon.createTopicSession
(false, Session.AUTO_ACKNOWLEDGE);
jmsConnectionReusable = Boolean.TRUE;
} catch (JMSException e) {
// the created topic connection may still be handed out
return topCon;
} finally {
if (ts1 != null) {
ts1.close();
}
if (ts2 != null) {
ts2.close();
}
}
topConUnwrappedCache = topCon;
topConCache = new TopicConnectionWrapper (topCon);
connectionCleanupThread = new Thread () {
public void run () {
if (topConUnwrappedCache != null) {
try {
topConUnwrappedCache.close ();
} catch (JMSException e) {
logger.warn ("Cannot close - ignored: "
+ e.getMessage(), e);
}
topConCache = null;
topConUnwrappedCache = null;
}
}
};
Runtime.getRuntime().addShutdownHook (connectionCleanupThread);
return topConCache;
}
}
TopicConnection topCon = ((TopicConnectionFactory)topConFacCache)
.createTopicConnection();
topCon.start ();
return topCon;
}
private class EventSubscriberImpl implements EventSubscriber {
private TopicConnection connection;
private TopicSession session;
private TopicSubscriber subs;
public EventSubscriberImpl (String processKey, String eventTypes)
throws IOException {
try {
initJmsSetup();
connection = topicConnection();
session = connection.createTopicSession
(false, Session.AUTO_ACKNOWLEDGE);
if (processKey == null && eventTypes == null) {
subs = session.createSubscriber (eventService);
return;
}
StringBuffer filter = new StringBuffer ();
if (processKey != null) {
filter.append ("processKey = '" + processKey + "'");
}
if (eventTypes != null) {
if (filter.length() > 0) {
filter.append (" AND ");
}
filter.append ("(");
StringTokenizer st
= new StringTokenizer (eventTypes, " \t\n\r\f,;");
boolean first = true;
while (st.hasMoreTokens ()) {
if (first) {
first = false;
} else {
filter.append (" OR ");
}
filter.append ("(eventType = '");
filter.append (st.nextToken());
filter.append ("')");
}
if (first) {
throw new IllegalArgumentException
("\"" + eventTypes + "\" is not a"
+ " valid list of event types.");
}
filter.append (")");
}
subs = session.createSubscriber
(eventService, filter.toString (), true);
if (logger.isDebugEnabled ()) {
logger.debug ("Created " + this + " with filter \""
+ filter.toString () + "\"");
}
} catch (JMSException e) {
throw (IOException)
(new IOException (e.getMessage())).initCause (e);
}
}
public void close () {
try {
subs.close ();
session.close ();
connection.close ();
} catch (JMSException e) {
logger.error ("Closing topic: " + e.getMessage (), e);
}
subs = null;
session = null;
connection = null;
}
public WfAuditEvent receive () throws IOException {
try {
Object e = ((ObjectMessage)subs.receive()).getObject();
if (logger.isDebugEnabled()) {
logger.debug ("EventSubscriber " + this + " received " + e);
}
return (WfAuditEvent)e;
} catch (JMSException e) {
throw (IOException)
(new IOException (e.getMessage())).initCause (e);
}
}
public WfAuditEvent receive (long timeout) throws IOException {
try {
Object e = subs.receive(timeout);
if (e == null) {
return null;
}
e = ((ObjectMessage)e).getObject();
if (logger.isDebugEnabled()) {
logger.debug ("EventSubscriber " + this + " received " + e);
}
return (WfAuditEvent)e;
} catch (JMSException e) {
throw (IOException)
(new IOException (e.getMessage())).initCause (e);
}
}
public WfAuditEvent receiveNoWait () throws IOException {
try {
Object e = ((ObjectMessage)subs.receiveNoWait()).getObject();
if (e == null) {
return null;
}
if (logger.isDebugEnabled()) {
logger.debug ("EventSubscriber " + this + " received " + e);
}
return (WfAuditEvent)e;
} catch (JMSException e) {
throw (IOException)
(new IOException (e.getMessage())).initCause (e);
}
}
public void setEventHandler (WfAuditHandler hndlr) throws IOException {
final WfAuditHandler handler = hndlr;
try {
subs.setMessageListener (new MessageListener () {
public void onMessage (Message msg) {
Object e = null;
try {
e = ((ObjectMessage)msg).getObject();
if (logger.isDebugEnabled()) {
logger.debug
("EventSubscriber " + this
+ " received " + e
+ " with processKey="
+ msg.getStringProperty("processKey")
+ " and eventType="
+ msg.getStringProperty("eventType"));
}
handler.receiveEvent((WfAuditEvent)e);
} catch (JMSException ex) {
logger.error (ex.getMessage (), ex);
} catch (InvalidPerformerException ex) {
// deliberatly ignored.
} catch (RemoteException ex) {
// deliberatly ignored.
} catch (Exception ex) {
logger.error (this + "cannot handle " + e
+ ": " + ex.getMessage (), ex);
}
}
});
} catch (JMSException e) {
throw (IOException)
(new IOException (e.getMessage())).initCause (e);
}
}
}
/* Comment copied from interface. */
public Map serviceProperties () throws RemoteException {
return serviceProperties;
}
/* Comment copied from interface. */
public Configuration configuration() throws RemoteException {
return engine.configuration();
}
/* Comment copied from interface. */
public ProcessDefinitionDirectory processDefinitionDirectory()
throws RemoteException {
return engine.processDefinitionDirectory();
}
/* Comment copied from interface. */
public ProcessDirectory processDirectory() throws RemoteException {
return engine.processDirectory();
}
/* Comment copied from interface. */
public Collection knownResources () throws RemoteException {
return engine.knownResources();
}
/* Comment copied from interface. */
public WfResource resourceByKey (String key)
throws InvalidKeyException, RemoteException {
return engine.resourceByKey(key);
}
/* Comment copied from interface. */
public Collection authorizers (WfResource resource)
throws RemoteException {
return engine.authorizers(resource);
}
/* Comment copied from interface. */
public WfResource asResource (Principal principal)
throws RemoteException, InvalidKeyException {
return engine.asResource(principal);
}
/* Comment copied from interface. */
public Collection requestedBy (WfRequester req)
throws RemoteException {
return ((ExtProcessDirectory)
engine.processDirectory()).requestedBy (req);
}
/* Comment copied from interface. */
public void doFinish (WfActivity act, ProcessData result)
throws InvalidDataException, CannotCompleteException, RemoteException {
engine.doFinish (act, result);
}
/* Comment copied from interface. */
public Object executeBatch (Batch batch)
throws RemoteException, InvocationTargetException {
return engine.executeBatch (batch);
}
/* Comment copied from interface. */
public WfObject eventReceiver (WfAuditHandler handler)
throws RemoteException {
try {
EventSubscriber es = new EventSubscriberImpl (null, null);
es.setEventHandler (handler);
return es;
} catch (IOException e) {
// This mapping is wrong but backward compatible, and the
// method now deprecated anyway.
throw (RemoteException)
(new RemoteException (e.getMessage())).initCause (e);
}
}
/* Comment copied from interface. */
public EventSubscriber createEventSubscriber () throws IOException {
return new EventSubscriberImpl (null, null);
}
/* Comment copied from interface. */
public EventSubscriber createEventSubscriber
(String processKey, String eventTypes) throws IOException {
return new EventSubscriberImpl (processKey, eventTypes);
}
/* Comment copied from interface. */
public void registerRequester (WfRequester requester)
throws RemoteException {
synchronized (this) {
if (reqEvtRec == null) {
try {
reqEvtRec = createEventSubscriber ();
reqEvtRec.setEventHandler (this);
} catch (IOException e) {
throw (IllegalStateException)
(new IllegalStateException
(e.getMessage())).initCause (e);
}
reqsByProcKey = new HashMap ();
procKeysByReq = new HashMap ();
ignoredProcs = new ArrayList ();
reqRefQueue = new ReferenceQueue ();
reqRefCleaner = new Thread () {
public void run () {
while (true) {
try {
Reference ref = reqRefQueue.remove ();
synchronized
(StandardWorkflowService.this) {
Set procKeys
= (Set)procKeysByReq.remove (ref);
for (Iterator i = procKeys.iterator ();
i.hasNext();) {
reqsByProcKey.remove
((String)i.next());
}
}
} catch (InterruptedException e) {
// deliberatly ignored
}
}
}
};
reqRefCleaner.setDaemon (true);
reqRefCleaner.start ();
}
procKeysByReq.put (new WeakReference (requester, reqRefQueue),
new HashSet());
// we could demand a requester to be registered before first
// use and thus avoid rebuilding ignoredProcs after every
// registration. But then we would need elaborate code to
// clean out old process keys from the ignoredProcs set...
ignoredProcs.clear ();
}
}
/**
* Receive an event and distribute it to the appropriate handler.
*
* @param evt the event.
* @throws InvalidPerformerException thrown by the derived
* {@link de.danet.an.workflow.omgcore.WfRequester
* <code>WfRequester</code>} if it receives an event from a
* process that is not among its performers.
* @throws RemoteException if a system-level error occurs.
*/
public void receiveEvent (WfAuditEvent evt)
throws InvalidPerformerException, RemoteException {
try {
String procKey = evt.processKey();
WfRequester requester = null;
synchronized (this) {
WeakReference requesterRef
= (WeakReference)reqsByProcKey.get(procKey);
if (requesterRef != null) {
requester = (WfRequester)requesterRef.get();
}
if (requester == null) {
// if we know that none of ours handles it, discard
if (ignoredProcs.contains (procKey)) {
return;
}
// try to find handler
found:
for (Iterator i = procKeysByReq.keySet().iterator();
i.hasNext();) {
WeakReference reqRef = (WeakReference)i.next();
WfRequester req = (WfRequester)reqRef.get();
if (req == null) {
continue;
}
Set assocKeys = (Set)procKeysByReq.get (reqRef);
Collection perfs = ((WfRequester)req).performers();
for (Iterator p = perfs.iterator(); p.hasNext();) {
WfProcess perf = (WfProcess)p.next();
String pk = perf.key();
reqsByProcKey.put (pk, reqRef);
assocKeys.add (pk);
if (pk.equals (procKey)) {
requester = req;
break found;
}
}
}
if (requester == null) {
ignoredProcs.add (procKey);
}
}
}
// if we know, who handles this, forward (outside sync!)
if (requester != null) {
requester.receiveEvent(evt);
}
} catch (InvalidPerformerException e) {
// deliberately ignored.
} catch (RemoteException e) {
// deliberately ignored.
}
}
/**
* Return the channel messages out topic.
* @return the topic
*/
Topic channelMessageOutTopic () {
return channelMessageOutTopic;
}
/* Comment copied from interface. */
public Channel getChannel (WfProcess process, String channelName)
throws RemoteException {
return new ChannelImpl (this, (Process)process, channelName, false);
}
/* Comment copied from interface. */
public Channel getChannel
(WfProcess process, String channelName, boolean sendOnly)
throws RemoteException {
return new ChannelImpl (this, (Process)process, channelName, sendOnly);
}
/**
* Free any allocated resources.
*/
public void release () {
if (connectionCleanupThread != null) {
Runtime.getRuntime()
.removeShutdownHook(connectionCleanupThread);
connectionCleanupThread.run();
connectionCleanupThread = null;
}
engine = null;
}
/* Comment copied from interface. */
public void release (WfObject obj) {
if (obj instanceof EventSubscriberImpl) {
((EventSubscriberImpl)obj).close();
return;
}
if (obj instanceof ChannelImpl) {
((ChannelImpl)obj).release();
return;
}
if (obj instanceof StandardWorkflowService) {
((StandardWorkflowService)obj).release();
return;
}
EJBUtil.removeSession (obj);
}
/* (non-Javadoc)
* @see de.danet.an.workflow.api.WorkflowService#caller()
*/
public Principal caller() throws RemoteException {
return engine.caller();
}
/**
* This class provides a wrapper around a topic connection that
* prevents it from being stopped or closed (redefined to noop).
*
* @author Michael Lipp
*
*/
public static class TopicConnectionWrapper implements TopicConnection {
private TopicConnection delegee;
/**
* Create a new instance with all attributes initialized
* to defaults or the given values.
*
* @param delegee
*/
public TopicConnectionWrapper(TopicConnection delegee) {
this.delegee = delegee;
}
/**
* @throws JMSException
* @see javax.jms.Connection#close()
*/
public void close() throws JMSException {
}
/**
* @param arg0
* @param arg1
* @param arg2
* @param arg3
* @return
* @throws JMSException
* @see javax.jms.Connection#createConnectionConsumer(javax.jms.Destination, java.lang.String, javax.jms.ServerSessionPool, int)
*/
public ConnectionConsumer createConnectionConsumer(Destination arg0, String arg1, ServerSessionPool arg2, int arg3) throws JMSException {
return delegee.createConnectionConsumer(arg0, arg1, arg2, arg3);
}
/**
* @param arg0
* @param arg1
* @param arg2
* @param arg3
* @return
* @throws JMSException
* @see javax.jms.TopicConnection#createConnectionConsumer(javax.jms.Topic, java.lang.String, javax.jms.ServerSessionPool, int)
*/
public ConnectionConsumer createConnectionConsumer(Topic arg0, String arg1, ServerSessionPool arg2, int arg3) throws JMSException {
return delegee.createConnectionConsumer(arg0, arg1, arg2, arg3);
}
/**
* @param arg0
* @param arg1
* @param arg2
* @param arg3
* @param arg4
* @return
* @throws JMSException
* @see javax.jms.TopicConnection#createDurableConnectionConsumer(javax.jms.Topic, java.lang.String, java.lang.String, javax.jms.ServerSessionPool, int)
*/
public ConnectionConsumer createDurableConnectionConsumer(Topic arg0, String arg1, String arg2, ServerSessionPool arg3, int arg4) throws JMSException {
return delegee.createDurableConnectionConsumer(arg0, arg1, arg2, arg3, arg4);
}
/**
* @param arg0
* @param arg1
* @return
* @throws JMSException
* @see javax.jms.Connection#createSession(boolean, int)
*/
public Session createSession(boolean arg0, int arg1) throws JMSException {
return delegee.createSession(arg0, arg1);
}
/**
* @param arg0
* @param arg1
* @return
* @throws JMSException
* @see javax.jms.TopicConnection#createTopicSession(boolean, int)
*/
public TopicSession createTopicSession(boolean arg0, int arg1) throws JMSException {
return delegee.createTopicSession(arg0, arg1);
}
/**
* @return
* @throws JMSException
* @see javax.jms.Connection#getClientID()
*/
public String getClientID() throws JMSException {
return delegee.getClientID();
}
/**
* @return
* @throws JMSException
* @see javax.jms.Connection#getExceptionListener()
*/
public ExceptionListener getExceptionListener() throws JMSException {
return delegee.getExceptionListener();
}
/**
* @return
* @throws JMSException
* @see javax.jms.Connection#getMetaData()
*/
public ConnectionMetaData getMetaData() throws JMSException {
return delegee.getMetaData();
}
/**
* @param arg0
* @throws JMSException
* @see javax.jms.Connection#setClientID(java.lang.String)
*/
public void setClientID(String arg0) throws JMSException {
delegee.setClientID(arg0);
}
/**
* @param arg0
* @throws JMSException
* @see javax.jms.Connection#setExceptionListener(javax.jms.ExceptionListener)
*/
public void setExceptionListener(ExceptionListener arg0) throws JMSException {
delegee.setExceptionListener(arg0);
}
/**
* @throws JMSException
* @see javax.jms.Connection#start()
*/
public void start() throws JMSException {
delegee.start();
}
/**
* @throws JMSException
* @see javax.jms.Connection#stop()
*/
public void stop() throws JMSException {
}
}
}