001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2003 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: XSLTTool.java,v 1.6 2007/03/27 21:59:43 mlipp Exp $
021: *
022: * $Log: XSLTTool.java,v $
023: * Revision 1.6 2007/03/27 21:59:43 mlipp
024: * Fixed lots of checkstyle warnings.
025: *
026: * Revision 1.5 2006/09/29 12:32:10 drmlipp
027: * Consistently using WfMOpen as projct name now.
028: *
029: * Revision 1.4 2006/03/08 14:46:44 drmlipp
030: * Synchronized with 1.3.3p5.
031: *
032: * Revision 1.3 2005/08/11 15:16:27 drmlipp
033: * Fixed problem with XSLTTool and namespaces.
034: *
035: * Revision 1.2.2.1 2005/08/09 15:46:10 drmlipp
036: * Fixed problem with XSLTTool and namespaces in output parameter
037: * mappings.
038: *
039: * Revision 1.2 2005/01/21 09:37:35 drmlipp
040: * Fixed log level.
041: *
042: * Revision 1.1.1.2 2004/08/18 15:17:38 drmlipp
043: * Update to 1.2
044: *
045: * Revision 1.28 2004/07/01 13:44:34 lipp
046: * Minor caching improvement.
047: *
048: * Revision 1.27 2004/03/31 19:36:20 lipp
049: * Completed implementation of Activity.abandon(String).
050: *
051: * Revision 1.26 2004/02/26 09:42:36 lipp
052: * Fixed startElement parameters.
053: *
054: * Revision 1.25 2004/02/20 09:53:01 lipp
055: * Fixed exception handling.
056: *
057: * Revision 1.24 2004/02/19 13:10:32 lipp
058: * Clarified start-/endDocument usage in SAXEventBuffers.
059: *
060: * Revision 1.23 2004/02/17 15:28:51 lipp
061: * Various improvements.
062: *
063: * Revision 1.22 2004/02/16 15:38:51 lipp
064: * Fixed handling of non-well formed result values.
065: *
066: * Revision 1.21 2004/02/13 10:01:34 lipp
067: * Changed result type for result provider to Map which is more
068: * appropriate.
069: *
070: * Revision 1.20 2004/01/28 14:55:09 lipp
071: * Minor corrections.
072: *
073: * Revision 1.19 2004/01/28 09:25:49 montag
074: * additional testcase added.
075: *
076: * Revision 1.18 2004/01/28 08:34:33 montag
077: * new functionality for merging multiple xml documents in one.
078: *
079: * Revision 1.17 2004/01/27 17:38:30 montag
080: * BodyFiller corrected (handling of missing endDocument event).
081: *
082: * Revision 1.16 2004/01/27 12:11:08 montag
083: * XSLTTool now implements ResultProvider interface.
084: *
085: * Revision 1.15 2003/07/14 09:01:19 montag
086: * error corrected setting the result type
087: * if there is no output mapping defined.
088: *
089: * Revision 1.14 2003/07/14 07:55:09 montag
090: * clean up the code.
091: *
092: * Revision 1.13 2003/07/11 15:08:45 montag
093: * create transformer during setting of xslt
094: * and cache it for repeated tool invocation.
095: *
096: * Revision 1.12 2003/07/11 14:35:04 montag
097: * remove code for file handling for
098: * the xslt parameter.
099: *
100: * Revision 1.11 2003/07/11 14:07:09 montag
101: * return SAXEventBufferImpl if no output
102: * mapping is defined.
103: *
104: * Revision 1.10 2003/07/10 14:42:13 montag
105: * xlst transformation als SAXEventBuffer.
106: *
107: * Revision 1.9 2003/07/04 09:09:09 montag
108: * debug logging inserted.
109: *
110: * Revision 1.8 2003/07/03 12:53:50 montag
111: * url handling corrected.
112: *
113: * Revision 1.7 2003/07/02 15:01:59 montag
114: * documentation completed.
115: *
116: * Revision 1.6 2003/07/02 13:50:09 montag
117: * Property XSLT no longer mandatory.
118: *
119: * Revision 1.5 2003/07/02 11:53:13 montag
120: * Support for additional IN parameters.
121: *
122: * Revision 1.4 2003/07/02 09:30:38 montag
123: * handling of complex out parameters
124: * with no defined mapping fixed.
125: *
126: * Revision 1.3 2003/07/02 07:33:50 montag
127: * first working version of the XSLTTool.
128: *
129: * Revision 1.2 2003/07/01 15:49:55 montag
130: * jaxen-dom for XSLTTool.
131: *
132: * Revision 1.1 2003/07/01 14:28:43 montag
133: * initial of XSLTTool.
134: *
135: *
136: */
137: package de.danet.an.workflow.tools;
138:
139: import java.io.Serializable;
140: import java.io.StringWriter;
141:
142: import java.text.ParseException;
143: import java.util.ArrayList;
144: import java.util.Date;
145: import java.util.HashMap;
146: import java.util.Iterator;
147: import java.util.List;
148: import java.util.Map;
149:
150: import java.net.MalformedURLException;
151: import java.net.URL;
152: import java.rmi.RemoteException;
153:
154: import javax.xml.transform.OutputKeys;
155: import javax.xml.transform.Source;
156: import javax.xml.transform.Templates;
157: import javax.xml.transform.Transformer;
158: import javax.xml.transform.TransformerConfigurationException;
159: import javax.xml.transform.TransformerException;
160: import javax.xml.transform.TransformerFactory;
161: import javax.xml.transform.sax.SAXResult;
162: import javax.xml.transform.sax.SAXTransformerFactory;
163: import javax.xml.transform.sax.TemplatesHandler;
164: import javax.xml.transform.sax.TransformerHandler;
165: import javax.xml.transform.stream.StreamResult;
166: import javax.xml.transform.stream.StreamSource;
167:
168: import org.jaxen.JaxenException;
169: import org.jaxen.XPath;
170: import org.jaxen.jdom.JDOMXPath;
171: import org.jdom.Document;
172: import org.jdom.input.SAXHandler;
173: import org.xml.sax.Attributes;
174: import org.xml.sax.ContentHandler;
175: import org.xml.sax.SAXException;
176: import org.xml.sax.helpers.AttributesImpl;
177: import org.xml.sax.helpers.XMLFilterImpl;
178:
179: import de.danet.an.util.XMLUtil;
180: import de.danet.an.util.sax.BodyFilter;
181:
182: import de.danet.an.workflow.util.SAXEventBufferImpl;
183: import de.danet.an.workflow.util.XPDLUtil;
184:
185: import de.danet.an.workflow.api.Activity;
186: import de.danet.an.workflow.api.FormalParameter;
187: import de.danet.an.workflow.api.SAXEventBuffer;
188:
189: import de.danet.an.workflow.spis.aii.ApplicationNotStoppedException;
190: import de.danet.an.workflow.spis.aii.CannotExecuteException;
191: import de.danet.an.workflow.spis.aii.ResultProvider;
192: import de.danet.an.workflow.spis.aii.ToolAgent;
193: import de.danet.an.workflow.spis.aii.XMLArgumentTypeProvider;
194:
195: /**
196: * This class provides a tool that performs a transformation
197: * according to the JAXP 1.1 specification.
198: *
199: * @author <a href="mailto:montag@danet.de"></a>
200: * @version $Revision: 1.6 $
201: */
202:
203: public class XSLTTool implements ToolAgent, XMLArgumentTypeProvider,
204: ResultProvider, Serializable {
205:
206: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
207: .getLog(XSLTTool.class);
208:
209: // hold the mapping of return parameter name and eventually the XPath
210: // expression (intialized from property)
211: private Map returnParamInfo = new HashMap();
212: // holds the Transformer source property for the stylesheet
213: private SAXEventBufferImpl xsltSource = null;
214:
215: // holds sax transformer factory
216: private SAXTransformerFactory saxTransFactCache = null;
217:
218: // holds the parsed stylesheet
219: private Templates templatesCache = null;
220:
221: /** The result container. */
222: private ThreadLocal result = new ThreadLocal();
223:
224: /**
225: * A filter that suppresses any characters before the first
226: * startElement. Normally there shouldn't be any, but somehow
227: * sometimes there are.
228: */
229: private class BodyCleaner extends XMLFilterImpl {
230: private boolean gotFirst = false;
231:
232: public BodyCleaner(ContentHandler contentHandler) {
233: setContentHandler(contentHandler);
234: }
235:
236: public void characters(char[] charArray, int start, int length)
237: throws SAXException {
238: if (gotFirst) {
239: getContentHandler()
240: .characters(charArray, start, length);
241: }
242: }
243:
244: public void startElement(String nsUri, String lname,
245: String qname, Attributes attributes)
246: throws SAXException {
247: gotFirst = true;
248: getContentHandler().startElement(nsUri, lname, qname,
249: attributes);
250: }
251: }
252:
253: /**
254: * Creates an instance of <code>XSLTTool</code>
255: * with all attributes initialized to default values.
256: */
257: public XSLTTool() {
258: }
259:
260: private SAXTransformerFactory saxTransFact()
261: throws TransformerConfigurationException {
262: synchronized (result) {
263: if (saxTransFactCache == null) {
264: saxTransFactCache = (SAXTransformerFactory) TransformerFactory
265: .newInstance();
266: }
267: return saxTransFactCache;
268: }
269: }
270:
271: /**
272: * Set the definition of XSLT. It is used to invoke the stylesheet
273: * dynamically.
274: * on windows, something like
275: * "file:/C:/Entwicklung/WfMOpen/systemtest/tools/testXSLT.xsl"
276: * on unix, something like "file:/usr/dir/test.xsl"
277: *
278: * @param xsltLocation the location of given XSL as an URL.
279: */
280: public void setXSLT(String xsltLocation) {
281: try {
282: if ((xsltLocation == null) || xsltLocation.equals("")) {
283: return;
284: }
285: // check for URL
286: URL url = null;
287: try {
288: url = new URL(xsltLocation);
289: } catch (MalformedURLException mue) {
290: // url == null
291: }
292: if (url != null) {
293: String systemID = url.toExternalForm();
294: if (logger.isDebugEnabled()) {
295: logger.debug("systemID = " + systemID);
296: }
297: xsltSource = convertToSAXEventBuffer(new StreamSource(
298: systemID));
299: } else {
300: logger.error("Error setting xslt: " + xsltLocation
301: + "is no valid url");
302: }
303: } catch (Exception e) {
304: logger.error("Error setting xslt: " + e.getMessage(), e);
305: }
306: }
307:
308: /**
309: * Create a SaxBufferEventImpl from a given source.
310: * @param source The source.
311: * @return SaxBufferEventImpl for the source
312: * @throws TransformerConfigurationException
313: * @throws TransformerException
314: */
315: private SAXEventBufferImpl convertToSAXEventBuffer(Source source)
316: throws TransformerConfigurationException,
317: TransformerException {
318: SAXEventBufferImpl b = new SAXEventBufferImpl();
319: SAXResult result = new SAXResult(b);
320: TransformerFactory.newInstance().newTransformer().transform(
321: source, result);
322: return b;
323: }
324:
325: /**
326: * Set the definition of XSLT.
327: *
328: * @param xslt the given XSLT definition
329: */
330: public void setXSLT(SAXEventBuffer xslt) {
331: xsltSource = (SAXEventBufferImpl) xslt;
332: }
333:
334: /**
335: * Get a transformer handler for this tool.
336: */
337: private Templates templates() throws CannotExecuteException {
338: try {
339: synchronized (result) {
340: if (templatesCache == null && xsltSource != null) {
341: TemplatesHandler templHand = saxTransFact()
342: .newTemplatesHandler();
343: xsltSource.emit(templHand);
344: // Now the TemplatesHandler contains the xslt information
345: templatesCache = templHand.getTemplates();
346: }
347: }
348: return templatesCache;
349: } catch (TransformerConfigurationException e) {
350: String msg = "Error creating TransformerHandler: "
351: + e.getMessage();
352: logger.error(msg, e);
353: throw new CannotExecuteException(msg);
354: } catch (SAXException e) {
355: String msg = "Error creating TransformerHandler: "
356: + e.getMessage();
357: logger.error(msg, e);
358: throw new CannotExecuteException(msg);
359: }
360: }
361:
362: /**
363: * Set the xml definition of output mappings. It is used to convert the
364: * result of the transformation process.
365: *
366: * @param outputMappings the given xml as JDOM Element.
367: */
368: public void setMappings(org.w3c.dom.Element outputMappings) {
369: try {
370: // retrieve namespaces
371: org.w3c.dom.NodeList namespacesNodeList = outputMappings
372: .getElementsByTagNameNS(XPDLUtil.XPDL_EXTN_NS,
373: "Namespaces");
374: org.w3c.dom.NodeList nsNodeList = null;
375: if (namespacesNodeList.getLength() > 0) {
376: org.w3c.dom.Element namespacesNode = (org.w3c.dom.Element) namespacesNodeList
377: .item(0);
378: nsNodeList = namespacesNode.getElementsByTagNameNS(
379: XPDLUtil.XPDL_EXTN_NS, "Namespace");
380: }
381: org.w3c.dom.NodeList paramNodeList = outputMappings
382: .getElementsByTagNameNS(XPDLUtil.XPDL_EXTN_NS,
383: "Parameter");
384: for (int i = 0; i < paramNodeList.getLength(); i++) {
385: org.w3c.dom.Element param = (org.w3c.dom.Element) paramNodeList
386: .item(i);
387: String name = param.getAttribute("Name");
388: XPath xpath = new JDOMXPath(param
389: .getAttribute("Select"));
390: if (nsNodeList != null) {
391: for (int j = 0; j < nsNodeList.getLength(); j++) {
392: org.w3c.dom.Element ns = (org.w3c.dom.Element) nsNodeList
393: .item(j);
394: String prefix = ns.getAttribute("Prefix");
395: String uri = ns.getAttribute("Uri");
396: xpath.addNamespace(prefix, uri);
397: }
398: }
399: returnParamInfo.put(name, xpath);
400: }
401: } catch (Exception e) {
402: // if any error ocurred, outputMappings is still null.
403: logger
404: .error("error in setting XML for output mappings!",
405: e);
406: }
407: }
408:
409: // Implementation of de.danet.an.workflow.spis.aii.XMLArgumentTypeProvider
410:
411: /**
412: * Return the requested type for XML arguments.
413: * @return one of <code>XML_AS_W3C_DOM</code>,
414: * <code>XML_AS_JDOM</code> or <code>XML_AS_SAX</code>
415: */
416: public int requestedXMLArgumentType() {
417: return XMLArgumentTypeProvider.XML_AS_SAX;
418: }
419:
420: // Implementation of de.danet.an.workflow.spis.aii.ToolAgent
421:
422: /**
423: * Describe <code>invoke</code> method here.
424: *
425: * @param activity a <code>WfActivity</code> value
426: * @param formPars the formal parameters.
427: * @param map a <code>Map</code> value
428: * @throws CannotExecuteException if an error occurs
429: * @throws RemoteException if a system level error occurs
430: */
431: public void invoke(Activity activity, FormalParameter[] formPars,
432: Map map) throws CannotExecuteException, RemoteException {
433: try {
434: result.set(invokeOperation(formPars, map));
435: } catch (JaxenException je) {
436: logger.error(je.getMessage());
437: logger.debug(je.getMessage(), je);
438: throw new CannotExecuteException(je.getMessage());
439: } finally {
440: if (logger.isDebugEnabled()) {
441: logger.debug("Finished invocation of "
442: + activity.uniqueKey());
443: }
444: }
445: }
446:
447: /**
448: * Invoke the transformation through the JAXP 1.1 API.
449: * The first input paramater of type <code>SAXEventBufferImpl</code>
450: * will be treaten as the content to be transformed; additional input
451: * parameters will be handled as additional parameter to the
452: * transformation process.<p>
453: * If no stylesheet is explicitly set, the transformation simply "echoes"
454: * the source to the result.<p>
455: * The result of the transformation is of type <code>DOMResult</code>.
456: * After the transformation, the output parameters are filled with the
457: * result, possibly applying a mapping afterward. The return values are
458: * written in the new constructed process data using the key of the out
459: * formal parameters.
460: * If there is at least one mapping defined, any return value of complex
461: * type will be filled with an element object. If there is no output
462: * mapping defined, then there must at least one output parameter with
463: * a complex type; in this case an object of type SAXEventBufferImpl is
464: * created and the result is set with tihs object.
465: *
466: * @param formPars formal parameters
467: * @param map actual parameters
468: * @return the new process data with the result of web services operation
469: * included.
470: * @throws WSIFDynamicInvokerException if any errors in invoking web
471: * service occurred.
472: */
473: private Map invokeOperation(FormalParameter[] formPars, Map map)
474: throws JaxenException, CannotExecuteException {
475: // Determine the content to be transformed
476: boolean firstInFound = false;
477: String newRootTag = null;
478: // Holds all additional parameter for the transformation
479: Map transformParameters = new HashMap();
480: // Holds all content for the transformation
481: List contentParameters = new ArrayList();
482: for (int i = 0; i < formPars.length; i++) {
483: if (formPars[i].mode() != FormalParameter.Mode.OUT) {
484: // IN or INOUT
485: String key = formPars[i].id();
486: Object value = map.get(key);
487: // check first IN parameter for operational mode
488: if (!firstInFound) {
489: if (value instanceof String) {
490: newRootTag = (String) value;
491: }
492: firstInFound = true;
493: }
494: if (value instanceof SAXEventBuffer) {
495: // add new content
496: contentParameters.add(value);
497: } else {
498: // add new parameter
499: transformParameters.put(key, value);
500: }
501: }
502: }
503:
504: SAXEventBufferImpl seb = new SAXEventBufferImpl();
505: try {
506: SAXResult saxResult = new SAXResult(new BodyCleaner(seb));
507: Templates tmplts = templates();
508: TransformerHandler th = null;
509: if (tmplts == null) {
510: th = saxTransFact().newTransformerHandler();
511: } else {
512: th = saxTransFact().newTransformerHandler(tmplts);
513: }
514: setTransformerParameters(th.getTransformer(),
515: transformParameters);
516: th.setResult(saxResult);
517: if (newRootTag == null) {
518: // simple input tree
519: ((SAXEventBuffer) contentParameters.get(0)).emit(th);
520: } else {
521: // create new start element
522: th.startDocument();
523: th.startElement("", newRootTag, newRootTag,
524: new AttributesImpl());
525: // content
526: Iterator it = contentParameters.iterator();
527: while (it.hasNext()) {
528: SAXEventBuffer c = (SAXEventBuffer) it.next();
529: c.emit(new BodyFilter(th));
530: }
531: th.endElement("", newRootTag, newRootTag);
532: th.endDocument();
533: }
534: seb.pack();
535: } catch (TransformerConfigurationException e) {
536: String msg = "Error creating TransformerHandler: "
537: + e.getMessage();
538: logger.error(msg, e);
539: throw new CannotExecuteException(msg);
540: } catch (SAXException se) {
541: String msg = "Error during transformation: "
542: + se.getMessage();
543: logger.error(msg, se);
544: throw new CannotExecuteException(msg);
545: }
546: if (logger.isDebugEnabled()) {
547: logTransformationResult(seb);
548: }
549:
550: // assemble the result, do additional mapping
551: Map resData = new HashMap();
552: Document jdomRes = null;
553: for (int i = 0; i < formPars.length; i++) {
554: if (logger.isDebugEnabled()) {
555: logger.debug("formPars[i].id() = " + formPars[i].id());
556: logger.debug("formPars[i].type() = "
557: + formPars[i].type());
558: logger.debug("formPars[i].mode() = "
559: + formPars[i].mode());
560: }
561: if (formPars[i].mode() == FormalParameter.Mode.IN) {
562: continue;
563: }
564: XPath path = (XPath) returnParamInfo.get(formPars[i].id());
565: if (logger.isDebugEnabled()) {
566: logger.debug("path = " + path);
567: }
568: if (path == null) {
569: resData.put(formPars[i].id(), seb);
570: continue;
571: }
572: // Handle path expression
573: if (jdomRes == null) {
574: try {
575: SAXHandler hdlr = new SAXHandler();
576: seb.emit(hdlr);
577: jdomRes = hdlr.getDocument();
578: } catch (SAXException e) {
579: String msg = "Problem converting SAX to JDOM: "
580: + e.getMessage();
581: logger.error(msg, e);
582: throw new CannotExecuteException(msg);
583: }
584: }
585: if (formPars[i].type().equals(String.class)) {
586: String value = path.stringValueOf(jdomRes);
587: if (logger.isDebugEnabled()) {
588: logger.debug("value = " + value);
589: }
590: resData.put(formPars[i].id(), value);
591: } else if (formPars[i].type().equals(Date.class)) {
592: String sval = path.stringValueOf(jdomRes);
593: try {
594: Date value = XMLUtil.parseXsdDateTime(sval);
595: if (logger.isDebugEnabled()) {
596: logger.debug("value = " + value);
597: }
598: resData.put(formPars[i].id(), value);
599: } catch (ParseException e) {
600: throw (CannotExecuteException) (new CannotExecuteException(
601: "Problem parsing " + sval
602: + " as xsd datetime: "
603: + e.getMessage())).initCause(e);
604: }
605: } else if (formPars[i].type().equals(Double.class)) {
606: String sval = path.stringValueOf(jdomRes);
607: try {
608: double value = XMLUtil.parseXsdDouble(sval);
609: if (logger.isDebugEnabled()) {
610: logger.debug("value = " + value);
611: }
612: resData.put(formPars[i].id(), new Double(value));
613: } catch (NumberFormatException e) {
614: throw (CannotExecuteException) (new CannotExecuteException(
615: "Problem parsing " + sval
616: + " as xsd double: "
617: + e.getMessage())).initCause(e);
618: }
619: } else if (formPars[i].type().equals(Boolean.class)) {
620: String sval = path.stringValueOf(jdomRes);
621: try {
622: boolean value = XMLUtil.parseXsdBoolean(sval);
623: if (logger.isDebugEnabled()) {
624: logger.debug("value = " + value);
625: }
626: resData.put(formPars[i].id(), new Boolean(value));
627: } catch (ParseException e) {
628: throw (CannotExecuteException) (new CannotExecuteException(
629: "Problem parsing " + sval
630: + " as xsd boolean: "
631: + e.getMessage())).initCause(e);
632: }
633: } else if ((formPars[i].type() instanceof Class)
634: && Number.class
635: .isAssignableFrom((Class) formPars[i]
636: .type())) {
637: Number n = path.numberValueOf(jdomRes);
638: if (formPars[i].type().equals(Long.class)
639: && !(n instanceof Long)) {
640: n = new Long(n.longValue());
641: }
642: resData.put(formPars[i].id(), n);
643: } else {
644: List selected = path.selectNodes(jdomRes);
645: resData.put(formPars[i].id(), selected);
646: }
647: }
648: return resData;
649: }
650:
651: /**
652: * Sets the additional parameter for the transformation process.
653: * @param transformer the transformer
654: * @param transformParameters the additional transform parameters
655: */
656: private void setTransformerParameters(Transformer transformer,
657: Map transformParameters) {
658: // set additional parameters
659: transformer.clearParameters();
660: if (!transformParameters.isEmpty()) {
661: Iterator it = transformParameters.keySet().iterator();
662: while (it.hasNext()) {
663: String key = (String) it.next();
664: Object value = transformParameters.get(key);
665: if (logger.isDebugEnabled()) {
666: logger
667: .debug("Set additional transformer parameter: "
668: + " (" + key + ", " + value + ")");
669: }
670: transformer.setParameter(key, value);
671: }
672: }
673: }
674:
675: /**
676: * Describe <code>terminate</code> method here.
677: *
678: * @param activity a <code>WfActivity</code> value
679: * @throws ApplicationNotStoppedException if the application could
680: * not be terminated.
681: */
682: public void terminate(Activity activity)
683: throws ApplicationNotStoppedException {
684: throw new ApplicationNotStoppedException(
685: "Terminate not implemented for XSLTTool.");
686: }
687:
688: /**
689: * Return the result evaluated during {@link ToolAgent#invoke
690: * <code>invoke</code>}. The method will only be called once after
691: * each invoke, i.e. the attribute holding the result be be
692: * cleared in this method.
693: *
694: * @return the result data or <code>null</code> if the invocation
695: * does not return any data.
696: */
697: public Object result() {
698: Map res = (Map) result.get();
699: result.set(null);
700: return res;
701: }
702:
703: /**
704: * Log the result of the transformtion to System.out.
705: * @param domResult the dom result
706: */
707: private void logTransformationResult(SAXEventBuffer seb) {
708: try {
709: StringWriter sw = new StringWriter();
710: StreamResult streamResult = new StreamResult(sw);
711: SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory
712: .newInstance();
713: TransformerHandler serializer = tf.newTransformerHandler();
714: serializer.getTransformer().setOutputProperty(
715: OutputKeys.ENCODING, "ISO-8859-1");
716: serializer.getTransformer().setOutputProperty(
717: OutputKeys.INDENT, "yes");
718: serializer.setResult(streamResult);
719: seb.emit(serializer);
720: logger.debug("TransformationResult:\n" + sw);
721: } catch (Exception e) {
722: logger.warn(e);
723: }
724: }
725:
726: }
|