aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java')
-rw-r--r--framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java372
1 files changed, 372 insertions, 0 deletions
diff --git a/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java b/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
new file mode 100644
index 00000000..bfc6127a
--- /dev/null
+++ b/framework/src/onos/tools/package/maven-plugin/src/main/java/org/onosproject/maven/OnosAppMojo.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.maven;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.Component;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.MavenProjectHelper;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import static com.google.common.io.ByteStreams.toByteArray;
+import static org.codehaus.plexus.util.FileUtils.*;
+
+/**
+ * Produces ONOS application archive using the app.xml file information.
+ */
+@Mojo(name = "app", defaultPhase = LifecyclePhase.PACKAGE)
+public class OnosAppMojo extends AbstractMojo {
+
+ private static final String APP = "app";
+ private static final String NAME = "[@name]";
+ private static final String VERSION = "[@version]";
+ private static final String FEATURES_REPO = "[@featuresRepo]";
+ private static final String ARTIFACT = "artifact";
+
+ private static final String APP_XML = "app.xml";
+ private static final String FEATURES_XML = "features.xml";
+
+ private static final String MVN_URL = "mvn:";
+ private static final String M2_PREFIX = "m2";
+
+ private static final String ONOS_APP_NAME = "onos.app.name";
+ private static final String ONOS_APP_ORIGIN = "onos.app.origin";
+
+ private static final String JAR = "jar";
+ private static final String XML = "xml";
+ private static final String APP_ZIP = "oar";
+ private static final String PACKAGE_DIR = "oar";
+
+ private static final String DEFAULT_ORIGIN = "ON.Lab";
+ private static final String DEFAULT_VERSION = "${project.version}";
+
+ private static final String DEFAULT_FEATURES_REPO =
+ "mvn:${project.groupId}/${project.artifactId}/${project.version}/xml/features";
+ private static final String DEFAULT_ARTIFACT =
+ "mvn:${project.groupId}/${project.artifactId}/${project.version}";
+
+ private static final int BUFFER_SIZE = 8192;
+
+ private String name;
+ private String origin;
+ private String version = DEFAULT_VERSION;
+ private String featuresRepo = DEFAULT_FEATURES_REPO;
+ private List<String> artifacts;
+
+ /**
+ * The project base directory.
+ */
+ @Parameter(defaultValue = "${basedir}")
+ protected File baseDir;
+
+ /**
+ * The directory where the generated catalogue file will be put.
+ */
+ @Parameter(defaultValue = "${project.build.directory}")
+ protected File dstDirectory;
+
+ /**
+ * The project group ID.
+ */
+ @Parameter(defaultValue = "${project.groupId}")
+ protected String projectGroupId;
+
+ /**
+ * The project artifact ID.
+ */
+ @Parameter(defaultValue = "${project.artifactId}")
+ protected String projectArtifactId;
+
+ /**
+ * The project version.
+ */
+ @Parameter(defaultValue = "${project.version}")
+ protected String projectVersion;
+
+ /**
+ * The project version.
+ */
+ @Parameter(defaultValue = "${project.description}")
+ protected String projectDescription;
+
+ @Parameter(defaultValue = "${localRepository}")
+ protected ArtifactRepository localRepository;
+
+ /**
+ * Maven project
+ */
+ @Parameter(defaultValue = "${project}")
+ protected MavenProject project;
+
+ /**
+ * Maven project helper.
+ */
+ @Component
+ protected MavenProjectHelper projectHelper;
+
+
+ private File m2Directory;
+ protected File stageDirectory;
+ protected String projectPath;
+
+ @Override
+ public void execute() throws MojoExecutionException {
+ File appFile = new File(baseDir, APP_XML);
+ File featuresFile = new File(baseDir, FEATURES_XML);
+
+ name = (String) project.getProperties().get(ONOS_APP_NAME);
+
+ // If neither the app.xml file exists, nor the onos.app.name property
+ // is defined, there is nothing for this Mojo to do, so bail.
+ if (!appFile.exists() && name == null) {
+ return;
+ }
+
+ m2Directory = new File(localRepository.getBasedir());
+ stageDirectory = new File(dstDirectory, PACKAGE_DIR);
+ projectPath = M2_PREFIX + "/" + artifactDir(projectGroupId, projectArtifactId, projectVersion);
+
+ origin = (String) project.getProperties().get(ONOS_APP_ORIGIN);
+ origin = origin != null ? origin : DEFAULT_ORIGIN;
+
+ if (appFile.exists()) {
+ loadAppFile(appFile);
+ } else {
+ artifacts = ImmutableList.of(eval(DEFAULT_ARTIFACT));
+ }
+
+ // If there are any artifacts, stage the
+ if (!artifacts.isEmpty()) {
+ getLog().info("Building ONOS application package for " + name + " (v" + eval(version) + ")");
+ artifacts.forEach(a -> getLog().debug("Including artifact: " + a));
+
+ if (stageDirectory.exists() || stageDirectory.mkdirs()) {
+ processAppXml(appFile);
+ processFeaturesXml(featuresFile);
+ processArtifacts();
+ generateAppPackage();
+ } else {
+ throw new MojoExecutionException("Unable to create directory: " + stageDirectory);
+ }
+ }
+ }
+
+ // Loads the app.xml file.
+ private void loadAppFile(File appFile) throws MojoExecutionException {
+ XMLConfiguration xml = new XMLConfiguration();
+ xml.setRootElementName(APP);
+
+ try (FileInputStream stream = new FileInputStream(appFile)) {
+ xml.load(stream);
+ xml.setAttributeSplittingDisabled(true);
+ xml.setDelimiterParsingDisabled(true);
+
+ name = xml.getString(NAME);
+ version = eval(xml.getString(VERSION));
+ featuresRepo = eval(xml.getString(FEATURES_REPO));
+
+ artifacts = xml.configurationsAt(ARTIFACT).stream()
+ .map(cfg -> eval(cfg.getRootNode().getValue().toString()))
+ .collect(Collectors.toList());
+
+ } catch (ConfigurationException e) {
+ throw new MojoExecutionException("Unable to parse app.xml file", e);
+ } catch (FileNotFoundException e) {
+ throw new MojoExecutionException("Unable to find app.xml file", e);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Unable to read app.xml file", e);
+ }
+ }
+
+ // Processes and stages the app.xml file.
+ private void processAppXml(File appFile) throws MojoExecutionException {
+ try {
+ File file = new File(stageDirectory, APP_XML);
+ forceMkdir(stageDirectory);
+ String contents;
+
+ if (appFile.exists()) {
+ contents = fileRead(appFile);
+ } else {
+ byte[] bytes = toByteArray(getClass().getResourceAsStream(APP_XML));
+ contents = new String(bytes);
+ }
+ fileWrite(file.getAbsolutePath(), eval(contents));
+ } catch (IOException e) {
+ throw new MojoExecutionException("Unable to process app.xml", e);
+ }
+ }
+
+ private void processFeaturesXml(File featuresFile) throws MojoExecutionException {
+ boolean specified = featuresRepo != null && featuresRepo.length() > 0;
+
+ // If featuresRepo attribute is specified and there is a features.xml
+ // file present, add the features repo as an artifact
+ try {
+ if (specified && featuresFile.exists()) {
+ processFeaturesXml(new FileInputStream(featuresFile));
+ } else if (specified) {
+ processFeaturesXml(getClass().getResourceAsStream(FEATURES_XML));
+ }
+ } catch (FileNotFoundException e) {
+ throw new MojoExecutionException("Unable to find features.xml file", e);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Unable to process features.xml file", e);
+ }
+ }
+
+ // Processes and stages the features.xml file.
+ private void processFeaturesXml(InputStream stream) throws IOException {
+ String featuresArtifact =
+ artifactFile(projectArtifactId, projectVersion, XML, "features");
+ File dstDir = new File(stageDirectory, projectPath);
+ forceMkdir(dstDir);
+ String s = eval(new String(toByteArray(stream)));
+ fileWrite(new File(dstDir, featuresArtifact).getAbsolutePath(), s);
+ }
+
+ // Stages all artifacts.
+ private void processArtifacts() throws MojoExecutionException {
+ for (String artifact : artifacts) {
+ processArtifact(artifact);
+ }
+ }
+
+ // Stages the specified artifact.
+ private void processArtifact(String artifact) throws MojoExecutionException {
+ if (!artifact.startsWith(MVN_URL)) {
+ throw new MojoExecutionException("Unsupported artifact URL:" + artifact);
+ }
+
+ String[] fields = artifact.substring(4).split("/");
+ if (fields.length < 3) {
+ throw new MojoExecutionException("Illegal artifact URL:" + artifact);
+ }
+
+ try {
+ String file = artifactFile(fields);
+
+ if (projectGroupId.equals(fields[0]) && projectArtifactId.equals(fields[1])) {
+ // Local artifact is not installed yet, package it from target directory.
+ File dstDir = new File(stageDirectory, projectPath);
+ forceMkdir(dstDir);
+ copyFile(new File(dstDirectory, file), new File(dstDir, file));
+ } else {
+ // Other artifacts are packaged from ~/.m2/repository directory.
+ String m2Path = artifactDir(fields);
+ File srcDir = new File(m2Directory, m2Path);
+ File dstDir = new File(stageDirectory, M2_PREFIX + "/" + m2Path);
+ forceMkdir(dstDir);
+ copyFile(new File(srcDir, file), new File(dstDir, file));
+ }
+ } catch (IOException e) {
+ throw new MojoExecutionException("Unable to stage artifact " + artifact, e);
+ }
+ }
+
+ // Generates the ONOS package ZIP file.
+ private void generateAppPackage() throws MojoExecutionException {
+ File appZip = new File(dstDirectory, artifactFile(projectArtifactId, projectVersion,
+ APP_ZIP, null));
+ try (FileOutputStream fos = new FileOutputStream(appZip);
+ ZipOutputStream zos = new ZipOutputStream(fos)) {
+ zipDirectory("", stageDirectory, zos);
+ projectHelper.attachArtifact(this.project, APP_ZIP, null, appZip);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Unable to compress application package", e);
+ }
+ }
+
+ // Generates artifact directory name from the specified fields.
+ private String artifactDir(String[] fields) {
+ return artifactDir(fields[0], fields[1], fields[2]);
+ }
+
+ // Generates artifact directory name from the specified elements.
+ private String artifactDir(String gid, String aid, String version) {
+ return gid.replace('.', '/') + "/" + aid.replace('.', '/') + "/" + version;
+ }
+
+ // Generates artifact file name from the specified fields.
+ private String artifactFile(String[] fields) {
+ return fields.length < 5 ?
+ artifactFile(fields[1], fields[2],
+ (fields.length < 4 ? JAR : fields[3]), null) :
+ artifactFile(fields[1], fields[2], fields[3], fields[4]);
+ }
+
+ // Generates artifact file name from the specified elements.
+ private String artifactFile(String aid, String version, String type,
+ String classifier) {
+ return classifier == null ? aid + "-" + version + "." + type :
+ aid + "-" + version + "-" + classifier + "." + type;
+ }
+
+ // Returns the given string with project variable substitutions.
+ private String eval(String string) {
+ return string == null ? null :
+ string.replaceAll("\\$\\{onos.app.name\\}", name)
+ .replaceAll("\\$\\{onos.app.origin\\}", origin)
+ .replaceAll("\\$\\{project.groupId\\}", projectGroupId)
+ .replaceAll("\\$\\{project.artifactId\\}", projectArtifactId)
+ .replaceAll("\\$\\{project.version\\}", projectVersion)
+ .replaceAll("\\$\\{project.description\\}", projectDescription);
+ }
+
+ // Recursively archives the specified directory into a given ZIP stream.
+ private void zipDirectory(String root, File dir, ZipOutputStream zos)
+ throws IOException {
+ byte[] buffer = new byte[BUFFER_SIZE];
+ File[] files = dir.listFiles();
+ if (files != null && files.length > 0) {
+ for (File file : files) {
+ if (file.isDirectory()) {
+ String path = root + file.getName() + "/";
+ zos.putNextEntry(new ZipEntry(path));
+ zipDirectory(path, file, zos);
+ zos.closeEntry();
+ } else {
+ FileInputStream fin = new FileInputStream(file);
+ zos.putNextEntry(new ZipEntry(root + file.getName()));
+ int length;
+ while ((length = fin.read(buffer)) > 0) {
+ zos.write(buffer, 0, length);
+ }
+ zos.closeEntry();
+ fin.close();
+ }
+ }
+ }
+ }
+}