Java tutorial
/* * Copyright 2015 Jose Carrizo * Licensed under the Apache License, Version 2.0 * See accompanying file LICENSE or get a copy at http://www.apache.org/licenses/LICENSE-2.0 */ package org.automagic.deps.doctor.editor; import static org.apache.commons.lang3.StringUtils.EMPTY; import static org.apache.commons.lang3.StringUtils.trim; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.lang3.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.versioning.ArtifactVersion; import org.apache.maven.project.MavenProject; import org.automagic.deps.doctor.TransitiveDependency; import org.automagic.deps.doctor.Utils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import com.google.common.base.Optional; public class PomWriterImpl implements PomWriter { private final Document document; private final MavenProject project; private final int indentationSize; private final boolean addComments; private final boolean indentWithTabs; private PomWriter parentWriter; public PomWriterImpl(MavenProject project, int indentationSize, boolean indentWithTabs, boolean addComments) { this.indentationSize = indentationSize; this.addComments = addComments; this.project = project; this.document = Utils.getDocument(project.getFile()); this.indentWithTabs = indentWithTabs; } @Override public void writeFullDependency(TransitiveDependency dependency) { writeDependency("/project", dependency, 2, true); } @Override public void writeDependencyWithoutVersion(TransitiveDependency dependency) { writeDependency("/project", dependency, 2, false); } @Override public void setDependencyVersion(TransitiveDependency dependency) { setDependencyVersion("/project/dependencies", dependency); } @Override public void setVersionProperty(String propertyName, ArtifactVersion version) { Node node = Utils.getNode("/project/properties/" + propertyName, document).get(); node.setTextContent(version.toString()); } @Override public void addExplicitDependencyVersion(TransitiveDependency dependency) { Element versionElement = document.createElement("version"); versionElement.setTextContent(dependency.getVersion().toString()); Artifact artifact = dependency.getArtifact(); Optional<Node> dependencyNode = Utils.getDependencyNode(artifact, document, "/project/dependencies"); addIndentedNode(dependencyNode.get(), versionElement, 3); } @Override public void addDepsMamagement() { Node rootNode = Utils.getNode("/project", document).get(); Element element = document.createElement("dependencyManagement"); addDummyComment(element); addIndentedNode(rootNode, element, 1); rootNode = Utils.getNode("/project/dependencyManagement", document).get(); clearDummyComment(rootNode); } @Override public void writeFullManagedDependency(TransitiveDependency dependency) { writeDependency("/project/dependencyManagement", dependency, 3, true); } @Override public void setManagedDependencyVersion(TransitiveDependency dependency) { setDependencyVersion("/project/dependencyManagement/dependencies", dependency); } @Override public byte[] saveChanges(boolean omitXmlDeclaration) { try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { Transformer transformer = TransformerFactory.newInstance().newTransformer(); if (omitXmlDeclaration) { transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); } Result result = new StreamResult(output); Source input = new DOMSource(document); transformer.transform(input, result); return output.toByteArray(); } catch (TransformerFactoryConfigurationError | TransformerException | IOException e) { throw new RuntimeException(e); } } private void writeDependency(String parent, TransitiveDependency dependency, int indent, boolean full) { Optional<Node> node = Utils.getNode(parent + "/dependencies", document); Node dependenciesNode; if (node.isPresent()) { dependenciesNode = node.get(); } else { Node parentNode = Utils.getNode(parent, document).get(); dependenciesNode = document.createElement("dependencies"); addDummyComment(dependenciesNode); addIndentedNode(parentNode, dependenciesNode, indent - 1); dependenciesNode = Utils.getNode(parent + "/dependencies", document).get(); clearDummyComment(dependenciesNode); } Artifact artifact = dependency.getArtifact(); String groupId = trim(artifact.getGroupId()); String artifactId = trim(artifact.getArtifactId()); String type = trim(artifact.getType()); String classifier = trim(artifact.getClassifier()); String version = dependency.getVersion().toString(); Node dependencyNode = document.createElement("dependency"); if (addComments) { String comment = getCommentText(dependency); dependencyNode.appendChild(document.createComment(comment)); } Node groupIdNode = document.createElement("groupId"); groupIdNode.setTextContent(groupId); dependencyNode.appendChild(groupIdNode); Node artifactIdNode = document.createElement("artifactId"); artifactIdNode.setTextContent(artifactId); dependencyNode.appendChild(artifactIdNode); if (StringUtils.isNotBlank(type) && !"jar".equals(type)) { Node typeNode = document.createElement("type"); typeNode.setTextContent(type); dependencyNode.appendChild(typeNode); } if (StringUtils.isNotBlank(classifier)) { Node classifierNode = document.createElement("classifier"); classifierNode.setTextContent(classifier); dependencyNode.appendChild(classifierNode); } if (full) { Node versionNode = document.createElement("version"); versionNode.setTextContent(version); dependencyNode.appendChild(versionNode); } addIndentedNode(dependenciesNode, dependencyNode, indent); } private void addIndentedNode(final Node parent, Node newChild, int indent) { Optional<Node> insertionPoint = getInsertionPoint(parent); List<Node> indentedList = indent(newChild, indent); Collections.reverse(indentedList); Node point = insertionPoint.get(); for (Node node : indentedList) { if (insertionPoint.isPresent()) { parent.insertBefore(node, point); point = node; } else { parent.appendChild(node); } } } private List<Node> indent(Node node, int indent) { Node root = document.createElement("dummy"); StringBuilder sb = new StringBuilder(); Node wrapper = root; for (int i = 1; i < indent; i++) { Element element = document.createElement("dummy"); wrapper.appendChild(element); wrapper = element; sb.append("/dummy"); } wrapper.appendChild(node); Node prettyRoot = Utils.prettyFormat(root, indentationSize, indentWithTabs); if (sb.length() != 0) { String xpath = sb.substring(1); prettyRoot = Utils.getNode(xpath, prettyRoot).get(); } final Optional<Node> point = getInsertionPoint(prettyRoot); final List<Node> result = new ArrayList<>(); final NodeList childNodes = prettyRoot.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node item = childNodes.item(i); if (point.isPresent() && point.get().equals(item)) { break; } result.add(item); } return result; } private Optional<Node> getInsertionPoint(Node node) { if (!node.hasChildNodes()) { return Optional.absent(); } Node point = null; for (int i = node.getChildNodes().getLength() - 1; i >= 0; i--) { Node blankNode = node.getChildNodes().item(i); if (blankNode.getNodeType() == Node.TEXT_NODE) { String nodeValue = blankNode.getNodeValue(); if (StringUtils.isBlank(nodeValue)) { point = blankNode; } } else { break; } } if (point != null) { return Optional.of(point); } return Optional.absent(); } @Override public PomWriter getParentWriter() { if (parentWriter == null) { parentWriter = new PomWriterImpl(project.getParent(), indentationSize, indentWithTabs, addComments); } return parentWriter; } private void addDummyComment(Node dependenciesNode) { dependenciesNode.appendChild(document.createComment("dummy")); } private void clearDummyComment(Node node) { NodeList childNodes = node.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node item = childNodes.item(i); if (Node.COMMENT_NODE == item.getNodeType()) { node.removeChild(item); break; } if (Node.TEXT_NODE == item.getNodeType()) { item.setNodeValue(EMPTY); } } } private void setDependencyVersion(String parent, TransitiveDependency dependency) { Optional<Node> dependencyNode = Utils.getDependencyNode(dependency.getArtifact(), document, parent); Node versionNode = Utils.getNode("./version", dependencyNode.get()).get(); versionNode.setTextContent(dependency.getVersion().toString()); Optional<Node> comment = Utils.getPluginComment(parent, dependency.getArtifact(), document); if (comment.isPresent()) { comment.get().setNodeValue(getCommentText(dependency)); } } private String getCommentText(TransitiveDependency dependency) { return String.format(" %s trace=%s ", PomWriter.AUTO_COMMENT, dependency.getDependencyNode().toNodeString()); } MavenProject getProject() { return project; } }