/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2004 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: JellyTool.java 1925 2006-11-17 10:52:59Z drmlipp $
*
* $Log$
* Revision 1.4 2006/09/29 12:32:10 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.3 2005/09/05 09:41:49 drmlipp
* Synchronized with 1.3.2.
*
* Revision 1.2.4.1 2005/09/01 13:39:35 drmlipp
* Improved exception handling once more.
*
* Revision 1.2 2004/12/30 12:08:02 mlipp
* Added caching of compiled script.
*
* Revision 1.1 2004/12/22 19:28:11 mlipp
* Added jelly tool.
*
*/
package de.danet.an.workflow.tools;
import java.util.HashMap;
import java.util.Map;
import java.rmi.RemoteException;
import org.apache.commons.jelly.JellyContext;
import org.apache.commons.jelly.JellyException;
import org.apache.commons.jelly.Script;
import org.apache.commons.jelly.XMLOutput;
import org.apache.commons.jelly.parser.XMLParser;
import org.dom4j.io.SAXContentHandler;
import org.xml.sax.SAXException;
import de.danet.an.util.sax.NamespaceAttributesFilter;
import de.danet.an.workflow.util.SAXEventBufferImpl;
import de.danet.an.workflow.util.XPDLUtil;
import de.danet.an.workflow.api.Activity;
import de.danet.an.workflow.api.FormalParameter;
import de.danet.an.workflow.api.SAXEventBuffer;
import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
import de.danet.an.workflow.spis.aii.CannotExecuteException;
import de.danet.an.workflow.spis.aii.ResultProvider;
import de.danet.an.workflow.spis.aii.ToolAgent;
import de.danet.an.workflow.spis.aii.XMLArgumentTypeProvider;
/**
* This class provides a tool for executing jelly scripts.
*
* @author <a href="mailto:mnl@mnl.de">Michael N. Lipp</a>
* @version $Revision: 1925 $
*/
public class JellyTool
implements ToolAgent, XMLArgumentTypeProvider, ResultProvider {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog(JellyTool.class);
/** The script to be executed on invocation. */
private SAXEventBuffer script = null;
/** The compiled script. */
private Script jscript = null;
/** The result container. */
private ThreadLocal result = new ThreadLocal ();
/**
* Creates an instance of <code>JellyTool</code>
* with all attributes initialized to default values.
*/
public JellyTool () {
}
/**
* Get the value of script.
* @return value of script.
* @see #setScript
*/
public SAXEventBuffer getScript() {
return script;
}
/**
* Set the value of script.
* @param newScript value to assign to script.
* @see #getScript
*/
public void setScript(SAXEventBuffer newScript) {
this.script = newScript;
}
private class ExtXMLParser extends XMLParser {
public void configure () {
super.configure ();
}
}
private class MyJellyContext extends JellyContext {
private Map map;
private Map xmlVals = new HashMap ();
private String arg0name;
private boolean arg0set = false;
public MyJellyContext (Map argsMap, String arg0) {
map = argsMap;
arg0name = arg0;
}
public Object getVariable(String name) {
if (map.containsKey (name)) {
Object v = map.get (name);
if (v instanceof SAXEventBuffer) {
if (!xmlVals.containsKey (name)) {
SAXContentHandler hdlr = new SAXContentHandler ();
try {
((SAXEventBuffer)v).emit (hdlr);
} catch (SAXException e) {
throw (IllegalArgumentException)
(new IllegalArgumentException
("Error converting SAX events: "
+ e.getMessage ())).initCause(e);
}
xmlVals.put (name, hdlr.getDocument());
}
return xmlVals.get (name);
}
return v;
} else {
return super.getVariable (name);
}
}
public void setVariable(String name, Object value) {
if (map.containsKey (name)) {
map.put (name, value);
if (name.equals (arg0name)) {
arg0set = true;
}
} else {
super.setVariable (name, value);
}
}
public boolean isArg0Set () {
return arg0set;
}
}
/* Comment copied from interface. */
public void invoke(Activity activity, FormalParameter[] fps, Map map)
throws RemoteException, CannotExecuteException {
try {
MyJellyContext context = new MyJellyContext(map, fps[0].id ());
synchronized (this) {
if (jscript == null) {
ExtXMLParser jellyParser = new ExtXMLParser ();
jellyParser.setContext(context);
jellyParser.configure ();
script.emit (new NamespaceAttributesFilter(jellyParser));
jscript = jellyParser.getScript ();
jscript.compile ();
}
}
SAXEventBufferImpl jres = new SAXEventBufferImpl ();
jres.startDocument ();
jscript.run (context, new XMLOutput(jres));
jres.endDocument ();
jres.pack ();
Map resData = new HashMap ();
int argStart = 0;
if (fps[0].mode() == FormalParameter.Mode.OUT
&& XPDLUtil.isXMLType (fps[0].type())
&& !context.isArg0Set ()) {
resData.put (fps[0].id (), jres);
argStart = 1;
}
for (int i = argStart; i < fps.length; i++) {
if (fps[i].mode() == FormalParameter.Mode.IN) {
continue;
}
String fpn = fps[i].id();
Object v = context.getVariable (fpn);
resData.put (fpn, v);
}
result.set (resData);
} catch (SAXException e) {
// Unwrap to support sophisticated
// exception handling
Exception cause = e;
if (e.getException() != null) {
cause = e.getException();
}
logger.error (cause.getMessage());
logger.debug (cause.getMessage(), cause);
throw new CannotExecuteException(e.getMessage(), cause);
} catch (JellyException e) {
// Unwrap JellyException to support sophisticated
// exception handling
Exception cause = e;
if (e.getCause() != null && (e.getCause() instanceof Exception)) {
cause = (Exception)e.getCause();
}
logger.error (cause.getMessage());
logger.debug (cause.getMessage(), cause);
throw new CannotExecuteException (e.getMessage(), cause);
}
}
/* Comment copied from interface. */
public Object result () {
Object res = result.get();
result.set (null);
return res;
}
/* Comment copied from interface. */
public void terminate(Activity activity)
throws ApplicationNotStoppedException {
throw new ApplicationNotStoppedException
("Terminate not implemented for JellyTool.");
}
/* Comment copied from interface. */
public int requestedXMLArgumentType() {
return XMLArgumentTypeProvider.XML_AS_SAX;
}
}