blob: 02ebd1ddda68b0a2a1b96248fbd259880a78cf7d [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 BSI Business Systems Integration AG.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BSI Business Systems Integration AG - initial API and implementation
******************************************************************************/
package org.eclipse.scout.maven.plugins.updatesite;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Stage the updatesite to staging area of the build server.
*/
@Mojo(name = "stage")
public class StagingMojo extends AbstractStagingMojo {
private static final String COMPOSITE_CONTENT = "compositeContent";
private static final String COMPOSITE_ARTIFACTS = "compositeArtifacts";
private static final String COMPOSITE_ARTIFACTS_JAR = COMPOSITE_ARTIFACTS + ".jar";
private static final String COMPOSITE_CONTENT_JAR = COMPOSITE_CONTENT + ".jar";
/**
* The directory where the generated archive file will be put.
*/
@Parameter(defaultValue = "${project.build.directory}/repository")
private String p2InputDirectory;
/**
* The directory where the generated archive file will be put.
*/
@Parameter
private String updatesiteDir;
@Parameter(defaultValue = "nightly")
private String compositeDir;
@Parameter(defaultValue = "http://download.eclipse.org/scout")
private String repositoryUrl;
@Parameter(defaultValue = "100")
private String maxSize;
public String getP2InputDirectory() {
return p2InputDirectory;
}
public void setP2InputDirectory(String p2InputDirectory) {
this.p2InputDirectory = p2InputDirectory;
}
public String getCompositeDirName() {
return compositeDir;
}
public void setCompositeDirName(String compositeDirName) {
this.compositeDir = compositeDirName;
}
public String getUpdatesiteDir() {
return updatesiteDir;
}
public int getMaxSize() {
return Integer.parseInt(maxSize);
}
public void setUpdatesiteDir(String updatesiteDir) {
this.updatesiteDir = updatesiteDir;
}
public String getCompositeUrl() {
return getRepositoryUrl() + "/" + getCompositeDirName();
}
private File getStageDir() {
return new File(getOutputDirectory() + File.separator + "stage");
}
@Override
public void execute() throws MojoExecutionException {
File compositeRepo = createCompositeRepo();
updateCompositeJars(compositeRepo);
File stageTargetDir = getStageTargetDir();
try {
FileUtility.ensureDirExists(stageTargetDir);
String timestamp = createTimestamp();
File zipFile = createStageZip(getStageDir(), timestamp);
createDoStageFile(zipFile, timestamp);
}
catch (IOException e) {
throw new MojoExecutionException("Could not create directory '" + stageTargetDir.getAbsolutePath() + "'.", e);
}
}
public File createCompositeRepo() throws MojoExecutionException {
if (getUpdatesiteDir() == null) {
throw new IllegalArgumentException("UpdatesiteDir cannot be null");
}
getLog().info("Creating composite Repository");
try {
File compositeRepo = new File(getStageDir(), getCompositeDirName());
File p2Dir = new File(compositeRepo.getPath(), getUpdatesiteDir());
FileUtility.ensureDirExists(p2Dir);
File p2InputDir = new File(getP2InputDirectory());
FileUtility.copy(p2InputDir, p2Dir);
return compositeRepo;
}
catch (IOException e) {
throw new MojoExecutionException("Could not copy repository.", e);
}
}
private void updateCompositeJars(File outputDir) throws MojoExecutionException {
File contentJar = downloadJar(getCompositeUrl(), COMPOSITE_CONTENT_JAR, outputDir.getPath());
File artifactsJar = downloadJar(getCompositeUrl(), COMPOSITE_ARTIFACTS_JAR, outputDir.getPath());
updateComposite(outputDir, contentJar, COMPOSITE_CONTENT);
updateComposite(outputDir, artifactsJar, COMPOSITE_ARTIFACTS);
}
public void updateComposite(File outputDir, File contentJar, String folderName) throws MojoExecutionException {
try {
getLog().info("Downloading " + contentJar);
String jarName = contentJar.getName();
File contentXML = extractCompositeArchive(outputDir, contentJar);
appendChild(contentXML, getUpdatesiteDir());
truncateChildren(contentXML, getMaxSize());
File contentFolder = new File(outputDir, folderName);
FileUtility.ensureDirExists(contentFolder);
FileUtility.copyToDir(contentXML, contentFolder);
File newContentJar = new File(outputDir, jarName);
FileUtility.compressArchive(contentFolder, newContentJar);
FileUtility.deleteFile(contentXML);
FileUtility.deleteFile(contentFolder);
}
catch (IOException e) {
throw new MojoExecutionException("Could not update archive", e);
}
}
public static File extractCompositeArchive(File outputDir, File content) throws MojoExecutionException {
if (content.getName() == null || !content.getName().endsWith(".jar")) {
throw new IllegalArgumentException("Composite Archive must be a jar file " + content.getName());
}
try {
FileUtility.extractArchive(content, outputDir);
}
catch (IOException e) {
throw new MojoExecutionException("Could not extract archive", e);
}
String xmlName = content.getName().replace(".jar", ".xml");
File xmlFile = new File(content.getParent(), xmlName);
if (!xmlFile.exists()) {
throw new MojoExecutionException("Could not extract composite archive. XML File not found " + xmlName);
}
return xmlFile;
}
public void appendChild(File contentXML, String locationName) throws MojoExecutionException {
try {
Document doc = FileUtility.readDOM(contentXML);
NodeList childrenNodes = doc.getElementsByTagName("children");
Node children = childrenNodes.item(0);
Element childElement = doc.createElement("child");
childElement.setAttribute("location", locationName);
children.appendChild(childElement);
String size = getChildElementCount(children);
children.getAttributes().getNamedItem("size").setNodeValue(size);
FileUtility.writeDOM(doc, contentXML);
}
catch (ParserConfigurationException e) {
throw new MojoExecutionException("Could not append child", e);
}
catch (SAXException e) {
throw new MojoExecutionException("Could not append child", e);
}
catch (IOException e) {
throw new MojoExecutionException("Could not append child", e);
}
}
public void truncateChildren(File contentXML, int truncateSize) throws MojoExecutionException {
try {
Document doc = FileUtility.readDOM(contentXML);
NodeList childrenNodes = doc.getElementsByTagName("children");
Node children = childrenNodes.item(0);
NodeList childNodes = doc.getElementsByTagName("child");
int removeCount = childNodes.getLength() - truncateSize;
for (int i = 0; i < removeCount; i++) {
children.removeChild(children.getFirstChild());
}
children.getAttributes().getNamedItem("size").setNodeValue(String.valueOf(truncateSize));
FileUtility.writeDOM(doc, contentXML);
}
catch (ParserConfigurationException e) {
throw new MojoExecutionException("Could not truncate children", e);
}
catch (SAXException e) {
throw new MojoExecutionException("Could not truncate children", e);
}
catch (IOException e) {
throw new MojoExecutionException("Could not truncate children", e);
}
}
private static String getChildElementCount(Node node) {
int count = 0;
NodeList childNodes = node.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
if (childNodes.item(i) instanceof Element) {
count++;
}
}
return "" + count;
}
private static File downloadJar(String url, String jarName, String outputDir) throws MojoExecutionException {
try {
URL u = new URL(url + "/" + jarName);
URLConnection conn = u.openConnection();
File outfile = new File(outputDir, jarName);
try (InputStream inputStream = conn.getInputStream(); FileOutputStream f = new FileOutputStream(outfile)) {
FileUtility.copy(inputStream, f);
}
return outfile;
}
catch (MalformedURLException e) {
throw new MojoExecutionException("Could not downlaod Jar " + e);
}
catch (IOException e) {
throw new MojoExecutionException("Could not downlaod Jar " + e);
}
}
public File createStageZip(File directory, String timestamp) throws MojoExecutionException {
File stageTargetDir = getStageTargetDir();
stageTargetDir.mkdirs();
File outZipFile = new File(stageTargetDir, "stage" + timestamp + ".zip");
try {
getLog().info("Zipping " + directory + " to " + outZipFile.getPath());
FileUtility.compressArchive(directory, outZipFile);
return outZipFile;
}
catch (IOException e) {
throw new MojoExecutionException("Could not create stage zip file", e);
}
}
private File createDoStageFile(File zipInputFile, String timestamp) throws MojoExecutionException {
try {
File out = new File(getStageTargetDir(), "doStage_" + timestamp);
String md5 = createMD5(zipInputFile) + " " + zipInputFile.getName();
try (FileWriter writer = new FileWriter(out)) {
writer.write(md5);
}
return out;
}
catch (IOException e) {
throw new MojoExecutionException("Could not create doStage file", e);
}
}
public String createMD5(File data) throws MojoExecutionException {
try {
byte[] content = FileUtility.readFile(data);
java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
byte[] array = md.digest(content);
StringBuilder sb = new StringBuilder();
for (byte element : array) {
sb.append(Integer.toHexString((element & 0xFF) | 0x100).substring(1, 3));
}
return sb.toString();
}
catch (java.security.NoSuchAlgorithmException e) {
throw new MojoExecutionException("Could not create md5", e);
}
catch (IOException e) {
throw new MojoExecutionException("Could not create md5", e);
}
}
private static String createTimestamp() {
SimpleDateFormat f = new SimpleDateFormat("yyyyMMdd-hhmmss-SSS", Locale.ENGLISH);
return f.format(new Date());
}
/**
* @return the repositoryUrl
*/
public String getRepositoryUrl() {
return repositoryUrl;
}
/**
* @param repositoryUrl
* the repositoryUrl to set
*/
public void setRepositoryUrl(String repositoryUrl) {
this.repositoryUrl = repositoryUrl;
}
}