/* * $Id$ * * SARL is an general-purpose agent programming language. * More details on http://www.sarl.io * * Copyright (C) 2014-2017 the original authors or authors. * * 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 io.sarl.maven.sre; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Map; import java.util.Objects; import java.util.jar.Attributes; import java.util.jar.Manifest; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; import io.sarl.eclipse.runtime.SREConstants; import io.sarl.lang.SARLVersion; /** Abstract mojo for compiling SARL. * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public abstract class AbstractSREMojo extends AbstractMojo { /** * The current Maven session. */ @Parameter(defaultValue = "${session}", required = true, readonly = true) private MavenSession session; /** * The current Maven project. */ @Parameter(defaultValue = "${project}", readonly = true, required = true) private MavenProject project; /** The boot class of the SRE. */ @Parameter(required = true) private String mainClass; /** * The version of the SARL specification supported by the SRE. */ @Parameter(defaultValue = SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING, required = true) private String sarlSpecificationVersion; /** * Name of the SRE. */ @Parameter(required = true) private String sreName; /** * Arguments for the Java virtual machine that will be used for running the SRE. */ @Parameter private String vmArguments; /** * Arguments for the application that will be ran by the SRE. */ @Parameter private String applicationArguments; /** * Command line options. */ @Parameter private CommandLineOptions commandLineOptions; /** * Indicates if the SRE is standalone. A standalone SRE is a SRE that is given in a single archive with * all its dependencies inside. * * <p>If this parameter is <code>true</code>, the SRE does not need other Maven artifact to be used. * If this parameter is <code>false</code>, the SRE needs another Maven artifact to be used. * * <p>By default, a SRE is assued to be standalone. */ @Parameter(defaultValue = "true") private boolean standaloneSRE; private ManifestUpdater manifestUpdater; /** Replies the manifest updater. * * @return the updater. */ public ManifestUpdater getManifestUpdater() { return this.manifestUpdater; } /** Change the manifest updater. * * @param updater the updater. */ public void setManifestUpdater(ManifestUpdater updater) { this.manifestUpdater = updater; } @Override public final void execute() throws MojoExecutionException, MojoFailureException { try { executeMojo(); } catch (Exception e) { getLog().error(e.getLocalizedMessage()); throw e; } } /** Execute the mojo. * * @throws MojoExecutionException if an unexpected problem occurs. Throwing this * exception causes a "BUILD ERROR" message to be displayed. * @throws MojoFailureException if an expected problem (such as a compilation failure) * occurs. Throwing this exception causes a "BUILD FAILURE" message to be displayed. */ protected abstract void executeMojo() throws MojoExecutionException, MojoFailureException; /** Put the string representation of the properties of this object into the given buffer. * * @param buffer the buffer. */ public void buildPropertyString(StringBuilder buffer) { buffer.append("sarlSpecification = ").append(this.sarlSpecificationVersion).append("\n"); //$NON-NLS-1$//$NON-NLS-2$ buffer.append("sreName = ").append(this.sreName).append("\n"); //$NON-NLS-1$//$NON-NLS-2$ buffer.append("standaloneSRE = ").append(this.standaloneSRE).append("\n"); //$NON-NLS-1$//$NON-NLS-2$ if (this.commandLineOptions != null) { this.commandLineOptions.buildPropertyString(buffer); } } /** Replies the current Maven session. * * @return the session */ protected MavenSession getMavenSession() { return this.session; } /** Replies the current Maven project. * * @return the project */ protected MavenProject getMavenProject() { return this.project; } /** The name of the main class of the SRE. * * @return the main class, never <code>null</code>. */ protected String getMainClass() { return Objects.toString(this.mainClass, ""); //$NON-NLS-1$ } /** Change the name of the main class of the SRE. * * @param name the main class. */ protected void setMainClass(String name) { this.mainClass = name; } /** Replies the version number of the SARL specification supported by the SRE. * * @return the sarlSpecificationVersion */ protected String getSarlSpecificationVersion() { if (this.sarlSpecificationVersion == null || this.sarlSpecificationVersion.isEmpty()) { return SARLVersion.SPECIFICATION_RELEASE_VERSION_STRING; } return this.sarlSpecificationVersion; } /** Replies the name of the SRE. * * @return the name, never <code>null</code>. */ protected String getSreName() { return Objects.toString(this.sreName, ""); //$NON-NLS-1$ } /** Chagne the name of the SRE. * * @param name the name. */ protected void setSreName(String name) { this.sreName = name; } /** Replies the arguments for the VM. * * @return the arguments, never <code>null</code>. */ protected String getVmArguments() { return Objects.toString(this.vmArguments, ""); //$NON-NLS-1$ } /** Change the arguments for the VM. * * @param args the arguments. */ protected void setVmArguments(String args) { this.vmArguments = args; } /** Replies the arguments for the application. * * @return the arguments, never <code>null</code>. */ protected String getApplicationArguments() { return Objects.toString(this.applicationArguments, ""); //$NON-NLS-1$ } /** Change the arguments for the application. * * @param args the arguments. */ protected void setApplicationArguments(String args) { this.applicationArguments = args; } /** Replies the command line options for the SRE. * * @return the command line options. */ protected CommandLineOptions getCommandLineOptions() { if (this.commandLineOptions == null) { this.commandLineOptions = new CommandLineOptions(); } return this.commandLineOptions; } /** Replies if the SRE is standalone. * * @return <code>true</code> if the SRE is standalone. */ protected boolean isStandaloneSRE() { return this.standaloneSRE; } /** Change if the SRE is standalone. * * @param standalone <code>true</code> if the SRE is standalone. */ protected void setStandaloneSRE(boolean standalone) { this.standaloneSRE = standalone; } /** Create the manifest of the SRE. * * @param filename the name of the manifest; or <code>null</code> if default. * @return the created file. * @throws MojoExecutionException if the mojo fails. * @throws MojoFailureException if the generation fails. */ protected File createSREManifestFile(File filename) throws MojoExecutionException, MojoFailureException { try { final Manifest manifest = createSREManifest(); final File manifestFile; if (filename == null) { final File parent = new File(getMavenProject().getBuild().getOutputDirectory()); manifestFile = new File(parent.getParentFile(), "SRE-MANIFEST.MF"); //$NON-NLS-1$ } else { manifestFile = filename; } try (FileOutputStream fos = new FileOutputStream(manifestFile)) { manifest.write(fos); } return manifestFile; } catch (MojoFailureException exception) { throw exception; } catch (IOException exception) { throw new MojoFailureException(exception.getLocalizedMessage(), exception); } } /** Create the manifest of the SRE. * * @return the created manifest. * @throws MojoExecutionException if the mojo fails. * @throws MojoFailureException if the generation fails. */ protected Manifest createSREManifest() throws MojoExecutionException, MojoFailureException { final Manifest manifest = new Manifest(); final String mainClass = getMainClass(); if (mainClass.isEmpty()) { throw new MojoFailureException("the main class of the SRE is missed"); //$NON-NLS-1$ } ManifestUpdater updater = getManifestUpdater(); if (updater == null) { updater = new ManifestUpdater() { @Override public void addSREAttribute(String name, String value) { assert name != null && !name.isEmpty(); if (value != null && !value.isEmpty()) { getLog().debug("Adding to SRE manifest: " + name + " = " + value); //$NON-NLS-1$//$NON-NLS-2$ final Map<String, Attributes> entries = manifest.getEntries(); Attributes attrs = entries.get(SREConstants.MANIFEST_SECTION_SRE); if (attrs == null) { attrs = new Attributes(); entries.put(SREConstants.MANIFEST_SECTION_SRE, attrs); } attrs.put(new Attributes.Name(name), value); } } @Override public void addMainAttribute(String name, String value) { assert name != null && !name.isEmpty(); if (value != null && !value.isEmpty()) { getLog().debug("Adding to SRE manifest: " + name + " = " + value); //$NON-NLS-1$//$NON-NLS-2$ manifest.getMainAttributes().put(new Attributes.Name(name), value); } } }; } buildManifest(updater, mainClass); return manifest; } /** Create the configuration of the SRE with the maven archive format. * * @return the created manifest. * @throws MojoExecutionException if the mojo fails. * @throws MojoFailureException if the generation fails. */ protected Xpp3Dom createSREConfiguration() throws MojoExecutionException, MojoFailureException { final Xpp3Dom xmlConfiguration = new Xpp3Dom("configuration"); //$NON-NLS-1$ final Xpp3Dom xmlArchive = new Xpp3Dom("archive"); //$NON-NLS-1$ xmlConfiguration.addChild(xmlArchive); final String mainClass = getMainClass(); if (mainClass.isEmpty()) { throw new MojoFailureException("the main class of the SRE is missed"); //$NON-NLS-1$ } final Xpp3Dom xmlManifest = new Xpp3Dom("manifest"); //$NON-NLS-1$ xmlArchive.addChild(xmlManifest); final Xpp3Dom xmlManifestMainClass = new Xpp3Dom("mainClass"); //$NON-NLS-1$ xmlManifestMainClass.setValue(mainClass); xmlManifest.addChild(xmlManifestMainClass); final Xpp3Dom xmlSections = new Xpp3Dom("manifestSections"); //$NON-NLS-1$ xmlArchive.addChild(xmlSections); final Xpp3Dom xmlSection = new Xpp3Dom("manifestSection"); //$NON-NLS-1$ xmlSections.addChild(xmlSection); final Xpp3Dom xmlSectionName = new Xpp3Dom("name"); //$NON-NLS-1$ xmlSectionName.setValue(SREConstants.MANIFEST_SECTION_SRE); xmlSection.addChild(xmlSectionName); final Xpp3Dom xmlManifestEntries = new Xpp3Dom("manifestEntries"); //$NON-NLS-1$ xmlSection.addChild(xmlManifestEntries); ManifestUpdater updater = getManifestUpdater(); if (updater == null) { updater = new ManifestUpdater() { @Override public void addSREAttribute(String name, String value) { assert name != null && !name.isEmpty(); if (value != null && !value.isEmpty()) { getLog().debug("Adding to SRE manifest: " + name + " = " + value); //$NON-NLS-1$//$NON-NLS-2$ final Xpp3Dom xmlManifestEntry = new Xpp3Dom(name); xmlManifestEntry.setValue(value); xmlManifestEntries.addChild(xmlManifestEntry); } } @Override public void addMainAttribute(String name, String value) { // } }; } buildManifest(updater, mainClass); return xmlConfiguration; } private void buildManifest(ManifestUpdater updater, String mainClass) { updater.addMainAttribute(SREConstants.MANIFEST_MAIN_CLASS, mainClass); updater.addMainAttribute(SREConstants.MANIFEST_CLASS_PATH, ""); //$NON-NLS-1$ final String name = getSreName(); if (name.isEmpty()) { getLog().debug("Configuring anonymous SRE"); //$NON-NLS-1$ } else { getLog().debug("Configuring SRE \"" + name + "\""); //$NON-NLS-1$ //$NON-NLS-2$ } final CommandLineOptions cmd = getCommandLineOptions(); updater.addSREAttribute(SREConstants.MANIFEST_SARL_SPEC_VERSION, getSarlSpecificationVersion()); updater.addSREAttribute(SREConstants.MANIFEST_SRE_NAME, name); updater.addSREAttribute(SREConstants.MANIFEST_STANDALONE_SRE, Boolean.toString(isStandaloneSRE())); updater.addSREAttribute(SREConstants.MANIFEST_CLI_SRE_OFFLINE, cmd.getOffline()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_RANDOM_CONTEXT_ID, cmd.getRandomContextId()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_BOOT_AGENT_CONTEXT_ID, cmd.getBootAgentContextId()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_DEFAULT_CONTEXT_ID, cmd.getDefaultContextId()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_HIDE_LOGO, cmd.getHideLogo()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_SHOW_LOGO, cmd.getShowLogo()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_HIDE_INFO, cmd.getHideInfo()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_SHOW_INFO, cmd.getShowInfo()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_NO_MORE_OPTION, cmd.getNoMoreOption()); updater.addSREAttribute(SREConstants.MANIFEST_CLI_EMBEDDED, cmd.getEmbedded()); updater.addSREAttribute(SREConstants.MANIFEST_VM_ARGUMENTS, getVmArguments()); updater.addSREAttribute(SREConstants.MANIFEST_PROGRAM_ARGUMENTS, getApplicationArguments()); } /** An updater for manifest. * * @author $Author: sgalland$ * @version $FullVersion$ * @mavengroupid $GroupId$ * @mavenartifactid $ArtifactId$ */ public interface ManifestUpdater { /** Add an attribute to the SRE section. * * @param name the name of the attribute. * @param value the value of the attribute. */ void addSREAttribute(String name, String value); /** Add an attribute to the main section. * * @param name the name of the attribute. * @param value the value of the attribute. */ void addMainAttribute(String name, String value); } }