001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2004 Danet GmbH (www.danet.de), GS-AN.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: JellyTool.java,v 1.5 2006/11/17 10:52:59 drmlipp Exp $
021: *
022: * $Log: JellyTool.java,v $
023: * Revision 1.5 2006/11/17 10:52:59 drmlipp
024: * Added exception reporting.
025: *
026: * Revision 1.4 2006/09/29 12:32:10 drmlipp
027: * Consistently using WfMOpen as projct name now.
028: *
029: * Revision 1.3 2005/09/05 09:41:49 drmlipp
030: * Synchronized with 1.3.2.
031: *
032: * Revision 1.2.4.1 2005/09/01 13:39:35 drmlipp
033: * Improved exception handling once more.
034: *
035: * Revision 1.2 2004/12/30 12:08:02 mlipp
036: * Added caching of compiled script.
037: *
038: * Revision 1.1 2004/12/22 19:28:11 mlipp
039: * Added jelly tool.
040: *
041: */
042: package de.danet.an.workflow.tools;
043:
044: import java.util.HashMap;
045: import java.util.Map;
046:
047: import java.rmi.RemoteException;
048:
049: import org.apache.commons.jelly.JellyContext;
050: import org.apache.commons.jelly.JellyException;
051: import org.apache.commons.jelly.Script;
052: import org.apache.commons.jelly.XMLOutput;
053: import org.apache.commons.jelly.parser.XMLParser;
054:
055: import org.dom4j.io.SAXContentHandler;
056: import org.xml.sax.SAXException;
057:
058: import de.danet.an.util.sax.NamespaceAttributesFilter;
059:
060: import de.danet.an.workflow.util.SAXEventBufferImpl;
061: import de.danet.an.workflow.util.XPDLUtil;
062:
063: import de.danet.an.workflow.api.Activity;
064: import de.danet.an.workflow.api.FormalParameter;
065: import de.danet.an.workflow.api.SAXEventBuffer;
066:
067: import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
068: import de.danet.an.workflow.spis.aii.CannotExecuteException;
069: import de.danet.an.workflow.spis.aii.ResultProvider;
070: import de.danet.an.workflow.spis.aii.ToolAgent;
071: import de.danet.an.workflow.spis.aii.XMLArgumentTypeProvider;
072:
073: /**
074: * This class provides a tool for executing jelly scripts.
075: *
076: * @author <a href="mailto:mnl@mnl.de">Michael N. Lipp</a>
077: * @version $Revision: 1.5 $
078: */
079: public class JellyTool implements ToolAgent, XMLArgumentTypeProvider,
080: ResultProvider {
081:
082: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
083: .getLog(JellyTool.class);
084:
085: /** The script to be executed on invocation. */
086: private SAXEventBuffer script = null;
087:
088: /** The compiled script. */
089: private Script jscript = null;
090:
091: /** The result container. */
092: private ThreadLocal result = new ThreadLocal();
093:
094: /**
095: * Creates an instance of <code>JellyTool</code>
096: * with all attributes initialized to default values.
097: */
098: public JellyTool() {
099: }
100:
101: /**
102: * Get the value of script.
103: * @return value of script.
104: * @see #setScript
105: */
106: public SAXEventBuffer getScript() {
107: return script;
108: }
109:
110: /**
111: * Set the value of script.
112: * @param newScript value to assign to script.
113: * @see #getScript
114: */
115: public void setScript(SAXEventBuffer newScript) {
116: this .script = newScript;
117: }
118:
119: private class ExtXMLParser extends XMLParser {
120: public void configure() {
121: super .configure();
122: }
123: }
124:
125: private class MyJellyContext extends JellyContext {
126: private Map map;
127: private Map xmlVals = new HashMap();
128: private String arg0name;
129: private boolean arg0set = false;
130:
131: public MyJellyContext(Map argsMap, String arg0) {
132: map = argsMap;
133: arg0name = arg0;
134: }
135:
136: public Object getVariable(String name) {
137: if (map.containsKey(name)) {
138: Object v = map.get(name);
139: if (v instanceof SAXEventBuffer) {
140: if (!xmlVals.containsKey(name)) {
141: SAXContentHandler hdlr = new SAXContentHandler();
142: try {
143: ((SAXEventBuffer) v).emit(hdlr);
144: } catch (SAXException e) {
145: throw (IllegalArgumentException) (new IllegalArgumentException(
146: "Error converting SAX events: "
147: + e.getMessage()))
148: .initCause(e);
149: }
150: xmlVals.put(name, hdlr.getDocument());
151: }
152: return xmlVals.get(name);
153: }
154: return v;
155: } else {
156: return super .getVariable(name);
157: }
158: }
159:
160: public void setVariable(String name, Object value) {
161: if (map.containsKey(name)) {
162: map.put(name, value);
163: if (name.equals(arg0name)) {
164: arg0set = true;
165: }
166: } else {
167: super .setVariable(name, value);
168: }
169: }
170:
171: public boolean isArg0Set() {
172: return arg0set;
173: }
174: }
175:
176: /* Comment copied from interface. */
177: public void invoke(Activity activity, FormalParameter[] fps, Map map)
178: throws RemoteException, CannotExecuteException {
179: try {
180: MyJellyContext context = new MyJellyContext(map, fps[0]
181: .id());
182: synchronized (this ) {
183: if (jscript == null) {
184: ExtXMLParser jellyParser = new ExtXMLParser();
185: jellyParser.setContext(context);
186: jellyParser.configure();
187: script.emit(new NamespaceAttributesFilter(
188: jellyParser));
189: jscript = jellyParser.getScript();
190: jscript.compile();
191: }
192: }
193: SAXEventBufferImpl jres = new SAXEventBufferImpl();
194: jres.startDocument();
195: jscript.run(context, new XMLOutput(jres));
196: jres.endDocument();
197: jres.pack();
198: Map resData = new HashMap();
199: int argStart = 0;
200: if (fps[0].mode() == FormalParameter.Mode.OUT
201: && XPDLUtil.isXMLType(fps[0].type())
202: && !context.isArg0Set()) {
203: resData.put(fps[0].id(), jres);
204: argStart = 1;
205: }
206: for (int i = argStart; i < fps.length; i++) {
207: if (fps[i].mode() == FormalParameter.Mode.IN) {
208: continue;
209: }
210: String fpn = fps[i].id();
211: Object v = context.getVariable(fpn);
212: resData.put(fpn, v);
213: }
214: result.set(resData);
215: } catch (SAXException e) {
216: // Unwrap to support sophisticated
217: // exception handling
218: Exception cause = e;
219: if (e.getException() != null) {
220: cause = e.getException();
221: }
222: logger.error(cause.getMessage());
223: logger.debug(cause.getMessage(), cause);
224: throw new CannotExecuteException(e.getMessage(), cause);
225: } catch (JellyException e) {
226: // Unwrap JellyException to support sophisticated
227: // exception handling
228: Exception cause = e;
229: if (e.getCause() != null
230: && (e.getCause() instanceof Exception)) {
231: cause = (Exception) e.getCause();
232: }
233: logger.error(cause.getMessage());
234: logger.debug(cause.getMessage(), cause);
235: throw new CannotExecuteException(e.getMessage(), cause);
236: }
237:
238: }
239:
240: /* Comment copied from interface. */
241: public Object result() {
242: Object res = result.get();
243: result.set(null);
244: return res;
245: }
246:
247: /* Comment copied from interface. */
248: public void terminate(Activity activity)
249: throws ApplicationNotStoppedException {
250: throw new ApplicationNotStoppedException(
251: "Terminate not implemented for JellyTool.");
252: }
253:
254: /* Comment copied from interface. */
255: public int requestedXMLArgumentType() {
256: return XMLArgumentTypeProvider.XML_AS_SAX;
257: }
258:
259: }
|