org.rhq.enterprise.server.plugins.ant.AntBundleServerPluginComponent Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rhq-serverplugin-ant-bundle Show documentation
Show all versions of rhq-serverplugin-ant-bundle Show documentation
Server side plugin that manages ant-scripted bundles
The newest version!
/*
* RHQ Management Platform
* Copyright (C) 2005-2014 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.enterprise.server.plugins.ant;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.bundle.ant.AntLauncher;
import org.rhq.bundle.ant.BundleAntProject;
import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
import org.rhq.core.util.ZipUtil;
import org.rhq.core.util.file.FileUtil;
import org.rhq.core.util.stream.StreamUtil;
import org.rhq.core.util.updater.DeploymentProperties;
import org.rhq.enterprise.server.bundle.BundleDistributionInfo;
import org.rhq.enterprise.server.bundle.RecipeParseResults;
import org.rhq.enterprise.server.plugin.pc.ServerPluginComponent;
import org.rhq.enterprise.server.plugin.pc.ServerPluginContext;
import org.rhq.enterprise.server.plugin.pc.bundle.BundleServerPluginFacet;
import org.rhq.enterprise.server.plugin.pc.bundle.UnknownRecipeException;
/**
* A bundle server-side plugin component that the server uses to process Ant-based bundles.
*
* @author John Mazzitelli
*/
public class AntBundleServerPluginComponent implements ServerPluginComponent, BundleServerPluginFacet {
private static final Log LOG = LogFactory.getLog(AntBundleServerPluginComponent.class);
private ServerPluginContext context;
private File tmpDirectory;
@Override
public void initialize(ServerPluginContext context) throws Exception {
this.context = context;
this.tmpDirectory = new File(this.context.getTemporaryDirectory(), "ant-bundle-server-plugin");
//noinspection ResultOfMethodCallIgnored
this.tmpDirectory.mkdirs();
if (!this.tmpDirectory.exists() || !this.tmpDirectory.isDirectory()) {
throw new Exception("Failed to create tmp dir [" + this.tmpDirectory + "] - cannot process Ant bundles");
}
if (LOG.isDebugEnabled()) {
LOG.debug("The Ant bundle plugin has been initialized: " + this);
}
}
@Override
public void start() {
if (LOG.isDebugEnabled()) {
LOG.debug("The Ant bundle plugin has started: " + this);
}
}
@Override
public void stop() {
if (LOG.isDebugEnabled()) {
LOG.debug("The Ant bundle plugin has stopped: " + this);
}
}
@Override
public void shutdown() {
if (LOG.isDebugEnabled()) {
LOG.debug("The Ant bundle plugin has been shut down: " + this);
}
}
@Override
public RecipeParseResults parseRecipe(String recipe) throws Exception {
// all Ant recipes must use the RHQ custom ant library; if the recipe doesn't have the
// string of that antlib URI, that means this probably isn't an Ant recipe in the first place
if (!recipe.contains("antlib:org.rhq.bundle")) {
throw new UnknownRecipeException("Not a valid Ant recipe");
}
DeploymentProperties deploymentProps;
Set bundleFiles;
ConfigurationDefinition configDef;
RecipeParseResults results;
File recipeFile = File.createTempFile("ant-bundle-recipe", ".xml", this.tmpDirectory);
File logFile = File.createTempFile("ant-bundle-recipe", ".log", this.tmpDirectory);
try {
// store the recipe in the tmp recipe file
ByteArrayInputStream in = new ByteArrayInputStream(recipe.getBytes());
FileOutputStream out = new FileOutputStream(recipeFile);
StreamUtil.copy(in, out);
// parse, but do not execute, the Ant script
AntLauncher antLauncher = new AntLauncher(true);
BundleAntProject project = antLauncher.parseBundleDeployFile(recipeFile, null);
// obtain the parse results
deploymentProps = new DeploymentProperties(0, project.getBundleName(), project.getBundleVersion(),
project.getBundleDescription(), project.getDestinationCompliance());
bundleFiles = project.getBundleFileNames();
configDef = project.getConfigurationDefinition();
} catch (Throwable t) {
if (LOG.isDebugEnabled()) {
try {
LOG.debug(new String(StreamUtil.slurp(new FileInputStream(logFile))));
} catch (Exception ignore) {
}
}
throw new Exception("Failed to parse the bundle Ant script.", t);
} finally {
recipeFile.delete();
logFile.delete();
}
results = new RecipeParseResults(deploymentProps, configDef, bundleFiles);
return results;
}
@Override
public BundleDistributionInfo processBundleDistributionFile(File distributionFile) throws Exception {
if (null == distributionFile) {
throw new IllegalArgumentException("distributionFile == null");
}
// try and parse the recipe, if successful then process the distributionFile completely
RecipeVisitor recipeVisitor = new RecipeVisitor(this, "deploy.xml");
ZipUtil.walkZipFile(distributionFile, recipeVisitor);
String recipe = recipeVisitor.getRecipe();
RecipeParseResults recipeParseResults = recipeVisitor.getResults();
if (null == recipeParseResults) {
throw new UnknownRecipeException("Not an Ant Bundle");
}
// if we parsed the recipe then this is a distribution we can deal with, get the bundle file Map
BundleFileVisitor bundleFileVisitor = new BundleFileVisitor(recipeParseResults.getBundleFileNames());
ZipUtil.walkZipFile(distributionFile, bundleFileVisitor);
return new BundleDistributionInfo(recipe, recipeParseResults, bundleFileVisitor.getBundleFiles());
}
private static class RecipeVisitor implements ZipUtil.ZipEntryVisitor {
private RecipeParseResults results = null;
private String recipeName = null;
private BundleServerPluginFacet facet = null;
private String recipe = null;
public RecipeVisitor(BundleServerPluginFacet facet, String recipeName) {
this.facet = facet;
this.recipeName = recipeName;
}
@Override
public boolean visit(ZipEntry entry, ZipInputStream stream) throws Exception {
if (this.recipeName.equalsIgnoreCase(entry.getName())) {
// this should be safe downcast, recipes are not that big
int contentSize = (int) entry.getSize();
ByteArrayOutputStream out = new ByteArrayOutputStream((contentSize > 0) ? contentSize : 32768);
StreamUtil.copy(stream, out, false);
this.recipe = new String(out.toByteArray());
//noinspection UnusedAssignment
out = null; // no need for this anymore, help out GC
this.results = this.facet.parseRecipe(this.recipe);
return false; // we found the file we are looking for so stop walking
}
return true;
}
public RecipeParseResults getResults() {
return results;
}
public String getRecipe() {
return recipe;
}
}
private static class BundleFileVisitor implements ZipUtil.ZipEntryVisitor {
private Set bundleFileNames;
private Map bundleFiles;
private File tmpDir;
BundleFileVisitor(Set bundleFileNames) throws IOException {
this.bundleFileNames = bundleFileNames;
this.bundleFiles = new HashMap(bundleFileNames.size());
this.tmpDir = FileUtil.createTempDirectory("ant-bundle", ".dir", null);
}
@Override
public boolean visit(ZipEntry entry, ZipInputStream stream) throws Exception {
if (bundleFileNames.contains(entry.getName())) {
File bundleFile = new File(tmpDir, entry.getName());
bundleFile.getParentFile().mkdirs();
FileOutputStream fos = null;
try {
fos = new FileOutputStream(bundleFile);
StreamUtil.copy(stream, fos, false);
} finally {
if (null != fos) {
try {
fos.close();
} catch (Exception e) {
//
}
}
}
this.bundleFiles.put(entry.getName(), bundleFile);
}
return true;
}
public Map getBundleFiles() {
return bundleFiles;
}
}
@Override
public String toString() {
if (this.context == null) {
return "";
}
return "plugin-key=" + this.context.getPluginEnvironment().getPluginKey() + "," + "plugin-url="
+ this.context.getPluginEnvironment().getPluginUrl();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy