/********************************************************************************
* Plugin to publish jars and update a jnlp file
*
*
* @author Nuno Ferro (mail@nunoferro.com) 2009/05/07
* @cc-plugin
********************************************************************************/
package net.sourceforge.cruisecontrol.publishers;
import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.Publisher;
import net.sourceforge.cruisecontrol.gendoc.annotations.Default;
import net.sourceforge.cruisecontrol.gendoc.annotations.Description;
import net.sourceforge.cruisecontrol.gendoc.annotations.Required;
import net.sourceforge.cruisecontrol.util.ValidationHelper;
import net.sourceforge.cruisecontrol.util.XMLLogHelper;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.util.FileUtils;
import org.apache.log4j.Logger;
import org.jdom.Element;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class JnlpPublisher implements Publisher {
// @todo Needs unit tests, documentation in configxml.html, and a new entry in default-plugins.properties
private static final long serialVersionUID = -5939441135781954954L;
private static final Logger LOG = Logger.getLogger(JnlpPublisher.class);
private String strTarget;
private String strJnlp;
private String strSource;
private boolean bDeleteOldJars;
/**
* @param target Specifies where the jar file should be published.
*/
@Required
public void setTarget(final String target) {
this.strTarget = target;
}
/**
* @param jnlp specifies the jnlp file to be updated.
*/
@Required
public void setJnlp(final String jnlp) {
this.strJnlp = jnlp;
}
/**
* @param source specifies where to get the jar.
*/
@Default("")
@Description("tries to find default from ant (don't think it's working though)")
public void setSource(final String source) {
this.strSource = source;
}
/**
* @param bDel if true deletes old jars with the same name.
*/
@Default("false")
public void setDeleteOldJars(final boolean bDel) {
this.bDeleteOldJars = bDel;
}
public void publish(final Element cruisecontrolLog) throws CruiseControlException {
final XMLLogHelper helper = new XMLLogHelper(cruisecontrolLog);
if (helper.isBuildSuccessful()) {
final Project project = new Project();
// if the source is not specified we set the default:
// ProjectPath/dist
if (strSource == null) {
strSource = project.getBaseDir().getPath() + File.separator + "dist";
}
// Validate target
final File dirTarget = new File(this.strTarget);
if (!dirTarget.exists()) {
throw new CruiseControlException("target directory " + dirTarget.getAbsolutePath()
+ " does not exist");
}
if (!dirTarget.isDirectory()) {
throw new CruiseControlException("target directory " + dirTarget.getAbsolutePath()
+ " is not a directory");
}
// Validate source
final File dirSource = new File(this.strSource);
if (!dirSource.exists()) {
throw new CruiseControlException("source directory " + dirSource.getAbsolutePath()
+ " does not exist");
}
if (!dirSource.isDirectory()) {
throw new CruiseControlException("source directory " + dirSource.getAbsolutePath()
+ " is not a directory");
}
// Validate JNLP file
final File fileJnlp = new File(this.strJnlp);
if (!fileJnlp.exists()) {
throw new CruiseControlException("jnlp file " + fileJnlp.getAbsolutePath()
+ " does not exist");
}
String strEntry = null;
String strNewFile = null;
String strVersion = null;
for (final File file : dirSource.listFiles()) {
final String strFilename = file.getName();
final int idxVersion = strFilename.indexOf("__V");
final int idxJar = strFilename.lastIndexOf(".jar");
// if the filename is valid (it has __V and ends with .jar
if (idxVersion > 0 && idxVersion < idxJar) {
// Grab file version
final String strTmp = strFilename.substring(idxVersion + 3, idxJar);
// Compare version, if it's bigger override
if (strVersion == null || strVersion.compareTo(strTmp) > 0) {
strEntry = strFilename.substring(0, idxVersion);
strNewFile = strFilename;
strVersion = strTmp;
}
}
}
if (strNewFile != null && strVersion != null) {
// Copy file
final FileUtils utils = FileUtils.getFileUtils();
try {
// first delete old jars if needed
if (this.bDeleteOldJars) {
for (final File file : dirTarget.listFiles()) {
if (file.getName().indexOf(strEntry + "__V") > -1) {
if (!file.delete()) {
LOG.warn("Failed to delete old jnlp jar file: " + file.getAbsolutePath());
}
}
}
}
// copy the file
utils.copyFile(new File(dirSource, strNewFile), new File(dirTarget, strNewFile));
} catch (IOException e) {
throw new CruiseControlException(e);
}
try {
// Update JNLP file
updateJnlpFile(this.strJnlp, strEntry, strVersion);
} catch (Exception ex) {
throw new CruiseControlException(ex);
}
}
}
}
public void validate() throws CruiseControlException {
ValidationHelper.assertIsSet(strTarget, "target", this.getClass());
ValidationHelper.assertIsSet(strJnlp, "jnlp", this.getClass());
}
static void updateJnlpFile(final String fileName, final String jarEntry, final String newVersion)
throws Exception {
final Document jnlpDocument = readJnlpDocument(fileName);
replaceVersion(jnlpDocument, jarEntry, newVersion);
writeDocument(jnlpDocument, fileName);
}
static Document readJnlpDocument(final String fileName) throws Exception {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new File(fileName));
}
static void replaceVersion(final Document jnlpDocument, final String jarEntry, final String newVersion) {
final NodeList jarNodes = jnlpDocument.getElementsByTagName("jar");
for (int i = 0; i < jarNodes.getLength(); i++) {
final Node node = jarNodes.item(i);
final NamedNodeMap map = node.getAttributes();
final Node hrefNode = map.getNamedItem("href");
if (hrefNode != null && hrefNode.getNodeValue().indexOf(jarEntry + ".jar") > -1) {
final Attr versionAttribute = jnlpDocument.createAttribute("version");
versionAttribute.setValue(newVersion);
map.setNamedItem(versionAttribute);
break;
}
}
}
static void writeDocument(final Document jnlpDocument, final String fileName) throws Exception {
final TransformerFactory xformFactory = TransformerFactory.newInstance();
final Transformer idTransform = xformFactory.newTransformer();
final Source input = new DOMSource(jnlpDocument);
final Result output = new StreamResult(new FileOutputStream(fileName));
idTransform.transform(input, output);
}
}