1
2
3
4
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 }