View Javadoc

1   /*
2    Copyright (C) 2007 Grid Systems, S.A.
3   
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8   
9    This library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13  
14   You should have received a copy of the GNU Lesser General Public
15   License along with this library; if not, write to the Free Software
16   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
17  */
18  package com.gridsystems.nextgrid.api.pom.ref;
19  
20  import java.io.IOException;
21  import java.io.StringReader;
22  import java.io.StringWriter;
23  
24  import javax.xml.parsers.DocumentBuilderFactory;
25  import javax.xml.parsers.ParserConfigurationException;
26  import javax.xml.transform.Transformer;
27  import javax.xml.transform.TransformerConfigurationException;
28  import javax.xml.transform.TransformerException;
29  import javax.xml.transform.TransformerFactory;
30  import javax.xml.transform.dom.DOMSource;
31  import javax.xml.transform.stream.StreamResult;
32  
33  import org.w3c.dom.Document;
34  import org.w3c.dom.Element;
35  import org.w3c.dom.Node;
36  import org.xml.sax.InputSource;
37  import org.xml.sax.SAXException;
38  
39  /**
40   * A DomReference instance wraps an XML DOM document.
41   * <p>
42   * There are mainly two use cases where a DomReference makes sense:
43   *
44   * <ul>
45   *   <li><b>Local Inputs</b>:
46   *     XML supports parameters of arbitrary complexity, from simple scalar
47   *     values, to large complex documents.
48   *   </li>
49   *   <li><b>Local Service Outputs</b>:
50   *     Custom local services (those that execute in the same process than the
51   *     workflow enactor) may use DomReferences to publish their outputs.
52   *   </li>
53   * </ul>
54   *
55   * @author Rodrigo Ruiz
56   */
57  public class DomReference extends ReferenceSupport<Document> {
58  
59    /**
60     * <code>serialVersionUID</code> attribute.
61     */
62    private static final long serialVersionUID = 1208741903142535808L;
63  
64    /**
65     * Wrapped XML document.
66     */
67    private Document doc;
68  
69    /**
70     * Creates a new empty instance.
71     */
72    public DomReference() {
73    }
74  
75    /**
76     * Creates a new instance.
77     *
78     * @param doc XML document to wrap
79     */
80    public DomReference(Document doc) {
81      this.doc = doc;
82    }
83  
84    /**
85     * Creates a new instance.
86     *
87     * @param xml A string containing an XML document
88     * @throws SAXException Parse error
89     * @throws ParserConfigurationException Factory configuration error
90     */
91    public DomReference(String xml)
92      throws SAXException, ParserConfigurationException {
93      this(parseDoc(xml));
94    }
95  
96    /**
97     * {@inheritDoc}
98     */
99    public final Document getValue() {
100     return this.doc;
101   }
102 
103   /**
104    * {@inheritDoc}
105    */
106   public final void setValue(Object value) {
107     if (value == null) {
108       this.doc = null;
109     } else if (value instanceof Document) {
110       this.doc = (Document)value;
111     } else if (value instanceof CharSequence) {
112       try {
113         this.doc = parseDoc(value.toString());
114       } catch (Exception e) {
115         throw new ClassCastException("Invalid XML value");
116       }
117     } else {
118       throw new ClassCastException("Cannot cast " + value.getClass() + " to XML");
119     }
120   }
121 
122   /**
123    * {@inheritDoc}
124    */
125   public Class<Document> getValueType() {
126     return Document.class;
127   }
128 
129   /**
130    * {@inheritDoc}
131    */
132   public boolean canCastTo(Class<?> type) {
133     if (type == null) {
134       return false;
135     } else {
136       return type.isAssignableFrom(Document.class)
137           || type.isAssignableFrom(String.class)
138           || type.isAssignableFrom(Node.class);
139     }
140   }
141 
142   /**
143    * {@inheritDoc}
144    */
145   public boolean canCastFrom(Class<?> type) {
146     return type.isAssignableFrom(CharSequence.class)
147         || type.isAssignableFrom(Document.class);
148   }
149 
150   /**
151    * {@inheritDoc}
152    */
153   public Object castTo(Class<?> type) {
154     if (type.isAssignableFrom(String.class)) {
155       return xmlToString(this.doc);
156     } else if (type.isAssignableFrom(Element.class)) {
157       return this.doc.getDocumentElement();
158     } else if (type.isAssignableFrom(Node.class)) {
159       return this.doc;
160     } else {
161       throw new ClassCastException("Cannot cast XML to " + type);
162     }
163   }
164   /**
165    * Parses a string into a DOM document.
166    *
167    * @param xml The string containing the XML document to parse
168    * @return The obtained document
169    * @throws ParserConfigurationException Factory configuration error
170    * @throws SAXException                 Parse error
171    */
172   protected static Document parseDoc(String xml)
173     throws SAXException, ParserConfigurationException {
174     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
175     //factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
176     factory.setNamespaceAware(true);
177 
178     InputSource is = new InputSource(new StringReader(xml));
179     try {
180       return factory.newDocumentBuilder().parse(is);
181     } catch (IOException e) {
182       // I/O exceptions should never happen while reading a string
183       throw new Error(e);
184     }
185   }
186 
187   /**
188    * Creates a new XML document instance.
189    *
190    * @return An XML document instance
191    * @throws ParserConfigurationException Factory configuration error
192    */
193   protected static Document newDocument() throws ParserConfigurationException {
194     DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
195     return factory.newDocumentBuilder().newDocument();
196   }
197 
198   /**
199    * Gets a string representation of the given XML node.
200    *
201    * @param node A node
202    * @return A String
203    */
204   protected static String xmlToString(Node node) {
205     try {
206       TransformerFactory factory = TransformerFactory.newInstance();
207       Transformer transformer = factory.newTransformer();
208 
209       StringWriter writer = new StringWriter();
210 
211       transformer.transform(new DOMSource(node), new StreamResult(writer));
212       return writer.getBuffer().toString();
213     } catch (TransformerConfigurationException e) {
214       e.printStackTrace();
215     } catch (TransformerException e) {
216       e.printStackTrace();
217     }
218     return null;
219   }
220 }