blob: e73f6119f88ecd9efd7035f51cec184515a39621 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.sling.maven.slingstart;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.felix.cm.file.ConfigurationHandler;
import org.apache.maven.MavenExecutionException;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
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.plugins.annotations.ResolutionScope;
import org.apache.sling.commons.osgi.BSNRenamer;
import org.apache.sling.provisioning.model.ArtifactGroup;
import org.apache.sling.provisioning.model.Configuration;
import org.apache.sling.provisioning.model.Feature;
import org.apache.sling.provisioning.model.FeatureTypes;
import org.apache.sling.provisioning.model.Model;
import org.apache.sling.provisioning.model.ModelConstants;
import org.apache.sling.provisioning.model.RunMode;
import org.apache.sling.provisioning.model.Section;
import org.apache.sling.provisioning.model.io.ModelWriter;
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.archiver.UnArchiver;
import org.codehaus.plexus.archiver.manager.ArchiverManager;
import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
import org.codehaus.plexus.util.FileUtils;
/**
* Prepare the packaging of the Sling quickstart artifact (either JAR or WAR).
*/
@Mojo(
name = "prepare-package",
defaultPhase = LifecyclePhase.PROCESS_SOURCES,
requiresDependencyResolution = ResolutionScope.TEST,
threadSafe = true
)
public class PreparePackageMojo extends AbstractSlingStartMojo {
private static final String ALL_RUNMODES_KEY = "_all_";
private static final String BASE_DESTINATION = "resources";
private static final String BOOT_DIRECTORY = "bundles";
private static final String ARTIFACTS_DIRECTORY = "install";
private static final String CONFIG_DIRECTORY = "config";
private static final String PROVISIONING_DIRECTORY = "provisioning";
private static final String EMBEDDED_MODEL_FILENAME = "model.txt";
private static final String BOOTSTRAP_FILE = "sling_bootstrap.txt";
private static final String PROPERTIES_FILE = "sling_install.properties";
/**
* If set to {@code true} creates a WAR artifact in addition to the standalone JAR from the model.
*/
@Parameter(defaultValue="false")
protected boolean createWebapp;
/**
* To look up Archiver/UnArchiver implementations
*/
@Component
private ArchiverManager archiverManager;
@Component
private ArtifactHandlerManager artifactHandlerManager;
/**
* Used to look up Artifacts in the remote repository.
*
*/
@Component
private ArtifactResolver resolver;
@Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
protected MojoExecution mojoExecution;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
final Model model = ProjectHelper.getEffectiveModel(this.project, getResolverOptions());
execute(model);
}
void execute(final Model model) throws MojoExecutionException {
this.prepareGlobal(model);
this.prepareStandaloneApp(model);
this.prepareWebapp(model);
}
/**
* Prepare the global map for the artifacts.
*/
private void prepareGlobal(final Model model) throws MojoExecutionException {
final Map<String, File> globalContentsMap = new HashMap<String, File>();
this.buildContentsMap(model, (String)null, globalContentsMap);
this.project.setContextValue(BuildConstants.CONTEXT_GLOBAL, globalContentsMap);
}
/**
* Prepare the standalone application.
*/
private void prepareStandaloneApp(final Model model) throws MojoExecutionException {
final Map<String, File> contentsMap = new HashMap<String, File>();
this.project.setContextValue(BuildConstants.CONTEXT_STANDALONE, contentsMap);
// unpack base artifact and create settings
final File outputDir = getStandaloneOutputDirectory();
unpackBaseArtifact(model, outputDir, ModelConstants.RUN_MODE_STANDALONE);
this.buildSettings(model, ModelConstants.RUN_MODE_STANDALONE, outputDir);
this.buildBootstrapFile(model, ModelConstants.RUN_MODE_STANDALONE, outputDir);
this.embedModel(model, outputDir);
this.buildContentsMap(model, ModelConstants.RUN_MODE_STANDALONE, contentsMap);
}
/** Embed our model in the created jar file */
private void embedModel(Model model, File outputDir) throws MojoExecutionException {
final File modelDir = new File(new File(outputDir, BASE_DESTINATION), PROVISIONING_DIRECTORY);
modelDir.mkdirs();
final File modelFile = new File(modelDir, EMBEDDED_MODEL_FILENAME);
try {
final FileWriter w = new FileWriter(modelFile);
try {
w.write("# Aggregated provisioning model embedded by " + getClass().getName() + "\n");
ModelWriter.write(w, model);
} finally {
w.flush();
w.close();
}
} catch(IOException ioe) {
throw new MojoExecutionException("Failed to create model file " + modelFile.getAbsolutePath(), ioe);
}
}
/**
* Prepare the web application.
*/
private void prepareWebapp(final Model model) throws MojoExecutionException {
if ( this.createWebapp ) {
final Map<String, File> contentsMap = new HashMap<String, File>();
this.project.setContextValue(BuildConstants.CONTEXT_WEBAPP, contentsMap);
// unpack base artifact and create settings
final File outputDir = new File(this.project.getBuild().getDirectory(), BuildConstants.WEBAPP_OUTDIR);
final File webappDir = new File(outputDir, "WEB-INF");
unpackBaseArtifact(model, outputDir, ModelConstants.RUN_MODE_WEBAPP);
// check for web.xml
final Feature webappF = model.getFeature(ModelConstants.FEATURE_LAUNCHPAD);
if ( webappF != null ) {
final RunMode webappRM = webappF.getRunMode();
if ( webappRM != null ) {
final Configuration webConfig = webappRM.getConfiguration(ModelConstants.CFG_LAUNCHPAD_WEB_XML);
if ( webConfig != null ) {
final File webXML = new File(webappDir, "web.xml");
try {
FileUtils.fileWrite(webXML, webConfig.getProperties().get(ModelConstants.CFG_LAUNCHPAD_WEB_XML).toString());
} catch (final IOException e) {
throw new MojoExecutionException("Unable to write configuration to " + webXML, e);
}
}
}
}
this.buildSettings(model, ModelConstants.RUN_MODE_WEBAPP, webappDir);
this.buildBootstrapFile(model, ModelConstants.RUN_MODE_WEBAPP, webappDir);
this.embedModel(model, webappDir);
this.buildContentsMap(model, ModelConstants.RUN_MODE_WEBAPP, contentsMap);
}
}
/**
* Build a list of all artifacts.
*/
private void buildContentsMap(final Model model, final String packageRunMode, final Map<String, File> contentsMap)
throws MojoExecutionException {
if ( packageRunMode == null ) {
// add base jar
final Artifact artifact = getBaseArtifact(model, null, BuildConstants.TYPE_JAR);
contentsMap.put(BASE_DESTINATION + "/"+ artifact.getArtifactId() + "." + artifact.getArtifactHandler().getExtension(), artifact.getFile());
}
for(final Feature feature : model.getFeatures()) {
if ( feature.isSpecial() && !feature.getName().equals(ModelConstants.FEATURE_BOOT)) {
continue;
} else if (FeatureTypes.SUBSYSTEM_APPLICATION.equals(feature.getType()) ||
FeatureTypes.SUBSYSTEM_COMPOSITE.equals(feature.getType()) ||
FeatureTypes.SUBSYSTEM_FEATURE.equals(feature.getType())) {
buildSubsystemBase(contentsMap, feature);
} else {
for(final RunMode runMode : feature.getRunModes()) {
if ( packageRunMode == null ) {
if ( runMode.isSpecial() ) {
continue;
}
this.buildContentsMap(model, runMode, contentsMap, feature.getName().equals(ModelConstants.FEATURE_BOOT));
} else {
if ( runMode.isRunMode(packageRunMode) ) {
this.buildContentsMap(model, runMode, contentsMap, feature.getName().equals(ModelConstants.FEATURE_BOOT));
}
}
}
}
}
}
private void buildSubsystemBase(final Map<String, File> contentsMap, final Feature feature) throws MojoExecutionException {
AtomicInteger startLevelHolder = new AtomicInteger(); // Used as output argument
File subsystemFile = createSubsystemBaseFile(feature, startLevelHolder);
if (subsystemFile != null)
contentsMap.put(getPathForArtifact(startLevelHolder.get(), subsystemFile.getName()), subsystemFile);
}
/**
* Build a list of all artifacts from this run mode
*/
private void buildContentsMap(final Model model, final RunMode runMode, final Map<String, File> contentsMap, final boolean isBoot)
throws MojoExecutionException{
for(final ArtifactGroup group : runMode.getArtifactGroups()) {
for(final org.apache.sling.provisioning.model.Artifact a : group) {
Artifact artifact = null;
if ( a.getGroupId().equals(this.project.getGroupId())
&& a.getArtifactId().equals(this.project.getArtifactId())
&& a.getVersion().equals(this.project.getVersion()) ) {
for(final Artifact projectArtifact : this.project.getAttachedArtifacts()) {
if ( projectArtifact.getClassifier().equals(a.getClassifier()) ) {
artifact = projectArtifact;
break;
}
}
// check if the artifact is bound already?
if (project.getArtifact().getFile().exists()) {
if (a.getClassifier() != null) {
if (a.getClassifier().equals(project.getArtifact().getClassifier())) {
artifact = project.getArtifact();
} else {
throw new MojoExecutionException(
"Unable to find artifact from same project with the given classifier: " + a.toMvnUrl());
}
} else {
if (project.getArtifact().getClassifier() == null) {
artifact = project.getArtifact();
} else {
throw new MojoExecutionException("Unable to find artifact with no classifier from same project, because the main artifact is bound to classifier " + project.getArtifact().getClassifier());
}
}
} else {
throw new MojoExecutionException("You must not reference artifact " + a.toMvnUrl()
+ " from the model which is not yet available in the phase '" + mojoExecution.getLifecyclePhase()+ ". Make sure to execute this goal after phase 'package'");
}
} else {
artifact = ModelUtils.getArtifact(this.project, this.mavenSession, this.artifactHandlerManager, this.resolver,
a.getGroupId(), a.getArtifactId(), a.getVersion(), a.getType(), a.getClassifier());
}
File artifactFile = artifact.getFile();
String newBSN = a.getMetadata().get("bundle:rename-bsn");
if (newBSN != null) {
try {
getTmpDir().mkdirs();
artifactFile = new BSNRenamer(artifactFile, getTmpDir(), newBSN).process();
} catch (IOException e) {
throw new MojoExecutionException("Unable to rename bundle BSN to " + newBSN + " for " + artifactFile, e);
}
}
contentsMap.put(getPathForArtifact(group.getStartLevel(), artifactFile.getName(), runMode, isBoot), artifactFile);
}
}
final File rootConfDir = new File(this.getTmpDir(), "global-config");
boolean hasConfig = false;
for(final Configuration config : runMode.getConfigurations()) {
// skip special configurations
if ( config.isSpecial() ) {
continue;
}
final String configPath = getPathForConfiguration(config, runMode);
final File configFile = new File(rootConfDir, configPath);
getLog().debug(String.format("Creating configuration at %s", configFile.getPath()));
configFile.getParentFile().mkdirs();
try {
final FileOutputStream os = new FileOutputStream(configFile);
try {
ConfigurationHandler.write(os, config.getProperties());
} finally {
os.close();
}
} catch (final IOException e) {
throw new MojoExecutionException("Unable to write configuration to " + configFile, e);
}
hasConfig = true;
}
if ( hasConfig ) {
contentsMap.put(BASE_DESTINATION, rootConfDir);
}
}
private File createSubsystemBaseFile(Feature feature, AtomicInteger startLevelHolder) throws MojoExecutionException {
File subsystemFile = new File(getTmpDir(), feature.getName() + ".subsystem-base");
if (subsystemFile.exists()) {
// This subsystem has already been created
// TODO is there a better way to avoid calling this multiple times?
return null;
}
startLevelHolder.set(-1);
// The runmodes information has to be the first item in the archive so that we always have it available when the
// archive is being processed. For this reason a Jar file is used here as it's guaranteed to store the manifest
// first.
Manifest runModesManifest = getRunModesManifest(feature);
getLog().info("Creating subsystem base file: " + subsystemFile.getName());
boolean created = subsystemFile.getParentFile().mkdirs();
if ( !created ) {
throw new MojoExecutionException("Failed creating " + subsystemFile.getParentFile().getAbsolutePath());
}
try (JarOutputStream os = new JarOutputStream(new FileOutputStream(subsystemFile), runModesManifest)) {
Map<String, Integer> bsnStartOrderMap = new HashMap<>();
for (RunMode rm : feature.getRunModes()) {
for (ArtifactGroup ag : rm.getArtifactGroups()) {
int startOrder = ag.getStartLevel(); // For subsystems the start level on the artifact group is used as start order.
for (org.apache.sling.provisioning.model.Artifact a : ag) {
Artifact artifact = ModelUtils.getArtifact(this.project, this.mavenSession, this.artifactHandlerManager, this.resolver,
a.getGroupId(), a.getArtifactId(), a.getVersion(), a.getType(), a.getClassifier());
File artifactFile = artifact.getFile();
String entryName = getEntryName(artifactFile, startOrder);
ZipEntry ze = new ZipEntry(entryName);
try {
os.putNextEntry(ze);
Files.copy(artifactFile.toPath(), os);
} finally {
os.closeEntry();
}
}
}
}
int sl = createSubsystemManifest(feature, bsnStartOrderMap, os);
if (sl != -1)
startLevelHolder.set(sl);
addReadme(os);
} catch (IOException ioe) {
throw new MojoExecutionException("Problem creating subsystem .esa file " + subsystemFile, ioe);
}
return subsystemFile;
}
private Manifest getRunModesManifest(Feature feature) throws MojoExecutionException {
Map<String, StringBuilder> runModes = new HashMap<>();
for (RunMode rm : feature.getRunModes()) {
for (ArtifactGroup ag : rm.getArtifactGroups()) {
int startOrder = ag.getStartLevel(); // For subsystems the start level on the artifact group is used as start order.
for (org.apache.sling.provisioning.model.Artifact a : ag) {
Artifact artifact = ModelUtils.getArtifact(this.project, this.mavenSession, this.artifactHandlerManager, this.resolver,
a.getGroupId(), a.getArtifactId(), a.getVersion(), a.getType(), a.getClassifier());
File artifactFile = artifact.getFile();
String entryName = getEntryName(artifactFile, startOrder);
String [] runModeNames = rm.getNames();
if (runModeNames == null)
runModeNames = new String[] {ALL_RUNMODES_KEY};
for (String runModeName : runModeNames) {
StringBuilder sb = runModes.get(runModeName);
if (sb == null) {
sb = new StringBuilder();
runModes.put(runModeName, sb);
} else {
sb.append('|');
}
sb.append(entryName);
}
}
}
}
Manifest mf = new Manifest();
Attributes attrs = mf.getMainAttributes();
attrs.putValue("Manifest-Version", "1.0"); // Manifest does not work without this value
attrs.putValue("About-This-Manifest", "This is not a real manifest, it is used as information when this archive is transformed into a real subsystem .esa file");
for (Map.Entry<String, StringBuilder> entry : runModes.entrySet()) {
attrs.putValue(entry.getKey().replace(':', '_'), entry.getValue().toString());
}
return mf;
}
private String getEntryName(File artifactFile, int startOrder) {
return "Potential_Bundles/" + startOrder + "/" + artifactFile.getName();
}
// This manifest will be used as the basis for the OSGI-INF/SUBSYSTEM.MF file when the real
// .esa file is generated. However since some contents of that file depend on the actual
// runmode that is being executed, additional information will be added to the SUBSYSTEM.MF
// file at startup time before it's finalized (example: Subsystem-Content).
private int createSubsystemManifest(Feature feature,
Map<String, Integer> startOrderMap, ZipOutputStream os) throws IOException {
int subsystemStartLevel = -1;
ZipEntry ze = new ZipEntry("SUBSYSTEM-MANIFEST-BASE.MF");
try {
os.putNextEntry(ze);
Manifest mf = new Manifest();
Attributes attributes = mf.getMainAttributes();
attributes.putValue("Manifest-Version", "1.0"); // Manifest does not work without this value
attributes.putValue("Subsystem-SymbolicName", feature.getName());
attributes.putValue("Subsystem-Version", "1"); // Version must be an integer (cannot be a long), TODO better idea?
attributes.putValue("Subsystem-Type", feature.getType());
for (Section section : feature.getAdditionalSections("subsystem-manifest")) {
String sl = section.getAttributes().get("startLevel");
try {
subsystemStartLevel = Integer.parseInt(sl);
} catch (NumberFormatException nfe) {
// Not a valid start level
}
BufferedReader br = new BufferedReader(new StringReader(section.getContents()));
String line = null;
while ((line = br.readLine()) != null) {
int idx = line.indexOf(':');
if (idx > 0) {
String key = line.substring(0, idx);
String value;
idx++;
if (line.length() > idx)
value = line.substring(idx);
else
value = "";
attributes.putValue(key.trim(), value.trim());
}
}
}
mf.write(os);
} finally {
os.closeEntry();
}
return subsystemStartLevel;
}
private void addReadme(ZipOutputStream os) throws IOException {
ZipEntry ze = new ZipEntry("readme.txt");
try (InputStream is = getClass().getResourceAsStream("/subsystem-base/readme.txt")) {
os.putNextEntry(ze);
IOUtils.copy(is, os);
} finally {
os.closeEntry();
}
}
/**
* Build the settings for the given packaging run mode
*/
private void buildSettings(final Model model, final String packageRunMode, final File outputDir)
throws MojoExecutionException {
final Properties settings = new Properties();
final Feature launchpadFeature = model.getFeature(ModelConstants.FEATURE_LAUNCHPAD);
if ( launchpadFeature != null ) {
final RunMode launchpadRunMode = launchpadFeature.getRunMode();
if ( launchpadRunMode != null ) {
for(final Map.Entry<String, String> entry : launchpadRunMode.getSettings()) {
settings.put(entry.getKey(), deescapeVariablePlaceholders(entry.getValue()));
}
}
}
final Feature bootFeature = model.getFeature(ModelConstants.FEATURE_BOOT);
if ( bootFeature != null ) {
final RunMode bootRunMode = bootFeature.getRunMode();
if ( bootRunMode != null ) {
for(final Map.Entry<String, String> entry : bootRunMode.getSettings()) {
settings.put(entry.getKey(), deescapeVariablePlaceholders(entry.getValue()));
}
}
}
for(final Feature f : model.getFeatures()) {
final RunMode packageRM = f.getRunMode(new String[] {packageRunMode});
if ( packageRM != null ) {
for(final Map.Entry<String, String> entry : packageRM.getSettings()) {
settings.put(entry.getKey(), deescapeVariablePlaceholders(entry.getValue()));
}
}
}
if ( settings.size() > 0 ) {
final File settingsFile = new File(outputDir, PROPERTIES_FILE);
getLog().debug(String.format("Creating settings at %s", settingsFile.getPath()));
FileWriter writer = null;
try {
writer = new FileWriter(settingsFile);
settings.store(writer, null);
} catch ( final IOException ioe ) {
throw new MojoExecutionException("Unable to write properties file.", ioe);
} finally {
IOUtils.closeQuietly(writer);
}
}
}
/**
* Build the bootstrap file for the given packaging run mode
*/
private void buildBootstrapFile(final Model model, final String packageRunMode, final File outputDir)
throws MojoExecutionException {
final StringBuilder sb = new StringBuilder();
final Feature launchpadFeature = model.getFeature(ModelConstants.FEATURE_LAUNCHPAD);
if ( launchpadFeature != null ) {
final RunMode launchpadRunMode = launchpadFeature.getRunMode();
if ( launchpadRunMode != null ) {
final Configuration c = launchpadRunMode.getConfiguration(ModelConstants.CFG_LAUNCHPAD_BOOTSTRAP);
if ( c != null ) {
sb.append(c.getProperties().get(c.getPid()));
sb.append('\n');
}
}
final RunMode packageRM = launchpadFeature.getRunMode(new String[] {packageRunMode});
if ( packageRM != null ) {
final Configuration c = packageRM.getConfiguration(ModelConstants.CFG_LAUNCHPAD_BOOTSTRAP);
if ( c != null ) {
sb.append(c.getProperties().get(c.getPid()));
sb.append('\n');
}
}
}
if ( sb.length() > 0 ) {
final File file = new File(outputDir, BOOTSTRAP_FILE);
getLog().debug(String.format("Creating bootstrap file at %s", file.getPath()));
try {
FileUtils.fileWrite(file, sb.toString());
} catch ( final IOException ioe ) {
throw new MojoExecutionException("Unable to write bootstrap file.", ioe);
}
}
}
/**
* Return the base artifact
*/
private Artifact getBaseArtifact(final Model model, final String classifier, final String type) throws MojoExecutionException {
try {
final org.apache.sling.provisioning.model.Artifact baseArtifact = ModelUtils.findBaseArtifact(model);
final Artifact a = ModelUtils.getArtifact(this.project, this.mavenSession, this.artifactHandlerManager, this.resolver,
baseArtifact.getGroupId(),
baseArtifact.getArtifactId(),
baseArtifact.getVersion(),
type,
classifier);
if (a == null) {
throw new MojoExecutionException(
String.format("Project doesn't have a base dependency of groupId %s and artifactId %s",
baseArtifact.getGroupId(), baseArtifact.getArtifactId()));
}
return a;
} catch ( final MavenExecutionException mee) {
throw new MojoExecutionException(mee.getMessage(), mee.getCause());
}
}
/**
* Unpack the base artifact
*/
private void unpackBaseArtifact(final Model model, final File outputDirectory, final String packageRunMode)
throws MojoExecutionException {
final String classifier;
final String type;
if ( ModelConstants.RUN_MODE_STANDALONE.equals(packageRunMode) ) {
classifier = BuildConstants.CLASSIFIER_APP;
type = BuildConstants.TYPE_JAR;
} else {
classifier = BuildConstants.CLASSIFIER_WEBAPP;
type = BuildConstants.TYPE_WAR;
}
final Artifact artifact = this.getBaseArtifact(model, classifier, type);
unpack(artifact.getFile(), outputDirectory);
}
/**
* Unpack a file
*/
private void unpack(final File source, final File destination)
throws MojoExecutionException {
getLog().debug("Unpacking " + source.getPath() + " to\n " + destination.getPath());
try {
destination.mkdirs();
final UnArchiver unArchiver = archiverManager.getUnArchiver(source);
unArchiver.setSourceFile(source);
unArchiver.setDestDirectory(destination);
unArchiver.extract();
} catch (final NoSuchArchiverException e) {
throw new MojoExecutionException("Unable to find archiver for " + source.getPath(), e);
} catch (final ArchiverException e) {
throw new MojoExecutionException("Unable to unpack " + source.getPath(), e);
}
}
private String getPathForArtifact(final int startLevel, final String artifactName) {
return getPathForArtifact(startLevel, artifactName, null, false);
}
/**
* Get the relative path for an artifact.
*/
private String getPathForArtifact(final int startLevel, final String artifactName, final RunMode rm, final boolean isBoot) {
final Set<String> runModesList = new TreeSet<String>();
if ( rm != null && rm.getNames() != null ) {
for(final String mode : rm.getNames()) {
runModesList.add(mode);
}
}
final String runModeExt;
if ( runModesList.size() == 0 || rm.isSpecial() ) {
runModeExt = "";
} else {
final StringBuilder sb = new StringBuilder();
for(final String n : runModesList ) {
sb.append('.');
sb.append(n);
}
runModeExt = sb.toString();
}
if ( isBoot ) {
return String.format("%s/%s/1/%s", BASE_DESTINATION, BOOT_DIRECTORY,
artifactName);
}
return String.format("%s/%s%s/%s/%s", BASE_DESTINATION, ARTIFACTS_DIRECTORY,
runModeExt,
(startLevel == -1 ? 1 : startLevel),
artifactName);
}
/**
* Get the relative path for a configuration
*/
private String getPathForConfiguration(final Configuration config, final RunMode rm) {
final Set<String> runModesList = new TreeSet<String>();
if (rm.getNames() != null ) {
for(final String mode : rm.getNames()) {
runModesList.add(mode);
}
}
final String runModeExt;
if ( runModesList.size() == 0 || rm.isSpecial() ) {
runModeExt = "";
} else {
final StringBuilder sb = new StringBuilder();
boolean first = true;
for(final String n : runModesList ) {
if ( first ) {
sb.append('/');
first = false;
} else {
sb.append('.');
}
sb.append(n);
}
runModeExt = sb.toString();
}
final String mainName = (config.getFactoryPid() != null ? config.getFactoryPid() : config.getPid());
final String alias = (config.getFactoryPid() != null ? "-" + config.getPid() : "");
return String.format("%s/%s%s/%s%s.config", BASE_DESTINATION, CONFIG_DIRECTORY,
runModeExt,
mainName,
alias);
}
/**
* Replace \${var} with ${var}
* @param text String with escaped variables
* @return String with deescaped variables
*/
private String deescapeVariablePlaceholders(String text) {
if (text == null) {
return null;
}
return text.replaceAll("\\\\\\$", "\\$");
}
}