modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java | 20 modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java | 8 modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/task/BundleTask.java | 58 +- modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractBundleType.java | 60 ++ modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ArchiveType.java | 16 modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentType.java | 268 ---------- modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java | 212 +++++++ modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/FileType.java | 12 modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ReplaceType.java | 2 modules/common/ant-bundle/src/main/resources/org/rhq/bundle/antlib.xml | 2 modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java | 9 modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml | 20 modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml | 22 modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java | 24 modules/plugins/ant-bundle/src/test/resources/simple-build.xml | 16 modules/plugins/ant-bundle/src/test/resources/test-bundle.xml | 33 + 16 files changed, 422 insertions(+), 360 deletions(-)
New commits: commit 68643815c277948c0617bfedb7db73550fabc901 Author: Ian P. Springer <ips@jetengine.(none)> Date: Thu May 27 10:39:26 2010 -0400
various reworking of rhq:bundle Ant task as discussed; rename rhq:deployment element to rhq:deploymentUnit (cherry picked from commit 8b50ba816d704ced7668a7fa6aa869416ba0c043)
Conflicts:
modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java modules/plugins/ant-bundle/src/test/resources/test-build.xml
diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java index 7c4925b..93e0a6a 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java @@ -46,7 +46,7 @@ import org.apache.tools.ant.helper.AntXMLContext; import org.apache.tools.ant.helper.ProjectHelper2;
import org.rhq.bundle.ant.task.BundleTask; -import org.rhq.bundle.ant.type.DeploymentType; +import org.rhq.bundle.ant.type.DeploymentUnitType;
/** * This object enables you to invoke an Ant script within the running VM. You can fully run the script @@ -69,14 +69,11 @@ public class AntLauncher {
// TODO (ips, 04/28/10): Figure out a way to avoid assuming the prefix is "rhq". private static final String BUNDLE_TASK_NAME = "rhq:bundle"; - private static final String INPUT_PROPERTY_TASK_NAME = "rhq:input-property"; - private static final String DEPLOY_TASK_NAME = "rhq:deploy";
/** * Executes the specified bundle deploy Ant build file (i.e. rhq-deploy.xml). * * @param buildFile the path to the build file (i.e. rhq-deploy.xml) - * @param targetName the target to run, <code>null</code> will run the default target * @param buildProperties the properties to pass into Ant * @param buildListeners a list of build listeners (provide callback methods for targetExecuted, taskExecuted, etc.) * @@ -84,8 +81,9 @@ public class AntLauncher { * * @throws InvalidBuildFileException if the build file is invalid */ - public BundleAntProject executeBundleDeployFile(File buildFile, String targetName, Properties buildProperties, - List<BuildListener> buildListeners) throws InvalidBuildFileException { + public BundleAntProject executeBundleDeployFile(File buildFile, Properties buildProperties, + List<BuildListener> buildListeners) + throws InvalidBuildFileException { parseBundleDeployFile(buildFile);
BundleAntProject project = new BundleAntProject(); @@ -121,8 +119,8 @@ public class AntLauncher { // targets. project.executeTarget("");
- // Now execute the target the user actually specified. - project.executeTarget((targetName == null) ? project.getDefaultTarget() : targetName); + // Now execute the default target? + //project.executeTarget(project.getDefaultTarget());
return project; } catch (Exception e) { @@ -228,11 +226,11 @@ public class AntLauncher { }
BundleTask bundleTask = (BundleTask) preconfigureTask(unconfiguredBundleTask); - Collection<DeploymentType> deployments = bundleTask.getDeployments().values(); + Collection<DeploymentUnitType> deployments = bundleTask.getDeploymentUnits().values(); if (deployments.isEmpty()) { - throw new InvalidBuildFileException("The bundle task must contain at least one deployment child element."); + throw new InvalidBuildFileException("The bundle task must contain exactly one rhq:deploymentUnit child element."); } - DeploymentType deployment = deployments.iterator().next(); + DeploymentUnitType deployment = deployments.iterator().next(); Map<File, File> files = deployment.getFiles(); for (File file : files.values()) { project.getBundleFileNames().add(file.getName()); diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java index 7d7959a..bd83825 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java @@ -121,14 +121,6 @@ public class BundleAntProject extends Project { this.deploymentId = deploymentId; }
- public String getDeploymentName() { - return deploymentName; - } - - public void setDeploymentName(String deploymentName) { - this.deploymentName = deploymentName; - } - public DeploymentPhase getDeploymentPhase() { return deploymentPhase; } diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/task/BundleTask.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/task/BundleTask.java index f943c0d..8e3c066 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/task/BundleTask.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/task/BundleTask.java @@ -22,7 +22,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.rhq.bundle.ant.DeployPropertyNames; import org.rhq.bundle.ant.DeploymentPhase; -import org.rhq.bundle.ant.type.DeploymentType; +import org.rhq.bundle.ant.type.DeploymentUnitType; import org.rhq.bundle.ant.type.InputPropertyType;
import java.io.File; @@ -43,7 +43,7 @@ public class BundleTask extends AbstractBundleTask { private String name; private String version; private String description; - private Map<String, DeploymentType> deployments = new HashMap<String, DeploymentType>(); + private Map<String, DeploymentUnitType> deploymentUnits = new HashMap<String, DeploymentUnitType>(); private Set<InputPropertyType> inputProperties = new HashSet<InputPropertyType>();
@Override @@ -63,8 +63,8 @@ public class BundleTask extends AbstractBundleTask { * The RHQ Ant launcher will ensure that the following Ant project properties are defined prior to this method being * invoked: * - * rhq.deploy.name - the {@link org.rhq.core.domain.bundle.BundleDeployment deployment} name - * (e.g. "appserver") + * rhq.deploy.id - the {@link org.rhq.core.domain.bundle.BundleDeployment deployment}'s unique id + * (e.g. "10001") * rhq.deploy.dir - the {@link org.rhq.core.domain.bundle.BundleDeployment deployment} install dir * (e.g. "/opt/jbossas-petstore") * rhq.deploy.phase - the {@link org.rhq.bundle.ant.DeploymentPhase deployment phase} @@ -105,15 +105,10 @@ public class BundleTask extends AbstractBundleTask { getProject().setDeploymentId(deploymentId); log(DeployPropertyNames.DEPLOY_ID + "="" + deploymentId + """, Project.MSG_DEBUG);
- String deploymentName = (String) projectProps.get(DeployPropertyNames.DEPLOY_NAME); - if (deploymentName == null) { - throw new BuildException("Required property [" + DeployPropertyNames.DEPLOY_NAME + "] was not specified."); - } - getProject().setDeploymentName(deploymentName); - DeploymentType deployment = this.deployments.get(deploymentName); - if (deployment == null) { - throw new BuildException("There is no deployment element defined with name '" + deploymentName + "'."); + if (this.deploymentUnits.size() != 1) { + throw new BuildException("The rhq:bundle task must contain exactly one rhq:deploymentUnit element."); } + DeploymentUnitType deploymentUnit = this.deploymentUnits.values().iterator().next();
String deploymentPhaseName = (String) projectProps.get(DeployPropertyNames.DEPLOY_PHASE); if (deploymentPhaseName == null) { @@ -142,28 +137,31 @@ public class BundleTask extends AbstractBundleTask { String dryRunString = (String) projectProps.get(DeployPropertyNames.DEPLOY_DRY_RUN); boolean dryRun = Boolean.valueOf(dryRunString); getProject().setDryRun(dryRun); - - log("Executing '" + deploymentPhase + "' phase for deployment '" + deploymentName + "' from bundle '" - + this.name + "' version " + this.version + " using config " + getProject().getConfiguration() + "..."); + String revertString = (String) projectProps.get(DeployPropertyNames.DEPLOY_REVERT); + boolean revert = Boolean.valueOf(revertString); + String cleanString = (String) projectProps.get(DeployPropertyNames.DEPLOY_CLEAN); + boolean clean = Boolean.valueOf(cleanString); + + log("Executing '" + deploymentPhase + "' phase for deployment with id [" + deploymentId + "] from bundle '" + + this.name + "' version " + this.version + " using config " + + getProject().getConfiguration().toString(true) + " [dryRun=" + dryRun + ", revert=" + revert + + ", clean=" + clean + "]..."); switch (deploymentPhase) { case INSTALL: - String revertString = (String) projectProps.get(DeployPropertyNames.DEPLOY_REVERT); - boolean revert = Boolean.valueOf(revertString); - String cleanString = (String) projectProps.get(DeployPropertyNames.DEPLOY_CLEAN); - boolean clean = Boolean.valueOf(cleanString); - deployment.install(revert, clean); + // TODO: Revert doesn't really make sense for an initial install. + deploymentUnit.install(revert, clean); break; case START: - deployment.start(); + deploymentUnit.start(); break; case STOP: - deployment.stop(); + deploymentUnit.stop(); break; case UPGRADE: - deployment.upgrade(); + deploymentUnit.upgrade(revert, clean); break; case UNINSTALL: - deployment.uninstall(); + deploymentUnit.uninstall(); break; } } @@ -197,12 +195,12 @@ public class BundleTask extends AbstractBundleTask { inputProperty.init(); }
- public void addConfigured(DeploymentType deployment) { - this.deployments.put(deployment.getName(), deployment); + public void addConfigured(DeploymentUnitType deployment) { + this.deploymentUnits.put(deployment.getName(), deployment); }
- public Map<String, DeploymentType> getDeployments() { - return deployments; + public Map<String, DeploymentUnitType> getDeploymentUnits() { + return deploymentUnits; }
/** @@ -233,8 +231,8 @@ public class BundleTask extends AbstractBundleTask { * @throws BuildException if an error occurs */ protected void validateTypes() throws BuildException { - if (this.deployments.isEmpty()) { - throw new BuildException("At least one 'deployment' child element must be specified."); + if (this.deploymentUnits.isEmpty()) { + throw new BuildException("At least one 'rhq:deploymentUnit' child element must be specified."); } } } \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractBundleType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractBundleType.java index 6874a63..cea5df4 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractBundleType.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/AbstractBundleType.java @@ -3,6 +3,10 @@ package org.rhq.bundle.ant.type; import org.apache.tools.ant.types.DataType; import org.rhq.bundle.ant.BundleAntProject;
+import java.io.File; +import java.util.List; +import java.util.regex.Pattern; + /** * */ @@ -11,4 +15,60 @@ public abstract class AbstractBundleType extends DataType { public BundleAntProject getProject() { return (BundleAntProject)super.getProject(); } + + protected static Pattern getPattern(List<FileSet> fileSets) { + if (fileSets == null || fileSets.isEmpty()) { + return null; + } + boolean first = true; + StringBuilder regex = new StringBuilder(); + for (FileSet fileSet : fileSets) { + if (!first) { + regex.append("|"); + } else { + first = false; + } + regex.append("("); + File dir = fileSet.getDir(); + if (dir != null) { + regex.append(dir); + regex.append('/'); + } + if (fileSet.getIncludePatterns().length == 0) { + regex.append(".*"); + } else { + boolean firstIncludePattern = true; + for (String includePattern : fileSet.getIncludePatterns()) { + if (!firstIncludePattern) { + regex.append("|"); + } else { + firstIncludePattern = false; + } + regex.append("("); + for (int i = 0; i < includePattern.length(); i++) { + char c = includePattern.charAt(i); + if (c == '?') { + regex.append('.'); + } else if (c == '*') { + if (i + 1 < includePattern.length()) { + char c2 = includePattern.charAt(++i); + if (c2 == '*') { + regex.append(".*"); + i++; + continue; + } + } + regex.append("[^/]*"); + } else { + regex.append(c); + } + // TODO: Escape backslashes. + } + regex.append(")"); + } + } + regex.append(")"); + } + return Pattern.compile(regex.toString()); + } } diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ArchiveType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ArchiveType.java index 1320630..19aaaf6 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ArchiveType.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ArchiveType.java @@ -22,11 +22,25 @@ */ package org.rhq.bundle.ant.type;
+import java.util.List; +import java.util.regex.Pattern; + /** - * An archive file to be exploded during the bundle deployment. + * An archive file to be exploded during the bundle deployment. Can optionally contain a rhq:replace child element + * that specifies the set of files that contain template variables (e.g. @@http.port@@) which need to be replaced with + * the value of the corresponding property. * * @author Ian Springer */ public class ArchiveType extends AbstractFileType { + private Pattern replacePattern; + + public void addConfigured(ReplaceType replace) { + List<FileSet> fileSets = replace.getFileSets(); + this.replacePattern = getPattern(fileSets); + }
+ public Pattern getReplacePattern() { + return replacePattern; + } } \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentType.java deleted file mode 100644 index db33995..0000000 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentType.java +++ /dev/null @@ -1,268 +0,0 @@ -/* - * RHQ Management Platform - * Copyright (C) 2010 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -package org.rhq.bundle.ant.type; - -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.Target; -import org.rhq.core.domain.configuration.Configuration; -import org.rhq.core.domain.configuration.PropertySimple; -import org.rhq.core.system.SystemInfoFactory; -import org.rhq.core.template.TemplateEngine; -import org.rhq.core.util.updater.DeployDifferences; -import org.rhq.core.util.updater.Deployer; -import org.rhq.core.util.updater.DeploymentData; -import org.rhq.core.util.updater.DeploymentProperties; - -import java.io.File; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Pattern; - -/** - * An Ant task for deploying a bundle or previewing the deployment. - * - * @author Ian Springer - */ -public class DeploymentType extends AbstractBundleType { - private String name; - private Map<File, File> files = new LinkedHashMap<File, File>(); - private Set<File> archives = new LinkedHashSet<File>(); - private SystemServiceType systemService; - private Pattern ignorePattern; - private Pattern replacePattern; - private boolean preview; - private String preinstallTarget; - private String postinstallTarget; - - public void install(boolean revert, boolean clean) throws BuildException { - if (this.preinstallTarget != null) { - Target target = (Target) getProject().getTargets().get(this.preinstallTarget); - if (target == null) { - throw new BuildException("Specified preinstall target (" + this.preinstallTarget + ") does not exist."); - } - target.performTasks(); - } - - int deploymentId = getProject().getDeploymentId(); - DeploymentProperties deploymentProps = new DeploymentProperties(deploymentId, getProject().getBundleName(), - getProject().getBundleVersion(), getProject().getBundleDescription()); - File deployDir = getProject().getDeployDir(); - TemplateEngine templateEngine = createTemplateEngine(); - if (this.files.isEmpty() && this.archives.isEmpty()) { - throw new BuildException("You must specify at least one file to deploy via nested rhq:file and/or rhq:archive elements."); - } - if (!this.files.isEmpty()) { - log("Deploying files " + this.files + "...", Project.MSG_VERBOSE); - } - if (!this.archives.isEmpty()) { - log("Deploying archives " + this.archives + "...", Project.MSG_VERBOSE); - } - - // for now, apply the pattern to all files in the deployment - Map<File, Pattern> archiveReplacePatterns = new HashMap<File, Pattern>(); - for (File file : this.archives) { - archiveReplacePatterns.put(file, this.replacePattern); - } - Set<File> rawFilesToReplace = this.files.keySet(); // TODO: CHANGE ME! only replace those raw files marked as "replace=true" - DeploymentData dd = new DeploymentData(deploymentProps, this.archives, this.files, deployDir, - archiveReplacePatterns, rawFilesToReplace, templateEngine, this.ignorePattern); - Deployer deployer = new Deployer(dd); - try { - DeployDifferences diffs = getProject().getDeployDifferences(); - boolean dryRun = getProject().isDryRun(); - if (revert) { - deployer.redeployAndRestoreBackupFiles(diffs, clean, dryRun); - } else { - deployer.deploy(diffs, clean, dryRun); - } - deployer.deploy(diffs); - getProject().log("Results:\n" + diffs + "\n"); - } catch (Exception e) { - throw new BuildException("Failed to deploy bundle '" + getProject().getBundleName() + "' version " - + getProject().getBundleVersion() + ": " + e, e); - } - - if (this.systemService != null) { - this.systemService.install(); - } - - if (this.postinstallTarget != null) { - Target target = (Target) getProject().getTargets().get(this.postinstallTarget); - if (target == null) { - throw new BuildException("Specified postinstall target (" + this.postinstallTarget + ") does not exist."); - } - target.performTasks(); - } - - return; - } - - public void start() throws BuildException { - - } - - public void stop() throws BuildException { - - } - - public void upgrade() throws BuildException { - - } - - public void uninstall() throws BuildException { - // TODO - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public Map<File, File> getFiles() { - return files; - } - - public Set<File> getArchives() { - return archives; - } - - public boolean isPreview() { - return this.preview; - } - - public void setPreview(boolean preview) { - this.preview = preview; - } - - public String getPreinstallTarget() { - return preinstallTarget; - } - - public void setPreinstallTarget(String preinstallTarget) { - this.preinstallTarget = preinstallTarget; - } - - public String getPostinstallTarget() { - return postinstallTarget; - } - - public void setPostinstallTarget(String postinstallTarget) { - this.postinstallTarget = postinstallTarget; - } - - public void addConfigured(SystemServiceType systemService) { - if (this.systemService != null) { - throw new IllegalStateException("A deployment can only have one system-service child element."); - } - this.systemService = systemService; - } - - public void addConfigured(FileType file) { - File destFile = file.getDestinationFile(); - if (destFile == null) { - File destDir = file.getDestinationDir(); - destFile = new File(destDir, file.getSource().getName()); - } - this.files.put(file.getSource(), destFile); - } - - public void addConfigured(ArchiveType archive) { - this.archives.add(archive.getSource()); - } - - public void addConfigured(IgnoreType ignore) { - List<FileSet> fileSets = ignore.getFileSets(); - this.ignorePattern = getPattern(fileSets); - } - - public void addConfigured(ReplaceType replace) { - List<FileSet> fileSets = replace.getFileSets(); - this.replacePattern = getPattern(fileSets); - } - - private TemplateEngine createTemplateEngine() { - TemplateEngine templateEngine = SystemInfoFactory.fetchTemplateEngine(); - // Add the deployment props to the template engine's tokens. - Configuration config = getProject().getConfiguration(); - for (PropertySimple prop : config.getSimpleProperties().values()) { - templateEngine.getTokens().put(prop.getName(), prop.getStringValue()); - } - return templateEngine; - } - - private static Pattern getPattern(List<FileSet> fileSets) { - boolean first = true; - StringBuilder regex = new StringBuilder(); - for (FileSet fileSet : fileSets) { - if (!first) { - regex.append("|"); - } else { - first = false; - } - regex.append("("); - File dir = fileSet.getDir(); - if (dir != null) { - regex.append(dir); - regex.append('/'); - } - if (fileSet.getIncludePatterns().length == 0) { - regex.append(".*"); - } else { - boolean firstIncludePattern = true; - for (String includePattern : fileSet.getIncludePatterns()) { - if (!firstIncludePattern) { - regex.append("|"); - } else { - firstIncludePattern = false; - } - regex.append("("); - for (int i = 0; i < includePattern.length(); i++) { - char c = includePattern.charAt(i); - if (c == '?') { - regex.append('.'); - } else if (c == '*') { - if (i + 1 < includePattern.length()) { - char c2 = includePattern.charAt(++i); - if (c2 == '*') { - regex.append(".*"); - i++; - continue; - } - } - regex.append("[^/]*"); - } else { - regex.append(c); - } - // TODO: Escape backslashes. - } - regex.append(")"); - } - } - regex.append(")"); - } - return Pattern.compile(regex.toString()); - } -} \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java new file mode 100644 index 0000000..df72add --- /dev/null +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/DeploymentUnitType.java @@ -0,0 +1,212 @@ +/* + * RHQ Management Platform + * Copyright (C) 2010 Red Hat, Inc. + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +package org.rhq.bundle.ant.type; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Target; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.system.SystemInfoFactory; +import org.rhq.core.template.TemplateEngine; +import org.rhq.core.util.updater.DeployDifferences; +import org.rhq.core.util.updater.Deployer; +import org.rhq.core.util.updater.DeploymentData; +import org.rhq.core.util.updater.DeploymentProperties; + +import java.io.File; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.regex.Pattern; + +/** + * An Ant task for deploying a bundle or previewing the deployment. + * + * @author Ian Springer + */ +public class DeploymentUnitType extends AbstractBundleType { + private String name; + private Map<File, File> files = new LinkedHashMap<File, File>(); + private Set<File> rawFilesToReplace = new LinkedHashSet<File>(); + private Set<File> archives = new LinkedHashSet<File>(); + private Map<File, Pattern> archiveReplacePatterns = new HashMap<File, Pattern>(); + private SystemServiceType systemService; + private Pattern ignorePattern; + private boolean preview; + private String preinstallTarget; + private String postinstallTarget; + + public void install(boolean revert, boolean clean) throws BuildException { + if (this.preinstallTarget != null) { + Target target = (Target) getProject().getTargets().get(this.preinstallTarget); + if (target == null) { + throw new BuildException("Specified preinstall target (" + this.preinstallTarget + ") does not exist."); + } + target.performTasks(); + } + + int deploymentId = getProject().getDeploymentId(); + DeploymentProperties deploymentProps = new DeploymentProperties(deploymentId, getProject().getBundleName(), + getProject().getBundleVersion(), getProject().getBundleDescription()); + File deployDir = getProject().getDeployDir(); + TemplateEngine templateEngine = createTemplateEngine(); + if (this.files.isEmpty() && this.archives.isEmpty()) { + throw new BuildException("You must specify at least one file to deploy via nested rhq:file and/or rhq:archive elements."); + } + if (!this.files.isEmpty()) { + log("Deploying files " + this.files + "...", Project.MSG_VERBOSE); + } + if (!this.archives.isEmpty()) { + log("Deploying archives " + this.archives + "...", Project.MSG_VERBOSE); + } + + DeploymentData deploymentData = new DeploymentData(deploymentProps, this.archives, this.files, deployDir, + this.archiveReplacePatterns, this.rawFilesToReplace, templateEngine, this.ignorePattern); + Deployer deployer = new Deployer(deploymentData); + try { + DeployDifferences diffs = getProject().getDeployDifferences(); + boolean dryRun = getProject().isDryRun(); + if (revert) { + deployer.redeployAndRestoreBackupFiles(diffs, clean, dryRun); + } else { + deployer.deploy(diffs, clean, dryRun); + } + deployer.deploy(diffs); + getProject().log("Results:\n" + diffs + "\n"); + } catch (Exception e) { + throw new BuildException("Failed to deploy bundle '" + getProject().getBundleName() + "' version " + + getProject().getBundleVersion() + ": " + e, e); + } + + if (this.systemService != null) { + this.systemService.install(); + } + + if (this.postinstallTarget != null) { + Target target = (Target) getProject().getTargets().get(this.postinstallTarget); + if (target == null) { + throw new BuildException("Specified postinstall target (" + this.postinstallTarget + ") does not exist."); + } + target.performTasks(); + } + + return; + } + + public void start() throws BuildException { + + } + + public void stop() throws BuildException { + + } + + public void upgrade(boolean revert, boolean clean) throws BuildException { + install(revert, clean); + } + + public void uninstall() throws BuildException { + // TODO + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Map<File, File> getFiles() { + return files; + } + + public Set<File> getArchives() { + return archives; + } + + public boolean isPreview() { + return this.preview; + } + + public void setPreview(boolean preview) { + this.preview = preview; + } + + public String getPreinstallTarget() { + return preinstallTarget; + } + + public void setPreinstallTarget(String preinstallTarget) { + this.preinstallTarget = preinstallTarget; + } + + public String getPostinstallTarget() { + return postinstallTarget; + } + + public void setPostinstallTarget(String postinstallTarget) { + this.postinstallTarget = postinstallTarget; + } + + public void addConfigured(SystemServiceType systemService) { + if (this.systemService != null) { + throw new IllegalStateException("A deployment can only have one system-service child element."); + } + this.systemService = systemService; + } + + public void addConfigured(FileType file) { + File destFile = file.getDestinationFile(); + if (destFile == null) { + File destDir = file.getDestinationDir(); + destFile = new File(destDir, file.getSource().getName()); + } + this.files.put(file.getSource(), destFile); + if (file.isReplace()) { + this.rawFilesToReplace.add(file.getSource()); + } + } + + public void addConfigured(ArchiveType archive) { + this.archives.add(archive.getSource()); + Pattern replacePattern = archive.getReplacePattern(); + if (replacePattern != null) { + this.archiveReplacePatterns.put(archive.getSource(), replacePattern); + } + } + + public void addConfigured(IgnoreType ignore) { + List<FileSet> fileSets = ignore.getFileSets(); + this.ignorePattern = getPattern(fileSets); + } + + private TemplateEngine createTemplateEngine() { + TemplateEngine templateEngine = SystemInfoFactory.fetchTemplateEngine(); + // Add the deployment props to the template engine's tokens. + Configuration config = getProject().getConfiguration(); + for (PropertySimple prop : config.getSimpleProperties().values()) { + templateEngine.getTokens().put(prop.getName(), prop.getStringValue()); + } + return templateEngine; + } +} \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/FileType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/FileType.java index 4e2c296..2e55c0e 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/FileType.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/FileType.java @@ -27,13 +27,15 @@ import org.apache.tools.ant.BuildException; import java.io.File;
/** - * A file to be copied during the bundle deployment. + * A file to be copied during the bundle deployment. If the replace attribute is set to true, any template variables + * (e.g. @@http.port@@) inside the file will be replaced with the value of the corresponding property. * * @author Ian Springer */ public class FileType extends AbstractFileType { private File destinationDir; private File destinationFile; + private boolean replace;
public File getDestinationDir() { return this.destinationDir; @@ -57,4 +59,12 @@ public class FileType extends AbstractFileType { } this.destinationFile = new File(destinationFile); } + + public boolean isReplace() { + return replace; + } + + public void setReplace(boolean replace) { + this.replace = replace; + } } \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ReplaceType.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ReplaceType.java index cdf2b6c..4479d1c 100644 --- a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ReplaceType.java +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/type/ReplaceType.java @@ -22,8 +22,6 @@ */ package org.rhq.bundle.ant.type;
-import org.apache.tools.ant.types.DataType; - import java.util.ArrayList; import java.util.List;
diff --git a/modules/common/ant-bundle/src/main/resources/org/rhq/bundle/antlib.xml b/modules/common/ant-bundle/src/main/resources/org/rhq/bundle/antlib.xml index 9f01c2b..fee46ef 100644 --- a/modules/common/ant-bundle/src/main/resources/org/rhq/bundle/antlib.xml +++ b/modules/common/ant-bundle/src/main/resources/org/rhq/bundle/antlib.xml @@ -8,7 +8,7 @@
<!-- bundle task's child types --> <typedef name="input-property" classname="org.rhq.bundle.ant.type.InputPropertyType"/> - <typedef name="deployment" classname="org.rhq.bundle.ant.type.DeploymentType"/> + <typedef name="deployment-unit" classname="org.rhq.bundle.ant.type.DeploymentUnitType"/>
<!-- deployment type's child types --> <typedef name="file" classname="org.rhq.bundle.ant.type.FileType"/> diff --git a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java index 403bfa2..831bdf9 100644 --- a/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java +++ b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java @@ -74,7 +74,7 @@ public class AntLauncherTest { Properties inputProps = createInputProperties("/test-bundle-v1-input.properties"); List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v1.xml"), null, inputProps, + BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v1.xml"), inputProps, buildListeners); /*Map<String, String> bundleFiles = project.getBundleFiles(); assert bundleFiles != null; @@ -94,6 +94,8 @@ public class AntLauncherTest {
String preinstallTargetExecuted = (String) project.getProperties().get("preinstallTargetExecuted"); assert preinstallTargetExecuted.equals("true"); + String postinstallTargetExecuted = (String) project.getProperties().get("postinstallTargetExecuted"); + assert postinstallTargetExecuted.equals("true"); }
private List<BuildListener> createBuildListeners() { @@ -114,7 +116,7 @@ public class AntLauncherTest { Properties inputProps = createInputProperties("/test-bundle-v2-input.properties"); List<BuildListener> buildListeners = createBuildListeners();
- BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v2.xml"), null, inputProps, + BundleAntProject project = ant.executeBundleDeployFile(getBuildXml("test-bundle-v2.xml"), inputProps, buildListeners); /*Map<String, String> bundleFiles = project.getBundleFiles(); assert bundleFiles != null; @@ -136,8 +138,7 @@ public class AntLauncherTest { private Properties createInputProperties(String resourcePath) throws IOException { Properties inputProps = new Properties(); inputProps.setProperty(DeployPropertyNames.DEPLOY_DIR, DEPLOY_DIR.getPath()); - inputProps.setProperty(DeployPropertyNames.DEPLOY_ID, "100"); - inputProps.setProperty(DeployPropertyNames.DEPLOY_NAME, "appserver"); + inputProps.setProperty(DeployPropertyNames.DEPLOY_ID, "100"); inputProps.setProperty(DeployPropertyNames.DEPLOY_PHASE, DeploymentPhase.INSTALL.name()); InputStream inputStream = this.getClass().getResourceAsStream(resourcePath); try { diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml index 2e63b2c..76820bf 100644 --- a/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml +++ b/modules/common/ant-bundle/src/test/resources/test-bundle-v1.xml @@ -12,20 +12,21 @@ defaultValue="8080" type="integer"/>
- <rhq:deployment name="appserver" preinstallTarget="preinstall"> + <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"> <rhq:system-service name="foo" scriptFile="foo-script" configFile="foo-config" overwriteScript="true" startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/> - <rhq:file name="test-v1.properties" destinationFile="subdir/test.properties"/> - <rhq:archive name="file.zip"/> - rhq:replace - <rhq:fileset includes="**/*.properties"/> - </rhq:replace> + <rhq:file name="test-v1.properties" destinationFile="subdir/test.properties" replace="true"/> + <rhq:archive name="file.zip"> + rhq:replace + <rhq:fileset includes="**/*.properties"/> + </rhq:replace> + </rhq:archive> <!-- the files that should be ignored during upgrades --> rhq:ignore <rhq:fileset includes="*.log"/> </rhq:ignore> - </rhq:deployment> + </rhq:deployment-unit>
</rhq:bundle>
@@ -36,4 +37,9 @@ <property name="preinstallTargetExecuted" value="true"/> </target>
+ <target name="postinstall"> + <echo>Done deploying Test Bundle v1.0 to ${rhq.deploy.dir}.</echo> + <property name="postinstallTargetExecuted" value="true"/> + </target> + </project> \ No newline at end of file diff --git a/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml b/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml index 501ba3f..6764c13 100644 --- a/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml +++ b/modules/common/ant-bundle/src/test/resources/test-bundle-v2.xml @@ -12,28 +12,34 @@ defaultValue="8080" type="integer"/>
- <rhq:deployment name="appserver" preinstallTarget="preinstall"> + <rhq:deployment-unit name="appserver" preinstallTarget="preinstall" postinstallTarget="postinstall"> <rhq:system-service name="foo" scriptFile="foo-script" configFile="foo-config" overwriteScript="true" startLevels="3,4,5" startPriority="80" stopPriority="20" root="root"/> - <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties"/> - <rhq:archive name="file.zip"/> - rhq:replace - <rhq:fileset includes="**/*.properties"/> - </rhq:replace> + <rhq:file name="test-v2.properties" destinationFile="subdir/test.properties" replace="true"/> + <rhq:archive name="file.zip"> + rhq:replace + <rhq:fileset includes="**/*.properties"/> + </rhq:replace> + </rhq:archive> <!-- the files that should be ignored during upgrades --> rhq:ignore <rhq:fileset includes="*.log"/> </rhq:ignore> - </rhq:deployment> + </rhq:deployment-unit>
</rhq:bundle>
<target name="main"/>
<target name="preinstall"> - <echo>Deploying Test Bundle v2.0 to ${rhq.deploy.dir}...</echo> + <echo>Deploying Test Bundle v1.0 to ${rhq.deploy.dir}...</echo> <property name="preinstallTargetExecuted" value="true"/> </target>
+ <target name="postinstall"> + <echo>Done deploying Test Bundle v1.0 to ${rhq.deploy.dir}.</echo> + <property name="postinstallTargetExecuted" value="true"/> + </target> + </project> \ No newline at end of file diff --git a/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java index 2eb1d85..f030cf0 100644 --- a/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java +++ b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java @@ -36,6 +36,8 @@ import org.apache.tools.ant.Project; import org.rhq.bundle.ant.AntLauncher; import org.rhq.bundle.ant.BundleAntProject; import org.rhq.bundle.ant.DeployPropertyNames; +import org.rhq.bundle.ant.DeploymentPhase; +import org.rhq.bundle.ant.InvalidBuildFileException; import org.rhq.bundle.ant.LoggerAntBuildListener; import org.rhq.core.domain.bundle.BundleDeployment; import org.rhq.core.domain.bundle.BundleResourceDeployment; @@ -54,6 +56,8 @@ import org.rhq.core.pluginapi.inventory.ResourceContext; import org.rhq.core.system.SystemInfoFactory; import org.rhq.core.util.stream.StreamUtil; import org.rhq.core.util.updater.DeployDifferences; +import org.rhq.core.util.updater.Deployer; +import org.rhq.core.util.updater.DeploymentsMetadata;
/** * @author John Mazzitelli @@ -121,9 +125,17 @@ public class AntBundlePluginComponent implements ResourceComponent, BundleFacet buildListeners.add(auditor);
// Parse and execute the Ant script. - AntLauncher antLauncher = new AntLauncher(); - BundleAntProject project = antLauncher.executeBundleDeployFile(recipeFile, null, antProps, - buildListeners); + executeDeploymentPhase(recipeFile, antProps, buildListeners, + DeploymentPhase.STOP); + String deployDirString = bundleDeployment.getDestination().getDeployDir(); + File deployDir = new File(deployDirString); + DeploymentsMetadata deployMetadata = new DeploymentsMetadata(deployDir); + DeploymentPhase installPhase = (deployMetadata.isManaged()) ? DeploymentPhase.UPGRADE : + DeploymentPhase.INSTALL; + BundleAntProject project = executeDeploymentPhase(recipeFile, antProps, buildListeners, + installPhase); + executeDeploymentPhase(recipeFile, antProps, buildListeners, + DeploymentPhase.START);
// Send the diffs to the Server so it can store them as an entry in the deployment history. BundleManagerProvider bundleManagerProvider = request.getBundleManagerProvider(); @@ -153,6 +165,12 @@ public class AntBundlePluginComponent implements ResourceComponent, BundleFacet return result; }
+ private BundleAntProject executeDeploymentPhase(File recipeFile, Properties antProps, List<BuildListener> buildListeners, DeploymentPhase stop) throws InvalidBuildFileException { + AntLauncher antLauncher = new AntLauncher(); + BundleAntProject project = antLauncher.executeBundleDeployFile(recipeFile, antProps, buildListeners); + return project; + } + private Properties createAntProperties(BundleDeployRequest request) { Properties antProps = new Properties();
diff --git a/modules/plugins/ant-bundle/src/test/resources/simple-build.xml b/modules/plugins/ant-bundle/src/test/resources/simple-build.xml deleted file mode 100644 index 88ade87..0000000 --- a/modules/plugins/ant-bundle/src/test/resources/simple-build.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0"?> - -<project name="test" default="init" - xmlns:rhq="antlib:org.rhq.bundle"> - - <rhq:bundle name="example.com (JBoss EAP 4.3)" version="1.0" - description="example.com corporate website hosted on JBoss EAP 4.3"/> - - <property name="outfile" value="${basedir}/output.1" /> - - <target name="init"> - <echo file="${outfile}" message="Hello World!!"/> - </target> - -</project> - \ No newline at end of file diff --git a/modules/plugins/ant-bundle/src/test/resources/test-bundle.xml b/modules/plugins/ant-bundle/src/test/resources/test-bundle.xml new file mode 100644 index 0000000..f51fae3 --- /dev/null +++ b/modules/plugins/ant-bundle/src/test/resources/test-bundle.xml @@ -0,0 +1,33 @@ +<?xml version="1.0"?> + +<project name="simple-build" default="main" + xmlns:rhq="antlib:org.rhq.bundle"> + + <echo>basedir=${basedir}</echo> + + <property name="outfile" value="${basedir}/output.2" /> + + <rhq:bundle name="example.com (JBoss EAP 4.3)" version="1.0" + description="example.com corporate website hosted on JBoss EAP 4.3"> + + <rhq:input-property + name="custom.prop1" + description="my prop 1" + required="true" + defaultValue="default 1"/> + + <rhq:input-property + name="custom.prop2" + description="my prop 2" + required="true" + defaultValue="default 2"/> + + <rhq:deployment-unit name="doodibittydoo"> + <rhq:file name="test.properties" destinationFile="config/test.properties" replace="true"/> + </rhq:deployment-unit> + + </rhq:bundle> + + <target name="main"/> + +</project> \ No newline at end of file
rhq-commits@lists.fedorahosted.org