/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2006 Danet GmbH (www.danet.de), BU BTS.
* 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: InstanceDataModelImpl.java 3009 2009-03-20 12:46:39Z drmlipp $
*
* $Log$
* Revision 1.3 2007/01/16 10:33:40 drmlipp
* Automatically add date type to binding if appropriate.
*
* Revision 1.2 2006/12/12 14:22:09 drmlipp
* Merged XForms client from branch.
*
* Revision 1.1.2.3 2006/12/11 13:30:19 drmlipp
* Continued with result delivery.
*
* Revision 1.1.2.2 2006/12/08 08:51:21 drmlipp
* Fixed conversion.
*
* Revision 1.1.2.1 2006/12/07 23:17:13 mlipp
* Restructured XForm component's properties.
*
*/
package de.danet.an.xformstool.portletapp;
import java.io.Serializable;
import java.text.ParseException;
import java.util.Date;
import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
import de.danet.an.util.XMLUtil;
import de.danet.an.util.jsf.xftaglib.InstanceDataModel;
import de.danet.an.util.sax.NamespaceAttributesAdder;
import de.danet.an.workflow.api.DefaultProcessData;
import de.danet.an.workflow.api.FormalParameter;
import de.danet.an.workflow.api.SAXEventBuffer;
import de.danet.an.workflow.omgcore.ProcessData;
import de.danet.an.workflow.util.SAXEventBufferImpl;
import de.danet.an.workflow.util.XPDLUtil;
/**
* This class provides an implementation of InstanceDataModel.
*
* @author Michael Lipp
*
*/
public class InstanceDataModelImpl
implements InstanceDataModel, Serializable {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory.getLog
(InstanceDataModelImpl.class);
private String id;
private String applicationId;
private FormalParameter[] formalParameters;
private Map actualParameters;
private transient String submitAction;
private transient Element instance = null;
private transient Node binds = null;
/**
* Create a new instance with all attributes initialized
* to defaults or the given values.
*
* @param id
* @param applicationId
* @param form
* @param binds
* @param instance
*/
public InstanceDataModelImpl
(String id, String applicationId,
FormalParameter[] formalParameters, Map actualParameters) {
this.id = id;
this.applicationId = applicationId;
this.formalParameters = formalParameters;
this.actualParameters = actualParameters;
}
/* (non-Javadoc)
* @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#getId()
*/
public String getId() {
return id;
}
/* (non-Javadoc)
* @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#getInstanceData()
*/
public Node getInstanceData() {
if (instance == null) {
try {
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
instance = doc.createElementNS("", "ActualParameters");
instance.setAttributeNS(XMLUtil.XMLNS_NS, "xmlns", "");
for (int i = 0; i < formalParameters.length; i++) {
FormalParameter fp = formalParameters[i];
Element param = doc.createElementNS("", "ActualParameter");
param.setAttribute("name", fp.id());
Object value = actualParameters.get(fp.id());
if (value == null) {
// do nothing
} else if (value instanceof SAXEventBuffer) {
appendActualParameter(param, (SAXEventBuffer)value);
} else {
param.appendChild(doc.createTextNode(value.toString()));
}
instance.appendChild(param);
}
} catch (ParserConfigurationException e) {
throw (IllegalStateException)
(new IllegalStateException(e.getMessage())).initCause(e);
}
}
return instance;
}
/**
* Append the XML value of an actual parameter to a node.
*/
private void appendActualParameter (Element param, SAXEventBuffer value) {
DOMResult res = new DOMResult();
try {
TransformerHandler t = ((SAXTransformerFactory)
SAXTransformerFactory.newInstance()).newTransformerHandler();
t.setResult(res);
value.emit(new NamespaceAttributesAdder(t));
Node tree = res.getNode();
if (tree instanceof Document) {
tree = ((Document)tree).getDocumentElement();
}
param.appendChild(param.getOwnerDocument().importNode(tree, true));
} catch (TransformerConfigurationException e) {
logger.error(e.getMessage(), e);
} catch (TransformerFactoryConfigurationError e) {
logger.error(e.getMessage(), e);
} catch (SAXException e) {
logger.error(e.getMessage(), e);
}
}
/* (non-Javadoc)
* @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#getBindings()
*/
public Node getBindings() {
if (binds == null) {
try {
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
binds = doc.createDocumentFragment();
for (int i = 0; i < formalParameters.length; i++) {
FormalParameter fp = formalParameters[i];
Element binding
= doc.createElementNS(XMLUtil.XMLNS_XFORMS, "bind");
binding.setAttribute("id", applicationId + ":" + fp.id());
binding.setAttribute
("nodeset", "ActualParameter[@name='" + fp.id() + "']");
if (fp.mode() == FormalParameter.Mode.IN) {
binding.setAttribute ("readonly", "true()");
}
if (fp.type().equals(Date.class)) {
binding.setAttribute ("type", "date");
}
binds.appendChild(binding);
}
} catch (ParserConfigurationException e) {
throw (IllegalStateException)
(new IllegalStateException(e.getMessage())).initCause(e);
}
}
return binds;
}
/* (non-Javadoc)
* Comment copied from interface or superclass.
*/
public void setSubmitAction(String action) {
submitAction = action;
}
/**
* @return Returns the submitAction.
*/
public String getSubmitAction() {
return submitAction;
}
/* (non-Javadoc)
* @see de.danet.an.util.jsf.xftaglib.InstanceDataModel#setInstanceData(org.w3c.dom.Node)
*/
public void setInstanceData(Node updatedData) {
if (updatedData instanceof Document) {
instance = ((Document)updatedData).getDocumentElement();
} else {
instance = (Element)updatedData;
}
if (logger.isDebugEnabled()) {
logger.debug("Instance data set to:\n"
+ XMLUtil.w3cDomToString(instance));
}
}
/**
* Return the submit action.
* @return the submit action
*/
public String submitAction () {
return submitAction;
}
/**
* Return the result map.
*/
public ProcessData resultData () {
ProcessData res = new DefaultProcessData ();
for (Node child = instance.getFirstChild(); child != null;
child = child.getNextSibling()) {
if (!(child instanceof Element)
|| !((Element)child).getNodeName().equals("ActualParameter")) {
continue;
}
Element param = (Element)child;
String name = param.getAttribute("name");
FormalParameter fp = null;
for (int i = 0; i < formalParameters.length; i++) {
if (formalParameters[i].id().equals(name)) {
fp = formalParameters[i];
break;
}
}
if (fp == null || fp.mode().equals(FormalParameter.Mode.IN)) {
continue;
}
if (XPDLUtil.isXMLType(fp.type())) {
SAXEventBufferImpl saxVal = new SAXEventBufferImpl();
try {
Transformer t
= SAXTransformerFactory.newInstance().newTransformer();
t.transform(new DOMSource(param),
new SAXResult(new ChildrenOnlyFiler(saxVal)));
} catch (TransformerConfigurationException e) {
logger.error(e.getMessage(), e);
} catch (TransformerFactoryConfigurationError e) {
logger.error(e.getMessage(), e);
} catch (TransformerException e) {
logger.error(e.getMessage(), e);
}
res.put(fp.id(), saxVal);
} else {
StringBuffer content = new StringBuffer();
for (Node pChild = param.getFirstChild(); pChild != null;
pChild = pChild.getNextSibling()) {
if (pChild.getNodeType() == Node.TEXT_NODE
|| pChild.getNodeType() == Node.CDATA_SECTION_NODE) {
content.append(pChild.getNodeValue());
}
}
if (fp.type().equals(String.class)) {
res.put(fp.id(), content.toString());
} else if (fp.type().equals(Boolean.class)) {
res.put(fp.id(), (new Boolean(content.toString())));
} else if (fp.type().equals(Long.class)) {
res.put(fp.id(), Long.valueOf(content.toString()));
} else if (fp.type().equals(Double.class)) {
res.put(fp.id(), Double.valueOf(content.toString()));
} else if (fp.type().equals(Date.class)) {
// Convert date to datetime
if (content.indexOf("T") < 0) {
content.append("T00:00:00");
}
try {
res.put (fp.id(),
XMLUtil.parseXsdDateTime(content.toString()));
} catch (ParseException e) {
logger.error ("Cannot parse XSD datetime: "
+ content.toString());
}
}
}
}
return res;
}
private class ChildrenOnlyFiler extends XMLFilterImpl {
private int level = 0;
public ChildrenOnlyFiler (ContentHandler dest) {
setContentHandler(dest);
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.XMLFilterImpl#startDocument()
*/
public void startDocument() throws SAXException {
// ignore
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.XMLFilterImpl#endDocument()
*/
public void endDocument() throws SAXException {
// ignore
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.XMLFilterImpl#startElement
*/
public void startElement
(String uri, String localName, String qName, Attributes atts)
throws SAXException {
if (level > 0) {
super.startElement(uri, localName, qName, atts);
}
level += 1;
}
/* (non-Javadoc)
* @see org.xml.sax.helpers.XMLFilterImpl#endElement
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
level -= 1;
if(level > 0) {
super.endElement(uri, localName, qName);
}
}
}
}