View Javadoc
1   /*
2    * REPOWEB, repository manager.
3    *
4    * Terms of license - http://opensource.org/licenses/apachepl.php
5    */
6   package org.repoweb.pom;
7   import java.io.IOException;
8   import java.io.StringReader;
9   import java.io.StringWriter;
10  import java.util.ArrayList;
11  import java.util.Iterator;
12  import java.util.List;
13  import javax.xml.parsers.DocumentBuilder;
14  import javax.xml.parsers.DocumentBuilderFactory;
15  import javax.xml.parsers.ParserConfigurationException;
16  import javax.xml.transform.Transformer;
17  import javax.xml.transform.TransformerConfigurationException;
18  import javax.xml.transform.TransformerException;
19  import javax.xml.transform.TransformerFactory;
20  import javax.xml.transform.dom.DOMSource;
21  import javax.xml.transform.stream.StreamResult;
22  import javax.xml.transform.stream.StreamSource;
23  import org.apache.xpath.XPathAPI;
24  import org.w3c.dom.Document;
25  import org.w3c.dom.Element;
26  import org.w3c.dom.Node;
27  import org.w3c.dom.NodeList;
28  import org.w3c.dom.traversal.NodeIterator;
29  import org.xml.sax.InputSource;
30  import org.xml.sax.SAXException;
31  /***
32   * XML utilitary class for POM files.
33   */
34  public final class XMLProject {
35      private static final String PROJECT = "project";
36      private static final String ARTIFACT_ID = "artifactId";
37      private static final String GROUP_ID = "groupId";
38      private static final String CURRENT_VERSION = "currentVersion";
39      private static final String NAME = "name";
40      private static final String SHORT_DESCRIPTION = "shortDescription";
41      private static final String DESCRIPTION = "description";
42      private static final String URL = "url";
43      private static final String ID = "id";
44      private static final String TYPE = "type";
45      private static final String JAR = "jar";
46      private static final String DEPENDENCIES = "dependencies";
47      private static final String DEPENDENCY = "dependency";
48      private static final String PROPERTIES = "properties";
49      private static final String VERSION = "version";
50  
51      private XMLProject() {}
52  
53      public static Project toBean(final InputSource source)
54          throws ParserConfigurationException, SAXException, IOException, 
55              TransformerException {
56          return new Unmarshaller().toBean(source);
57      }
58  
59  
60      public static String toXml(final Project project)
61          throws ParserConfigurationException, TransformerException {
62          return new Marshaller().toXml(project);
63      }
64  
65  
66      public static String dependenciesToXml(Project project)
67          throws TransformerException, ParserConfigurationException {
68          return new Marshaller().dependenciesToXml(project);
69      }
70  
71  
72      public static void dependenciesToBean(InputSource source, Project project)
73          throws TransformerException, IOException, ParserConfigurationException, 
74              SAXException {
75          if (source == null) {
76              return;
77          }
78          new Unmarshaller().dependenciesToBean(source, project);
79      }
80  
81      /***
82       * Group methods for unmarshalling.
83       */
84      private static final class Unmarshaller {
85          private Common _common;
86  
87          Unmarshaller() throws TransformerConfigurationException {
88              _common = new Common();
89          }
90  
91          public Project toBean(final InputSource source)
92              throws ParserConfigurationException, SAXException, IOException, 
93                  TransformerException {
94              Node doc = getProjectNode(source, PROJECT);
95  
96              Project prj = new Project();
97              String id = getNodeValue(doc, ID);
98  
99              prj.setArtifactId(getNodeValue(doc, ARTIFACT_ID, id));
100             prj.setGroupId(getNodeValue(doc, GROUP_ID, id));
101             prj.setCurrentVersion(getNodeValue(doc, CURRENT_VERSION));
102             prj.setName(getNodeValue(doc, NAME));
103             prj.setShortDescription(StringUtil.flatten(getNodeValue(doc, SHORT_DESCRIPTION)));
104             prj.setDescription(StringUtil.flatten(getNodeValue(doc, DESCRIPTION)));
105             prj.setUrl(getNodeValue(doc, URL));
106             prj.setDependencies(getDependency(doc, DEPENDENCIES + "/" + DEPENDENCY));
107 
108             String result = getFreeContent(doc);
109 
110             if (result.length() != 0) {
111                 prj.setFreeContent(result);
112             }
113 
114             return prj;
115         }
116 
117 
118         public void dependenciesToBean(InputSource source, Project project)
119             throws ParserConfigurationException, IOException, SAXException, 
120                 TransformerException {
121             Node doc = getProjectNode(source, DEPENDENCIES);
122             project.setDependencies(getDependency(doc, DEPENDENCY));
123         }
124 
125 
126         private List getDependency(Node doc, String xpath)
127             throws TransformerException {
128             NodeIterator iter = XPathAPI.selectNodeIterator(doc, xpath);
129 
130             Node node = iter.nextNode();
131             if (node == null) {
132                 return null;
133             }
134 
135             List deps = new ArrayList();
136             while (node != null) {
137                 deps.add(newDependency(node));
138                 node = iter.nextNode();
139             }
140             return deps;
141         }
142 
143 
144         private Dependency newDependency(Node node)
145             throws TransformerException {
146             Dependency dep = new Dependency();
147             String id = getNodeValue(node, ID);
148 
149             dep.setArtifactId(getNodeValue(node, ARTIFACT_ID, id));
150             dep.setGroupId(getNodeValue(node, GROUP_ID, id));
151             dep.setVersion(getNodeValue(node, VERSION));
152             dep.setUrl(getNodeValue(node, URL));
153             dep.setType(getNodeValue(node, TYPE));
154             dep.setJar(getNodeValue(node, JAR));
155             dep.setProperties(getProperties(XPathAPI.selectNodeList(node,
156                         PROPERTIES + "/*")));
157 
158             return dep;
159         }
160 
161 
162         private List getProperties(NodeList childNodes) {
163             List deps = new ArrayList();
164             for (int i = 0; i < childNodes.getLength(); i++) {
165                 Node node = childNodes.item(i);
166                 deps.add(newProperty(node));
167             }
168             return deps;
169         }
170 
171 
172         private Property newProperty(Node node) {
173             Property prop = new Property();
174             prop.setId(node.getNodeName());
175             prop.setValue(node.getFirstChild().getNodeValue());
176             return prop;
177         }
178 
179 
180         private String getFreeContent(Node doc) throws TransformerException {
181             NodeIterator iter =
182                 XPathAPI.selectNodeIterator(doc,
183                     "//project/*[name() != 'pomVersion'" + " and name() != 'id'"
184                     + " and name() != 'artifactId'" + " and name() != 'groupId'"
185                     + " and name() != 'currentVersion'" + " and name() != 'name'"
186                     + " and name() != 'shortDescription'"
187                     + " and name() != 'dependencies'" + " and name() != 'description'"
188                     + " and name() != 'url'" + "]");
189 
190             Node node;
191             StringBuffer buffer = new StringBuffer();
192             while ((node = iter.nextNode()) != null) {
193                 buffer.append(_common.toStringWhitoutHeader(node));
194             }
195             String result = buffer.toString();
196             return result;
197         }
198 
199 
200         private static String getNodeValue(final Node doc, final String nodeName)
201             throws TransformerException {
202             return getNodeValue(doc, nodeName, null);
203         }
204 
205 
206         private static String getNodeValue(Node doc, final String nodeName,
207             final String defaultValue) throws TransformerException {
208             Node node = XPathAPI.selectSingleNode(doc, nodeName);
209             if (node == null || node.getFirstChild() == null) {
210                 return defaultValue;
211             }
212             else {
213                 return node.getFirstChild().getNodeValue();
214             }
215         }
216 
217 
218         private Node getProjectNode(final InputSource source, String tagName)
219             throws ParserConfigurationException, SAXException, IOException {
220             DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
221             DocumentBuilder builder = factory.newDocumentBuilder();
222             Node doc = builder.parse(source).getElementsByTagName(tagName).item(0);
223             return doc;
224         }
225     }
226     /***
227      * Common methods beetwen marshalling and unmarshalling.
228      */
229     private static final class Common {
230         private static final String XSL =
231             "<?xml version=\"1.0\"?>                                           "
232             + "<xsl:stylesheet                                                 "
233             + "        xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"      "
234             + "        version=\"1.0\">                                        "
235             + "   <xsl:output method=\"xml\" encoding=\"TEXT\"/>"
236             + "   <xsl:template match=\"*\" >                                  "
237             + "       <xsl:copy-of select=\".\"/>                              "
238             + "   </xsl:template>                                              "
239             + "</xsl:stylesheet>";
240         private Transformer _transformer;
241 
242         Common() throws TransformerConfigurationException {
243             TransformerFactory tFactory = TransformerFactory.newInstance();
244             _transformer =
245                 tFactory.newTransformer(new StreamSource(new StringReader(XSL)));
246         }
247 
248         public String toStringWhitoutHeader(Node node)
249             throws TransformerException {
250             final String xml = toString(node);
251             return xml.substring(xml.indexOf("?>") + 2);
252         }
253 
254 
255         public String toString(Node node) throws TransformerException {
256             final StringWriter tempWriter = new StringWriter();
257             _transformer.transform(new DOMSource(node), new StreamResult(tempWriter));
258             return tempWriter.toString();
259         }
260     }
261     /***
262      * Group methods for marshalling.
263      */
264     private static final class Marshaller {
265         private Common _common;
266 
267         Marshaller() throws TransformerConfigurationException {
268             _common = new Common();
269         }
270 
271         public String toXml(final Project project)
272             throws ParserConfigurationException, TransformerException {
273             Document rootDocument = buildDom(project);
274 
275             String result = _common.toString(rootDocument);
276 
277             if (project.getFreeContent() != null) {
278                 return (result.substring(0, result.indexOf("</project>"))
279                 + project.getFreeContent() + "</project>").replaceAll("encoding=\"TEXT\"",
280                     "encoding=\"UTF-8\"");
281             }
282             else {
283                 return result.replaceFirst("encoding=\"TEXT\"", "encoding=\"UTF-8\"");
284             }
285         }
286 
287 
288         public String dependenciesToXml(final Project project)
289             throws ParserConfigurationException, TransformerException {
290             if (project.getDependencies() == null) {
291                 return "";
292             }
293             final Document rootDocument = newRootDocument(DEPENDENCIES);
294 
295             addDependecyNodes(rootDocument, rootDocument.getDocumentElement(), project);
296 
297             return removeXmlHeader(_common.toString(rootDocument));
298         }
299 
300 
301         private Document buildDom(final Project project)
302             throws ParserConfigurationException {
303             final Document rootDocument = newRootDocument("project");
304 
305             final Element docElement = rootDocument.getDocumentElement();
306             docElement.setAttribute("xmlns:xsi",
307                 "http://www.w3.org/2001/XMLSchema-instance");
308             docElement.setAttribute("xsi:noNamespaceSchemaLocation", "maven-project.xsd");
309 
310             docElement.appendChild(buildNode("pomVersion", "3", rootDocument));
311             appendNode(docElement, ARTIFACT_ID, project.getArtifactId());
312             appendNode(docElement, GROUP_ID, project.getGroupId());
313             appendNode(docElement, CURRENT_VERSION, project.getCurrentVersion());
314             appendNode(docElement, NAME, project.getName());
315             appendNode(docElement, SHORT_DESCRIPTION, project.getShortDescription());
316             appendNode(docElement, DESCRIPTION, project.getDescription());
317             appendNode(docElement, URL, project.getUrl());
318 
319             if (project.getDependencies() != null) {
320                 final Node dependenciesNode =
321                     docElement.appendChild(rootDocument.createElement(DEPENDENCIES));
322                 addDependecyNodes(rootDocument, dependenciesNode, project);
323             }
324 
325             return rootDocument;
326         }
327 
328 
329         private void addDependecyNodes(final Document rootDocument,
330             final Node dependenciesNode, final Project project) {
331             for (Iterator iter = project.getDependencies().iterator(); iter.hasNext();) {
332                 Dependency dep = (Dependency)iter.next();
333                 Node depNode = newDependencyNode(dep, rootDocument);
334                 dependenciesNode.appendChild(depNode);
335             }
336         }
337 
338 
339         private Node newDependencyNode(final Dependency dep, final Document rootDocument) {
340             final Node depNode = rootDocument.createElement(DEPENDENCY);
341             if (dep.getGroupId().equals(dep.getArtifactId())) {
342                 appendNode(depNode, ID, dep.getGroupId());
343             }
344             else {
345                 appendNode(depNode, GROUP_ID, dep.getGroupId());
346                 appendNode(depNode, ARTIFACT_ID, dep.getArtifactId());
347             }
348             appendNode(depNode, VERSION, dep.getVersion());
349             appendNode(depNode, JAR, dep.getJar());
350             if (!dep.isDefaultType()) {
351                 appendNode(depNode, TYPE, dep.getType());
352             }
353             appendNode(depNode, URL, dep.getUrl());
354 
355             if (dep.getProperties() != null && dep.getProperties().size() != 0) {
356                 final Node propertiesNode =
357                     depNode.appendChild(rootDocument.createElement(PROPERTIES));
358                 for (Iterator iter = dep.getProperties().iterator(); iter.hasNext();) {
359                     Property prop = (Property)iter.next();
360                     appendNode(propertiesNode, prop.getId(), prop.getValue());
361                 }
362             }
363             return depNode;
364         }
365 
366 
367         private static void appendNode(final Node fatherNode, final String nodeName,
368             final String value) {
369             if (value != null && !"".equals(value.trim())) {
370                 fatherNode.appendChild(buildNode(nodeName, value,
371                         fatherNode.getOwnerDocument()));
372             }
373         }
374 
375 
376         private static Node buildNode(final String nodeName, final String value,
377             Document rootDocument) {
378             final Element node = rootDocument.createElement(nodeName);
379 
380             node.appendChild(rootDocument.createTextNode(value));
381 
382             return node;
383         }
384 
385 
386         private Document newRootDocument(String rootTagName)
387             throws ParserConfigurationException {
388             final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
389             final DocumentBuilder builder = factory.newDocumentBuilder();
390             final Document rootDocument =
391                 builder.getDOMImplementation().createDocument(null, rootTagName, null);
392             return rootDocument;
393         }
394 
395 
396         private String removeXmlHeader(String result) {
397             return result.replaceFirst("<?.*?>", "");
398         }
399     }
400 }