package co.codewizards.cloudstore.release;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StreamTokenizer;
import java.io.Writer;
import java.util.LinkedList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
class PomUpdater {
private final File pomFile;
private String newMavenVersion;
private String artifactIdPrefix;
private Document document;
private Writer writer;
private final StringBuilder buf = new StringBuilder();
public PomUpdater(final File pomFile) {
this.pomFile = pomFile;
}
public void update() throws Exception {
final DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
final DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
document = dBuilder.parse(pomFile);
if (artifactIdPrefix != null && !getArtifactId().startsWith(artifactIdPrefix))
return;
boolean replaceFile = false;
final LinkedList<String> tagStack = new LinkedList<String>();
final File tmpFile = new File(pomFile.getParentFile(), pomFile.getName() + ".tmp");
OutputStream out = null;
final InputStream in = new FileInputStream(pomFile);
try {
out = new FileOutputStream(tmpFile);
writer = new OutputStreamWriter(out, "UTF-8");
final InputStreamReader reader = new InputStreamReader(in, "UTF-8");
final StreamTokenizer st = new StreamTokenizer(reader);
st.resetSyntax();
st.wordChars('A', 'Z');
st.wordChars('a', 'z');
st.wordChars('0', '9');
st.ordinaryChar('-');
st.ordinaryChar('<');
st.ordinaryChar('>');
st.ordinaryChar('/');
final StringBuilder tagSB = new StringBuilder();
final int[] lastTtype = new int[4];
boolean isInComment = false;
boolean isInTag = false;
boolean isInEndTag = false;
while (StreamTokenizer.TT_EOF != st.nextToken()) {
if (st.sval != null) {
buf.append(st.sval);
if (isInTag)
tagSB.append(st.sval);
}
else if (st.ttype >= 0) {
if (isInComment && st.ttype == '>') {
flushBuf();
if (lastTtype[0] == '-' && lastTtype[1] == '-')
isInComment = false;
}
else if (!isInComment) {
if (st.ttype == '<') {
isInTag = true;
tagSB.setLength(0);
if (buf.length() > 0) {
if ( tagStack.size() == 2
&& tagStack.get(0).equals("project")
&& tagStack.get(1).equals("version")
&& getArtifactId().startsWith(artifactIdPrefix)) {
buf.setLength(0);
buf.append(newMavenVersion);
replaceFile = true;
}
if ( tagStack.size() == 3
&& tagStack.get(0).equals("project")
&& tagStack.get(1).equals("parent")
&& tagStack.get(2).equals("version")
&& getParentArtifactId().startsWith(artifactIdPrefix)) {
buf.setLength(0);
buf.append(newMavenVersion);
replaceFile = true;
}
}
}
else if (isInTag && st.ttype == '/' && lastTtype[0] == '<') {
isInEndTag = true;
}
else if (isInTag && st.ttype == '>') {
flushBuf();
if (lastTtype[0] != '/') { // ignore empty tags (having no end-tag)
final String tag = tagSB.toString();
tagSB.setLength(0);
String tagName = tag.trim();
int idx = tagName.indexOf(' ');
if (idx >= 0)
tagName = tagName.substring(0, idx);
idx = tagName.indexOf('\t');
if (idx >= 0)
tagName = tagName.substring(0, idx);
idx = tagName.indexOf('\n');
if (idx >= 0)
tagName = tagName.substring(0, idx);
if (!tagName.isEmpty() && !tagName.startsWith("?")) {
if (isInEndTag) {
if (tagName.equals(tagStack.peekLast()))
tagStack.pollLast();
else
throw new IllegalStateException("Document \"" + pomFile.getAbsolutePath() + "\" is not well-formed! End-tag \"" + tagName + "\" without corresponding begin-tag!");
}
else {
tagStack.addLast(tagName);
}
}
}
isInEndTag = false;
isInTag = false;
}
else if (st.ttype == '-') {
if (lastTtype[0] == '-' && lastTtype[1] == '!' && lastTtype[2] == '<')
isInComment = true;
if (isInTag)
tagSB.append((char) st.ttype);
}
else if (isInTag) {
tagSB.append((char) st.ttype);
}
}
buf.append((char) st.ttype);
if (st.ttype == '>')
flushBuf();
}
for (int i = lastTtype.length - 2; i >= 0; i--) {
lastTtype[i + 1] = lastTtype[i];
}
lastTtype[0] = st.ttype;
}
flushBuf();
reader.close();
writer.close();
if (replaceFile) {
pomFile.delete();
if (!tmpFile.renameTo(pomFile))
throw new IOException("Failed to rename '" + tmpFile.getAbsolutePath() + "' to '" + pomFile.getAbsolutePath() + "'!!!");
}
} finally {
in.close();
if (out != null)
out.close();
tmpFile.delete();
}
}
private void flushBuf() throws IOException {
writer.write(buf.toString());
buf.setLength(0);
}
public PomUpdater setNewMavenVersion(final String newMavenVersion) {
this.newMavenVersion = newMavenVersion;
return this;
}
public String getNewMavenVersion() {
return newMavenVersion;
}
public String getArtifactIdPrefix() {
return artifactIdPrefix;
}
public PomUpdater setArtifactIdPrefix(final String artifactIdPrefix) {
this.artifactIdPrefix = artifactIdPrefix;
return this;
}
private String artifactId;
private String parentArtifactId;
protected String getArtifactId() {
if (artifactId == null) {
final NodeList nodeList = document.getElementsByTagName("artifactId");
for (int a = 0; a < nodeList.getLength(); ++a) {
final Node node = nodeList.item(a);
if (node.getParentNode() != null && "project".equals(node.getParentNode().getNodeName()) && node.getParentNode().getParentNode() == document) {
final NodeList childNodes = node.getChildNodes();
for (int b = 0; b < childNodes.getLength(); ++b) {
final Node child = childNodes.item(b);
if (child instanceof Text) {
final String wholeText = ((Text)child).getWholeText();
artifactId = wholeText;
return artifactId;
}
}
}
}
artifactId = "";
}
return artifactId;
}
protected String getParentArtifactId() {
if (parentArtifactId == null) {
final NodeList nodeList = document.getElementsByTagName("artifactId");
for (int a = 0; a < nodeList.getLength(); ++a) {
final Node node = nodeList.item(a);
if (node.getParentNode() != null && "parent".equals(node.getParentNode().getNodeName()) && node.getParentNode().getParentNode() != null && "project".equals(node.getParentNode().getParentNode().getNodeName()) && node.getParentNode().getParentNode().getParentNode() == document) {
final NodeList childNodes = node.getChildNodes();
for (int b = 0; b < childNodes.getLength(); ++b) {
final Node child = childNodes.item(b);
if (child instanceof Text) {
final String wholeText = ((Text)child).getWholeText();
parentArtifactId = wholeText;
return parentArtifactId;
}
}
}
}
parentArtifactId = "";
}
return parentArtifactId;
}
}