001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2006 Danet GmbH (www.danet.de), BU BTS.
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: InstanceDataModelImpl.java,v 1.4 2007/01/16 15:04:23 drmlipp Exp $
021: *
022: * $Log: InstanceDataModelImpl.java,v $
023: * Revision 1.4 2007/01/16 15:04:23 drmlipp
024: * Added datetime support.
025: *
026: * Revision 1.3 2007/01/16 10:33:40 drmlipp
027: * Automatically add date type to binding if appropriate.
028: *
029: * Revision 1.2 2006/12/12 14:22:09 drmlipp
030: * Merged XForms client from branch.
031: *
032: * Revision 1.1.2.3 2006/12/11 13:30:19 drmlipp
033: * Continued with result delivery.
034: *
035: * Revision 1.1.2.2 2006/12/08 08:51:21 drmlipp
036: * Fixed conversion.
037: *
038: * Revision 1.1.2.1 2006/12/07 23:17:13 mlipp
039: * Restructured XForm component's properties.
040: *
041: */
042: package de.danet.an.xformstool.portletapp;
043:
044: import java.io.Serializable;
045: import java.text.ParseException;
046: import java.util.Date;
047: import java.util.Map;
048:
049: import javax.xml.parsers.DocumentBuilderFactory;
050: import javax.xml.parsers.ParserConfigurationException;
051: import javax.xml.transform.Transformer;
052: import javax.xml.transform.TransformerConfigurationException;
053: import javax.xml.transform.TransformerException;
054: import javax.xml.transform.TransformerFactoryConfigurationError;
055: import javax.xml.transform.dom.DOMResult;
056: import javax.xml.transform.dom.DOMSource;
057: import javax.xml.transform.sax.SAXResult;
058: import javax.xml.transform.sax.SAXTransformerFactory;
059: import javax.xml.transform.sax.TransformerHandler;
060:
061: import org.w3c.dom.Document;
062: import org.w3c.dom.Element;
063: import org.w3c.dom.Node;
064: import org.xml.sax.Attributes;
065: import org.xml.sax.ContentHandler;
066: import org.xml.sax.SAXException;
067: import org.xml.sax.helpers.XMLFilterImpl;
068:
069: import de.danet.an.util.XMLUtil;
070: import de.danet.an.util.jsf.xftaglib.InstanceDataModel;
071: import de.danet.an.util.sax.NamespaceAttributesAdder;
072: import de.danet.an.workflow.api.DefaultProcessData;
073: import de.danet.an.workflow.api.FormalParameter;
074: import de.danet.an.workflow.api.SAXEventBuffer;
075: import de.danet.an.workflow.omgcore.ProcessData;
076: import de.danet.an.workflow.util.SAXEventBufferImpl;
077: import de.danet.an.workflow.util.XPDLUtil;
078:
079: /**
080: * This class provides an implementation of InstanceDataModel.
081: *
082: * @author Michael Lipp
083: *
084: */
085: public class InstanceDataModelImpl implements InstanceDataModel,
086: Serializable {
087:
088: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
089: .getLog(InstanceDataModelImpl.class);
090:
091: private String id;
092: private String applicationId;
093: private FormalParameter[] formalParameters;
094: private Map actualParameters;
095:
096: private transient Element instance = null;
097: private transient Node binds = null;
098:
099: /**
100: * Create a new instance with all attributes initialized
101: * to defaults or the given values.
102: *
103: * @param id
104: * @param applicationId
105: * @param form
106: * @param binds
107: * @param instance
108: */
109: public InstanceDataModelImpl(String id, String applicationId,
110: FormalParameter[] formalParameters, Map actualParameters) {
111: this .id = id;
112: this .applicationId = applicationId;
113: this .formalParameters = formalParameters;
114: this .actualParameters = actualParameters;
115: }
116:
117: /* (non-Javadoc)
118: * @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#getId()
119: */
120: public String getId() {
121: return id;
122: }
123:
124: /* (non-Javadoc)
125: * @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#getInstanceData()
126: */
127: public Node getInstanceData() {
128: if (instance == null) {
129: try {
130: Document doc = DocumentBuilderFactory.newInstance()
131: .newDocumentBuilder().newDocument();
132: instance = doc.createElementNS("", "ActualParameters");
133: instance.setAttributeNS(XMLUtil.XMLNS_NS, "xmlns", "");
134: for (int i = 0; i < formalParameters.length; i++) {
135: FormalParameter fp = formalParameters[i];
136: Element param = doc.createElementNS("",
137: "ActualParameter");
138: param.setAttribute("name", fp.id());
139: Object value = actualParameters.get(fp.id());
140: if (value == null) {
141: // do nothing
142: } else if (value instanceof SAXEventBuffer) {
143: appendActualParameter(param,
144: (SAXEventBuffer) value);
145: } else {
146: param.appendChild(doc.createTextNode(value
147: .toString()));
148: }
149: instance.appendChild(param);
150: }
151: } catch (ParserConfigurationException e) {
152: throw (IllegalStateException) (new IllegalStateException(
153: e.getMessage())).initCause(e);
154: }
155: }
156: return instance;
157: }
158:
159: /**
160: * Append the XML value of an actual parameter to a node.
161: */
162: private void appendActualParameter(Element param,
163: SAXEventBuffer value) {
164: DOMResult res = new DOMResult();
165: try {
166: TransformerHandler t = ((SAXTransformerFactory) SAXTransformerFactory
167: .newInstance()).newTransformerHandler();
168: t.setResult(res);
169: value.emit(new NamespaceAttributesAdder(t));
170: Node tree = res.getNode();
171: if (tree instanceof Document) {
172: tree = ((Document) tree).getDocumentElement();
173: }
174: param.appendChild(param.getOwnerDocument().importNode(tree,
175: true));
176: } catch (TransformerConfigurationException e) {
177: logger.error(e.getMessage(), e);
178: } catch (TransformerFactoryConfigurationError e) {
179: logger.error(e.getMessage(), e);
180: } catch (SAXException e) {
181: logger.error(e.getMessage(), e);
182: }
183: }
184:
185: /* (non-Javadoc)
186: * @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#getBindings()
187: */
188: public Node getBindings() {
189: if (binds == null) {
190: try {
191: Document doc = DocumentBuilderFactory.newInstance()
192: .newDocumentBuilder().newDocument();
193: binds = doc.createDocumentFragment();
194: for (int i = 0; i < formalParameters.length; i++) {
195: FormalParameter fp = formalParameters[i];
196: Element binding = doc.createElementNS(
197: XMLUtil.XMLNS_XFORMS, "bind");
198: binding.setAttribute("id", applicationId + ":"
199: + fp.id());
200: binding.setAttribute("nodeset",
201: "ActualParameter[@name='" + fp.id() + "']");
202: if (fp.mode() == FormalParameter.Mode.IN) {
203: binding.setAttribute("readonly", "true()");
204: }
205: if (fp.type().equals(Date.class)) {
206: binding.setAttribute("type", "date");
207: }
208: binds.appendChild(binding);
209: }
210: } catch (ParserConfigurationException e) {
211: throw (IllegalStateException) (new IllegalStateException(
212: e.getMessage())).initCause(e);
213: }
214: }
215: return binds;
216: }
217:
218: /* (non-Javadoc)
219: * @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#setInstanceData(org.w3c.dom.Node)
220: */
221: public void setInstanceData(Node updatedData) {
222: if (updatedData instanceof Document) {
223: instance = ((Document) updatedData).getDocumentElement();
224: } else {
225: instance = (Element) updatedData;
226: }
227: if (logger.isDebugEnabled()) {
228: logger.debug("Instance data set to:\n"
229: + XMLUtil.w3cDomToString(instance));
230: }
231: }
232:
233: /**
234: * Return the result map.
235: */
236: public ProcessData resultData() {
237: ProcessData res = new DefaultProcessData();
238: for (Node child = instance.getFirstChild(); child != null; child = child
239: .getNextSibling()) {
240: if (!(child instanceof Element)
241: || !((Element) child).getNodeName().equals(
242: "ActualParameter")) {
243: continue;
244: }
245: Element param = (Element) child;
246: String name = param.getAttribute("name");
247: FormalParameter fp = null;
248: for (int i = 0; i < formalParameters.length; i++) {
249: if (formalParameters[i].id().equals(name)) {
250: fp = formalParameters[i];
251: break;
252: }
253: }
254: if (fp == null || fp.mode().equals(FormalParameter.Mode.IN)) {
255: continue;
256: }
257: if (XPDLUtil.isXMLType(fp.type())) {
258: SAXEventBufferImpl saxVal = new SAXEventBufferImpl();
259: try {
260: Transformer t = SAXTransformerFactory.newInstance()
261: .newTransformer();
262: t.transform(new DOMSource(param), new SAXResult(
263: new ChildrenOnlyFiler(saxVal)));
264: } catch (TransformerConfigurationException e) {
265: logger.error(e.getMessage(), e);
266: } catch (TransformerFactoryConfigurationError e) {
267: logger.error(e.getMessage(), e);
268: } catch (TransformerException e) {
269: logger.error(e.getMessage(), e);
270: }
271: res.put(fp.id(), saxVal);
272: } else {
273: StringBuffer content = new StringBuffer();
274: for (Node pChild = param.getFirstChild(); pChild != null; pChild = pChild
275: .getNextSibling()) {
276: if (pChild.getNodeType() == Node.TEXT_NODE
277: || pChild.getNodeType() == Node.CDATA_SECTION_NODE) {
278: content.append(pChild.getNodeValue());
279: }
280: }
281: if (fp.type().equals(String.class)) {
282: res.put(fp.id(), content.toString());
283: } else if (fp.type().equals(Boolean.class)) {
284: res.put(fp.id(), (new Boolean(content.toString())));
285: } else if (fp.type().equals(Long.class)) {
286: res.put(fp.id(), Long.valueOf(content.toString()));
287: } else if (fp.type().equals(Double.class)) {
288: res
289: .put(fp.id(), Double.valueOf(content
290: .toString()));
291: } else if (fp.type().equals(Date.class)) {
292: // Convert date to datetime
293: if (content.indexOf("T") < 0) {
294: content.append("T00:00:00");
295: }
296: try {
297: res.put(fp.id(), XMLUtil
298: .parseXsdDateTime(content.toString()));
299: } catch (ParseException e) {
300: logger.error("Cannot parse XSD datetime: "
301: + content.toString());
302: }
303: }
304: }
305: }
306: return res;
307: }
308:
309: private class ChildrenOnlyFiler extends XMLFilterImpl {
310: private int level = 0;
311:
312: public ChildrenOnlyFiler(ContentHandler dest) {
313: setContentHandler(dest);
314: }
315:
316: /* (non-Javadoc)
317: * @see org.xml.sax.helpers.XMLFilterImpl#startDocument()
318: */
319: public void startDocument() throws SAXException {
320: // ignore
321: }
322:
323: /* (non-Javadoc)
324: * @see org.xml.sax.helpers.XMLFilterImpl#endDocument()
325: */
326: public void endDocument() throws SAXException {
327: // ignore
328: }
329:
330: /* (non-Javadoc)
331: * @see org.xml.sax.helpers.XMLFilterImpl#startElement
332: */
333: public void startElement(String uri, String localName,
334: String qName, Attributes atts) throws SAXException {
335: if (level > 0) {
336: super .startElement(uri, localName, qName, atts);
337: }
338: level += 1;
339: }
340:
341: /* (non-Javadoc)
342: * @see org.xml.sax.helpers.XMLFilterImpl#endElement
343: */
344: public void endElement(String uri, String localName,
345: String qName) throws SAXException {
346: level -= 1;
347: if (level > 0) {
348: super.endElement(uri, localName, qName);
349: }
350: }
351: }
352: }
|