/*
* 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: ToolBasedImpl.java 2576 2007-11-02 16:00:34Z drmlipp $
*
* $Log$
* Revision 1.6 2007/09/20 21:27:20 mlipp
* Removed superfluous import.
*
* Revision 1.5 2007/05/03 21:58:19 mlipp
* Internal refactoring for making better use of local EJBs.
*
* Revision 1.4 2007/03/27 21:59:43 mlipp
* Fixed lots of checkstyle warnings.
*
* Revision 1.3 2006/09/29 12:32:08 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.2 2005/08/25 13:24:22 drmlipp
* Synchronized with 1.3.1p6.
*
* Revision 1.1.1.2.6.1 2005/08/24 14:14:52 drmlipp
* Started implementation of exception mapping.
*
* Revision 1.1.1.2 2004/08/18 15:17:38 drmlipp
* Update to 1.2
*
* Revision 1.21 2004/05/07 15:02:27 lipp
* Removed legacy initialization code.
*
* Revision 1.20 2004/05/03 15:38:11 lipp
* Getting on with SAX based process creation.
*
* Revision 1.19 2004/04/30 13:46:19 lipp
* Getting on with SAX based initialization.
*
* Revision 1.18 2004/03/25 15:52:45 lipp
* Ensure backward compatibility of serialzed instances.
*
* Revision 1.17 2004/03/25 14:41:47 lipp
* Added possibility to specify actual parameters as XML.
*
* Revision 1.16 2003/06/27 08:51:45 lipp
* Fixed copyright/license information.
*
* Revision 1.15 2003/05/07 14:45:50 lipp
* Implemented synchronous subflow.
*
* Revision 1.14 2003/05/06 13:21:30 lipp
* Resolved cyclic dependency.
*
* Revision 1.13 2003/05/06 09:43:14 lipp
* Moved tool/sub-process invocation.
*
* Revision 1.12 2003/05/05 07:04:51 lipp
* Handling parameters for sub-flow now.
*
* Revision 1.11 2003/04/26 18:56:24 lipp
* Moved extended interfaces to own package.
*
* Revision 1.10 2003/04/26 16:11:14 lipp
* Moved some classes to reduce package dependencies.
*
* Revision 1.9 2003/04/25 14:50:59 lipp
* Fixed javadoc errors and warnings.
*
* Revision 1.8 2003/04/19 19:46:52 lipp
* Fixed parameter evaluation error.
*
* Revision 1.7 2003/04/16 21:06:38 lipp
* Improved placement of debug statement.
*
* Revision 1.6 2003/04/16 16:19:31 lipp
* Fixed null pointer bug
*
* Revision 1.5 2003/04/02 09:30:05 lipp
* Supporting more data types.
*
* Revision 1.4 2003/03/31 16:50:28 huaiyang
* Logging using common-logging.
*
* Revision 1.3 2003/03/28 12:44:08 lipp
* Moved XPDL related constants to XPDLUtil.
*
* Revision 1.2 2003/03/27 12:58:55 lipp
* Removed redundant check.
*
* Revision 1.1 2003/03/27 10:45:37 lipp
* Renamed activity implementation classes for clarity.
*
* Revision 1.10 2003/03/26 09:21:39 lipp
* Added support for evaluating actual IN parameters.
*
* Revision 1.9 2003/03/24 12:31:37 lipp
* Minor improvements.
*
* Revision 1.8 2002/12/19 21:37:43 lipp
* Reorganized interfaces.
*
* Revision 1.7 2002/11/26 11:23:30 lipp
* Modified RemoteException comment.
*
* Revision 1.6 2002/10/09 07:31:22 lipp
* Fixed logger category.
*
* Revision 1.5 2002/10/06 20:14:38 lipp
* Updated argument handling.
*
* Revision 1.4 2002/09/27 10:48:35 lipp
* Fixed bug in parameter mode access.
*
* Revision 1.3 2002/09/24 12:31:44 lipp
* Reestablished method.
*
* Revision 1.2 2002/09/24 12:25:19 lipp
* setResult implemented.
*
* Revision 1.1 2002/09/23 15:12:39 lipp
* Extended tool implementation definition and usage.
*
*/
package de.danet.an.workflow.domain;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import de.danet.an.util.sax.StackedHandler;
import de.danet.an.workflow.internalapi.ExtActivityLocal;
import de.danet.an.workflow.internalapi.ExtProcessLocal;
import de.danet.an.workflow.localapi.ActivityLocal;
import de.danet.an.workflow.localapi.ProcessLocal;
import de.danet.an.workflow.omgcore.InvalidDataException;
import de.danet.an.workflow.api.FormalParameter;
import de.danet.an.workflow.api.InvalidIdException;
import de.danet.an.workflow.api.Activity.ToolImplementation;
/**
* This class represents (an item of) a tool based activity
* implementation, i.e. it implements {@link
* de.danet.an.workflow.localapi.ActivityLocal.ToolImplementation
* <code>ToolImplementation</code>}.
*
* @author <a href="mailto:lipp@danet.de"></a>
* @version $Revision: 2576 $
*/
public final class ToolBasedImpl
extends ActImplBase implements ToolImplementation {
/** Unique id. */
static final long serialVersionUID = -4198678919987230490L;
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog(ToolBasedImpl.class);
/** The tool id. */
private String id = null;
/** The implementation description. */
private String description = null;
/** The actual parmeters. */
private Object[] actualParams = null;
/**
* Creates an instance of <code>ToolImplementation</code>
* with all attributes initialized to default values.
*/
private ToolBasedImpl () {
}
/**
* Return the tool id.
* @return value of id.
*/
public String id() {
return id;
}
/**
* Return the implementation description.
* @return value of description.
*/
public String description() {
return description;
}
/**
* Return the actual parameters.
* @return actualParameters.
*/
public Object[] actualParameters() {
return actualParams;
}
/**
* Triggers the execution of the current tool for the given activity.
* @param act the activity
*/
public void invoke (ExtActivityLocal act) {
try {
ExtProcessLocal process = (ExtProcessLocal)act.containerLocal();
ApplicationDefinition appl = (ApplicationDefinition)
process.processDefinition().applicationById(id());
Map params = parameterMap (process, act, appl);
act.invokeTool (appl, params);
return;
} catch (InvalidIdException e) {
// cannot happen since procdef is initially verified
logger.error (e.getMessage(), e);
throw new IllegalStateException (e.getMessage());
}
}
/**
* Create the parameter map for a tool invocation based on the
* given activity, its container and application definition. This
* method is intended for callers that have retrieved the
* <code>ApplicationDefinition</code> and <code>Process</code>
* from the <code>Activity</code> anyway, so calling {@link
* #parameterMap(ActivityLocal) <code>ParameterMap(Activity)</code>}
* would be a duplication of efforts.
*
* @param process the process which the activity belongs to.
* @param act the activity to which this tool implementation description
* is to be applied.
* @param appl the application definition.
* @return the parameter map.
* @see #parameterMap(ActivityLocal)
*/
private Map parameterMap
(ExtProcessLocal process, ActivityLocal act, ApplicationDefinition appl) {
if (!appl.id().equals (id())) {
throw new IllegalArgumentException
("Application-id \"" + appl.id() + "\" does not match"
+ " actual parameterlist tool reference \"" + id() + "\"");
}
return super.parameterMap (process, act, appl.formalParameters());
}
/**
* Merge the result returned by an implementation into the process
* data. The names of the result data items must be formal parameter
* names which are mapped to process data items as defined by the
* actual parameters.
*
* @param act the activity related with the implementation invocation.
* @param result the result data.
* @throws InvalidDataException if the entries in the result do not
* match formal parameter names or excessive entries exist.
*/
public void mergeResult (ActivityLocal act, Map result)
throws InvalidDataException {
try {
ProcessLocal process = (ProcessLocal)act.containerLocal();
ApplicationDefinition appl = (ApplicationDefinition)
process.processDefinition().applicationById(id());
FormalParameter[] fps = appl.formalParameters();
mergeResult (process, fps, result);
} catch (InvalidIdException e) {
// cannot happen since procdef is initially verified
logger.error (e.getMessage(), e);
throw new IllegalStateException (e.getMessage());
}
}
/**
* Return a string representation of this object.
* @return the representation
*/
public String toString() {
return "Tool[id=" + id() + "]";
}
/**
* Helper class for retrieving the tool based implementation from
* the process definition.
*/
public class SAXInitializer extends StackedHandler {
private List apList = new ArrayList ();
/**
* Receive notification of the beginning of an element.
*
* @param uri the Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace processing is not
* being performed.
* @param loc the local name (without prefix), or the empty string
* if Namespace processing is not being performed.
* @param raw the raw XML 1.0 name (with prefix), or the empty
* string if raw names are not available.
* @param a the attributes attached to the element. If there are
* no attributes, it shall be an empty Attributes object.
* @throws SAXException not thrown.
*/
public void startElement
(String uri, String loc, String raw, Attributes a)
throws SAXException {
if (loc.equals ("Tool")) {
setContextData ("implementation", ToolBasedImpl.this);
id = a.getValue ("Id");
}
}
/**
* Receive notification of the end of an element.
*
* @param uri the Namespace URI, or the empty string if the
* element has no Namespace URI or if Namespace processing is not
* being performed.
* @param loc the local name (without prefix), or the empty string
* if Namespace processing is not being performed.
* @param raw the raw XML 1.0 name (with prefix), or the empty
* string if raw names are not available.
* @throws SAXException not thrown.
*/
public void endElement(String uri, String loc, String raw)
throws SAXException {
if (loc.equals ("Description")) {
description = text().trim();
} else if (loc.equals ("ActualParameter")) {
apList.add (text().trim());
} else if (loc.equals ("Tool")) {
actualParams = (String[])
apList.toArray(new String[apList.size()]);
}
}
}
/**
* Return a handler that can be used to initialize an object from
* SAX events. The instance created is returned in the
* HandlerStack's context data as "implementation".
* @return the handler.
*/
public static StackedHandler saxConstructor () {
return (new ToolBasedImpl()).newSaxInitializer ();
}
private StackedHandler newSaxInitializer () {
return new SAXInitializer ();
}
}