.classpath | 5 modules/common/ant-bundle/pom.xml | 50 + modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AbstractBundleTask.java | 27 + modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java | 191 +++++++ modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java | 50 + modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleTask.java | 29 + modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/LoggerAntBuildListener.java | 115 ++++ modules/common/ant-bundle/src/main/resources/bundle-ant-tasks.properties | 1 modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java | 87 +++ modules/common/ant-bundle/src/test/resources/simple-build.xml | 12 modules/common/pom.xml | 1 modules/core/util/src/main/java/org/rhq/core/template/TemplateEngine.java | 4 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java | 16 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java | 8 modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/bundle/BundleServerPluginManager.java | 44 + modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java | 5 modules/enterprise/server/plugins/ant-bundle/pom.xml | 214 ++++++++ modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java | 125 ++++ modules/enterprise/server/plugins/ant-bundle/src/main/resources/META-INF/rhq-serverplugin.xml | 20 modules/enterprise/server/plugins/filetemplate-bundle/pom.xml | 6 modules/enterprise/server/plugins/pom.xml | 1 modules/enterprise/server/plugins/validate-all-serverplugins/pom.xml | 1 modules/plugins/ant-bundle/pom.xml | 267 ++++++++++ modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java | 136 +++++ modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginDiscoveryComponent.java | 51 + modules/plugins/ant-bundle/src/main/resources/META-INF/rhq-plugin.xml | 20 modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java | 158 +++++ modules/plugins/ant-bundle/src/test/resources/log4j.xml | 35 + modules/plugins/ant-bundle/src/test/resources/simple-build.xml | 8 modules/plugins/ant-bundle/src/test/resources/test-build.xml | 27 + modules/plugins/pom.xml | 1 modules/plugins/validate-all-plugins/pom.xml | 1 32 files changed, 1689 insertions(+), 27 deletions(-)
New commits: commit 8bd78f0b3a282f09d4549dee054d94855509d484 Merge: c3bb31e... ae88c7c... Author: John Mazzitelli mazz@redhat.com Date: Mon Mar 29 00:31:34 2010 -0400
Merge branch 'gwt' of ssh://git.fedorahosted.org/git/rhq/rhq into gwt
commit c3bb31e179881380b02df5d9dee0743878a3e4c5 Author: John Mazzitelli mazz@redhat.com Date: Mon Mar 29 00:31:14 2010 -0400
introduce a new bundle type - ANT we now two kinds of bundles - one has a simple recipe style (file template) and the second uses Ant scripts as its recipe (thus providing a more advanced way to lay down bundle content on the agent)
diff --git a/.classpath b/.classpath index 082cf31..c1a9e78 100644 --- a/.classpath +++ b/.classpath @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> <classpathentry kind="src" path="modules/common/jboss-as/src/main/java"/> + <classpathentry kind="src" path="modules/common/ant-bundle/src/main/java"/> + <classpathentry kind="src" path="modules/common/ant-bundle/src/test/java"/> <classpathentry kind="src" path="modules/common/filetemplate-bundle/src/main/java"/> <classpathentry kind="src" path="modules/common/filetemplate-bundle/src/test/java"/> <classpathentry kind="src" path="modules/enterprise/gui/base-perspective-jar/src/main/java"/> @@ -71,6 +73,7 @@ <classpathentry kind="src" path="modules/enterprise/server/plugins/alert-microblog/src/main/java"/> <classpathentry kind="src" path="modules/enterprise/server/plugins/alert-mobicents/src/main/java"/> <classpathentry kind="src" path="modules/enterprise/server/plugins/cobbler/src/main/java"/> + <classpathentry kind="src" path="modules/enterprise/server/plugins/ant-bundle/src/main/java"/> <classpathentry kind="src" path="modules/enterprise/server/plugins/filetemplate-bundle/src/main/java"/> <classpathentry kind="src" path="modules/enterprise/gui/portal-war/src/main/java"/> <classpathentry kind="src" path="modules/enterprise/gui/portal-war/src/test/java"/> @@ -129,6 +132,8 @@ <classpathentry kind="src" path="modules/plugins/jdbctrace/src/main/java"/> <classpathentry kind="src" path="modules/plugins/augeas/src/main/java"/> <classpathentry kind="src" path="modules/plugins/augeas/src/test/java"/> + <classpathentry kind="src" path="modules/plugins/ant-bundle/src/main/java"/> + <classpathentry kind="src" path="modules/plugins/ant-bundle/src/test/java"/> <classpathentry kind="src" path="modules/plugins/filetemplate-bundle/src/main/java"/> <classpathentry kind="src" path="modules/plugins/filetemplate-bundle/src/test/java"/> <classpathentry kind="src" path="modules/helpers/rtfilter/src/main/java"/> diff --git a/modules/common/ant-bundle/pom.xml b/modules/common/ant-bundle/pom.xml new file mode 100644 index 0000000..90e3f39 --- /dev/null +++ b/modules/common/ant-bundle/pom.xml @@ -0,0 +1,50 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.rhq</groupId> + <artifactId>rhq-common-parent</artifactId> + <version>3.0.0-SNAPSHOT</version> + </parent> + + <groupId>org.rhq</groupId> + <artifactId>rhq-ant-bundle-common</artifactId> + <packaging>jar</packaging> + + <name>RHQ Ant Bundle Plugins Common Library</name> + <description>A library with the code common to the agent and server plugins for Ant Bundles</description> + + <scm> + <connection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/common/ant-bundle/</connection> + <developerConnection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/common/ant-bundle/</developerConnection> + </scm> + + <properties> + <scm.module.path>modules/common/ant-bundle/</scm.module.path> + </properties> + + <dependencies> + + <dependency> + <groupId>ant</groupId> + <artifactId>ant</artifactId> + <version>1.6.5</version> + </dependency> + + <dependency> + <groupId>ant</groupId> + <artifactId>ant-launcher</artifactId> + <version>1.6.5</version> + </dependency> + + <!-- include some optional ant tasks for users to be able to use --> + <dependency> + <groupId>ant-contrib</groupId> + <artifactId>ant-contrib</artifactId> + <version>1.0b3</version> + </dependency> + + </dependencies> + +</project> \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AbstractBundleTask.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AbstractBundleTask.java new file mode 100644 index 0000000..d5db4cc --- /dev/null +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AbstractBundleTask.java @@ -0,0 +1,27 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 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; + +import org.apache.tools.ant.Task; + +public abstract class AbstractBundleTask extends Task { + public BundleAntProject getBundleAntProject() { + return (BundleAntProject) getProject(); + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..b184274 --- /dev/null +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/AntLauncher.java @@ -0,0 +1,191 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser 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.bundle.ant; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintWriter; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.helper.ProjectHelper2; + +import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; +import org.rhq.core.domain.configuration.definition.PropertyDefinitionSimple; +import org.rhq.core.domain.configuration.definition.PropertySimpleType; + +public class AntLauncher { + + // currently, the bundle plugins don't need custom ant tasks, but there is an ant task stubbed for future use here + private static final String ANT_TASKS = "bundle-ant-tasks.properties"; + + /** + * Launches ANT and parses the given build file and optionally executes it. + * + * @param buildFile the build file that ANT will run + * @param target the target to run, <code>null</code> will run the default target + * @param customTaskDefs the properties file found in classloader that contains all the taskdef definitions + * @param properties set of properties to set for the ANT task to access + * @param logFile where ANT messages will be logged + * @param logStdOut if <code>true</code>, log messages will be sent to stdout as well as the log file + * @param execute if <code>true</code> the ant script will be parsed and executed; otherwise, it will only be parsed + * + * @throws RuntimeException + */ + public BundleAntProject startAnt(File buildFile, String target, String customTaskDefs, Properties properties, + File logFile, boolean logStdOut, boolean execute) { + + PrintWriter logFileOutput = null; + + try { + logFileOutput = new PrintWriter(new FileOutputStream(logFile, true)); + + ClassLoader classLoader = getClass().getClassLoader(); + + Properties taskDefs = new Properties(); + if (customTaskDefs != null) { + InputStream taskDefsStream = classLoader.getResourceAsStream(customTaskDefs); + try { + taskDefs.load(taskDefsStream); + } finally { + taskDefsStream.close(); + } + } + + BundleAntProject project = new BundleAntProject(); + project.setCoreLoader(classLoader); + project.init(); + project.setBaseDir(buildFile.getParentFile()); + + if (properties != null) { + for (Map.Entry<Object, Object> property : properties.entrySet()) { + project.setProperty(property.getKey().toString(), property.getValue().toString()); + } + } + + // notice we are adding the listener after we set the properties - we do not want the + // the properties echoed out in the log (in case they contain sensitive passwords) + project.addBuildListener(new LoggerAntBuildListener(target, logFileOutput, Project.MSG_DEBUG)); + if (logStdOut) { + PrintWriter stdout = new PrintWriter(System.out); + project.addBuildListener(new LoggerAntBuildListener(target, stdout, Project.MSG_INFO)); + } + + for (Map.Entry<Object, Object> taskDef : taskDefs.entrySet()) { + project.addTaskDefinition(taskDef.getKey().toString(), Class.forName(taskDef.getValue().toString(), + true, classLoader)); + } + + ProjectHelper2 helper = new ProjectHelper2(); + helper.parse(project, buildFile); + + parseBundleFiles(project); + parseBundleConfiguration(project); + + if (execute) { + project.executeTarget((target == null) ? project.getDefaultTarget() : target); + } + + return project; + + } catch (Exception e) { + throw new RuntimeException("Cannot run ANT on script [" + buildFile + "]. Cause: " + e, e); + } finally { + if (logFileOutput != null) { + logFileOutput.close(); + } + } + } + + private void parseBundleFiles(BundleAntProject project) { + Map<String, ? extends Task> refs = project.getReferences(); + for (Map.Entry<String, ? extends Task> entry : refs.entrySet()) { + String refId = entry.getKey(); + if (refId.startsWith("_bundlefile.")) { + Hashtable attribs = entry.getValue().getRuntimeConfigurableWrapper().getAttributeMap(); + + if (!attribs.containsKey("name")) { + throw new BuildException("Property id=[" + refId + "] must specify the 'name' attribute"); + } + String name = attribs.get("name").toString(); + + // allow the bundle author to specify the bundle file in one of the standard two ways + Object location = attribs.get("location"); + Object value = attribs.get("value"); + + String bundleFilename; + if (location != null) { + bundleFilename = location.toString(); + } else if (value != null) { + bundleFilename = value.toString(); + } else { + throw new BuildException("Property id=[" + refId + "], name=[" + name + + "] must specify the bundle file name in an attribute named 'location' or 'value'"); + } + + project.addBundleFile(name, bundleFilename); + } + } + } + + private void parseBundleConfiguration(BundleAntProject project) { + Map<String, ? extends Task> refs = project.getReferences(); + for (Map.Entry<String, ? extends Task> entry : refs.entrySet()) { + String refId = entry.getKey(); + if (refId.startsWith("_bundleconfig.")) { + Hashtable attribs = entry.getValue().getRuntimeConfigurableWrapper().getAttributeMap(); + + if (!attribs.containsKey("name")) { + throw new BuildException("Property id=[" + refId + "] must specify the 'name' attribute"); + } + String name = attribs.get("name").toString(); + + // allow the bundle author to specify the bundle config prop in one of the standard two ways + Object location = attribs.get("location"); + Object value = attribs.get("value"); + + String bundlePropValue; + if (location != null) { + bundlePropValue = location.toString(); + } else if (value != null) { + bundlePropValue = value.toString(); + } else { + throw new BuildException("Property id=[" + refId + "], name=[" + name + + "] must specify the bundle configuration name in an attribute named 'location' or 'value'"); + } + + PropertyDefinitionSimple prop = new PropertyDefinitionSimple(name, "Needed by bundle recipe.", false, + PropertySimpleType.STRING); + prop.setDisplayName(name); + prop.setDefaultValue(bundlePropValue);// TODO: I would like to set this-setDefaultValue is deprecated, how to do this? + ConfigurationDefinition configDef = project.getConfigurationDefinition(); + configDef.put(prop); + } + } + } +} 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 new file mode 100644 index 0000000..0dd282c --- /dev/null +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleAntProject.java @@ -0,0 +1,50 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser 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.bundle.ant; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.tools.ant.Project; + +import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; + +public class BundleAntProject extends Project { + private final Map<String, String> bundleFiles = new HashMap<String, String>(); + private ConfigurationDefinition configDef; + + public Map<String, String> getBundleFiles() { + return bundleFiles; + } + + public void addBundleFile(String name, String filename) { + bundleFiles.put(name, filename); + } + + public ConfigurationDefinition getConfigurationDefinition() { + if (configDef == null) { + configDef = new ConfigurationDefinition("antbundle", null); + } + return configDef; + } +} diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleTask.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleTask.java new file mode 100644 index 0000000..a21ca6e --- /dev/null +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/BundleTask.java @@ -0,0 +1,29 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 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; + +import org.apache.tools.ant.BuildException; + +public class BundleTask extends AbstractBundleTask { + @Override + public void execute() throws BuildException { + // TODO this is a stub for a custom bundle task, in case we need one + return; + } +} \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/LoggerAntBuildListener.java b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/LoggerAntBuildListener.java new file mode 100644 index 0000000..e7365e3 --- /dev/null +++ b/modules/common/ant-bundle/src/main/java/org/rhq/bundle/ant/LoggerAntBuildListener.java @@ -0,0 +1,115 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-2008 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; + +import java.io.PrintWriter; +import java.util.Date; + +import org.apache.tools.ant.BuildEvent; +import org.apache.tools.ant.BuildListener; +import org.apache.tools.ant.Target; +import org.apache.tools.ant.Task; + +/** + * Listens for ANT build events and logs them to a log stream. + * + * @author John Mazzitelli + */ +public class LoggerAntBuildListener implements BuildListener { + private final String mainTarget; + private final PrintWriter output; + private final int priorityThreshold; + + public LoggerAntBuildListener(String target, PrintWriter logFile, int priorityThreshold) { + this.mainTarget = (target != null) ? target : "(default)"; + this.output = logFile; + this.priorityThreshold = priorityThreshold; + + // start with the date this was started + this.output.println("======================================"); + this.output.println("ANT target [" + this.mainTarget + "]"); + this.output.println(new Date().toString()); + this.output.println("======================================"); + } + + public void buildFinished(BuildEvent event) { + logEvent(event, "FINISHED! [" + this.mainTarget + ']'); + } + + public void buildStarted(BuildEvent event) { + logEvent(event, "STARTED! [" + this.mainTarget + ']'); + } + + public void messageLogged(BuildEvent event) { + logEvent(event, null); + } + + public void targetFinished(BuildEvent event) { + logEvent(event, null); + } + + public void targetStarted(BuildEvent event) { + logEvent(event, null); + } + + public void taskFinished(BuildEvent event) { + logEvent(event, null); + } + + public void taskStarted(BuildEvent event) { + logEvent(event, null); + } + + private void logEvent(BuildEvent event, String additionalMessage) { + if (event.getPriority() > this.priorityThreshold) { + return; + } + + String message = event.getMessage(); + Throwable exception = event.getException(); + Target target = event.getTarget(); + Task task = event.getTask(); + + if (additionalMessage != null) { + output.println(additionalMessage); + } + + if (target != null) { + output.print("[" + target.getName() + "] "); + } + + if (task != null) { + output.print("[" + task.getTaskName() + "] "); + } + + if (message != null) { + output.print(message); + } + + if (exception != null) { + output.println(); + exception.printStackTrace(output); + } + + output.println(); + output.flush(); + + return; + } +} \ No newline at end of file diff --git a/modules/common/ant-bundle/src/main/resources/bundle-ant-tasks.properties b/modules/common/ant-bundle/src/main/resources/bundle-ant-tasks.properties new file mode 100644 index 0000000..6f84e21 --- /dev/null +++ b/modules/common/ant-bundle/src/main/resources/bundle-ant-tasks.properties @@ -0,0 +1 @@ +bundle-task=org.rhq.bundle.ant.BundleTask \ No newline at end of file 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 new file mode 100644 index 0000000..01de89e --- /dev/null +++ b/modules/common/ant-bundle/src/test/java/org/rhq/bundle/ant/AntLauncherTest.java @@ -0,0 +1,87 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser 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.bundle.ant; + +import java.io.File; +import java.util.Map; + +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import org.rhq.core.domain.configuration.definition.ConfigurationDefinition; + +@Test +public class AntLauncherTest { + private File logFile; + + @BeforeMethod + public void beforeMethod() { + logFile = new File("target/test-ant-log.txt"); + if (logFile.exists()) { + if (!logFile.delete()) { + System.out.println("Failed to clean up test - log file did not delete"); + } + } + return; + } + + public void testSimpleParseTest() throws Exception { + AntLauncher ant = new AntLauncher(); + BundleAntProject project = ant.startAnt(getBuildXml("simple-build.xml"), "unnecessary-target", null, null, + logFile, true, false); + assert project != null; + Map<String, String> bundleFiles = project.getBundleFiles(); + assert bundleFiles != null; + assert bundleFiles.size() == 2 : bundleFiles; + assert bundleFiles.get("f").equals("file.txt") : bundleFiles; + assert bundleFiles.get("pkg").equals("package.zip") : bundleFiles; + + ConfigurationDefinition configDef = project.getConfigurationDefinition(); + assert configDef.getPropertyDefinitions().size() == 2; + assert configDef.getPropertyDefinitionSimple("custom.prop1") != null; + assert configDef.getPropertyDefinitionSimple("custom.prop2") != null; + } + + public void testSimpleExecTest() throws Exception { + AntLauncher ant = new AntLauncher(); + BundleAntProject project = ant.startAnt(getBuildXml("simple-build.xml"), "first-target", null, null, logFile, + true, true); + Map<String, String> bundleFiles = project.getBundleFiles(); + assert bundleFiles != null; + assert bundleFiles.size() == 2 : bundleFiles; + assert bundleFiles.get("f").equals("file.txt") : bundleFiles; + assert bundleFiles.get("pkg").equals("package.zip") : bundleFiles; + + ConfigurationDefinition configDef = project.getConfigurationDefinition(); + assert configDef.getPropertyDefinitions().size() == 2; + assert configDef.getPropertyDefinitionSimple("custom.prop1") != null; + assert configDef.getPropertyDefinitionSimple("custom.prop2") != null; + } + + private File getBuildXml(String name) throws Exception { + File file = new File("target/test-classes", name); + assert file.exists() : "the test ant build script doesn't exist: " + file.getAbsolutePath(); + return file; + } +} diff --git a/modules/common/ant-bundle/src/test/resources/simple-build.xml b/modules/common/ant-bundle/src/test/resources/simple-build.xml new file mode 100644 index 0000000..fecb376 --- /dev/null +++ b/modules/common/ant-bundle/src/test/resources/simple-build.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<project name="simple-bundle-test"> + <property id="_bundlefile.1" name="f" location="file.txt" /> + <property id="_bundleconfig.1" name="custom.prop1" location="1" /> + + <target name="first-target"> + <echo>Hello!!!!!!!!</echo> + <property id="_bundlefile.2" name="pkg" value="package.zip" /> + <property id="_bundleconfig.2" name="custom.prop2" value="2" /> + <echo>World!!!!!!!!</echo> + </target> +</project> \ No newline at end of file diff --git a/modules/common/pom.xml b/modules/common/pom.xml index 8abfe11..1e561b4 100644 --- a/modules/common/pom.xml +++ b/modules/common/pom.xml @@ -67,5 +67,6 @@ <modules> <module>jboss-as</module> <module>filetemplate-bundle</module> + <module>ant-bundle</module> </modules> </project> \ No newline at end of file diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java index 07c49a8..0e83859 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java @@ -143,12 +143,12 @@ public class ServerPluginService implements ServerPluginServiceManagement {
File tmpDir = LookupUtil.getCoreServer().getJBossServerTempDir();
- // TODO: determine what things to hide from our war classloader - //StringBuilder defaultRegex = new StringBuilder(); - //defaultRegex.append("(package\.with\.classes\.to\.hide\..*)|"); + // determine what things to hide from our war classloader + StringBuilder defaultRegex = new StringBuilder(); + defaultRegex.append("(org\.apache\.tools\..*)"); // ant.jar
MasterServerPluginContainerConfiguration config; - config = new MasterServerPluginContainerConfiguration(pluginDir, dataDir, tmpDir, null); + config = new MasterServerPluginContainerConfiguration(pluginDir, dataDir, tmpDir, defaultRegex.toString()); pc.initialize(config); return pc; } diff --git a/modules/enterprise/server/plugins/ant-bundle/pom.xml b/modules/enterprise/server/plugins/ant-bundle/pom.xml new file mode 100644 index 0000000..b044ca3 --- /dev/null +++ b/modules/enterprise/server/plugins/ant-bundle/pom.xml @@ -0,0 +1,214 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.rhq</groupId> + <artifactId>rhq-enterprise-server-plugins-parent</artifactId> + <version>3.0.0-SNAPSHOT</version> + </parent> + + <groupId>org.rhq</groupId> + <artifactId>rhq-serverplugin-ant-bundle</artifactId> + <packaging>jar</packaging> + + <name>RHQ Ant Bundle Server Plugin</name> + <description>Server side plugin that manages ant-scripted bundles</description> + + <scm> + <connection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/enterprise/server/plugins/ant-bundle/</connection> + <developerConnection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/enterprise/server/plugins/ant-bundle/</developerConnection> + </scm> + + <properties> + <scm.module.path>modules/enterprise/server/plugins/ant-bundle/</scm.module.path> + </properties> + + <dependencies> + + <!-- Internal Deps --> + + <dependency> + <groupId>org.rhq</groupId> + <artifactId>rhq-core-domain</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.rhq</groupId> + <artifactId>rhq-core-client-api</artifactId> + <version>${project.version}</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.rhq</groupId> + <artifactId>rhq-ant-bundle-common</artifactId> + <version>${project.version}</version> + </dependency> + + <!-- 3rd Party Deps --> + + <!-- TODO: This is a fix for the Javac bug requiring annotations to be + available when compiling dependent classes. It is fixed in JDK 6 --> + <dependency> + <groupId>javax.persistence</groupId> + <artifactId>persistence-api</artifactId> + <version>1.0</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>jboss.jboss-embeddable-ejb3</groupId> + <artifactId>hibernate-all</artifactId> + <version>1.0.0.Alpha9</version> + <scope>provided</scope> + <!-- needed for referenced domain entities that use Hibernate annotations --> + </dependency> + + </dependencies> + + <build> + <plugins> + + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups> + <!-- + <argLine>-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine> + --> + </configuration> + </plugin> + + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.0</version> + <executions> + <execution> + <id>copy-rhq-plugins</id> + <phase>process-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + + <artifactItem> + <groupId>org.rhq</groupId> + <artifactId>rhq-ant-bundle-common</artifactId> + <version>${project.version}</version> + </artifactItem> + + <artifactItem> + <groupId>ant</groupId> + <artifactId>ant</artifactId> + <version>1.6.5</version> + </artifactItem> + + <artifactItem> + <groupId>ant</groupId> + <artifactId>ant-launcher</artifactId> + <version>1.6.5</version> + </artifactItem> + + <!-- include some optional ant tasks for users to be able to use --> + <artifactItem> + <groupId>ant-contrib</groupId> + <artifactId>ant-contrib</artifactId> + <version>1.0b3</version> + </artifactItem> + + </artifactItems> + <outputDirectory>${project.build.outputDirectory}/lib</outputDirectory> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + </build> + + <profiles> + + <profile> + <id>dev</id> + + <properties> + <rhq.rootDir>../../../../..</rhq.rootDir> + <rhq.containerDir>${rhq.rootDir}/${rhq.defaultDevContainerPath}</rhq.containerDir> + <rhq.deploymentDir>${rhq.containerDir}/jbossas/server/default/deploy/${rhq.earName}/rhq-serverplugins</rhq.deploymentDir> + </properties> + + <build> + <plugins> + + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.1</version> + <executions> + + <execution> + <id>deploy</id> + <phase>compile</phase> + <configuration> + <tasks> + <mkdir dir="${rhq.deploymentDir}" /> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Updating ${deployment.file}...</echo> + <jar destfile="${deployment.file}" basedir="${project.build.outputDirectory}" /> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>undeploy</id> + <phase>clean</phase> + <configuration> + <tasks> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Deleting ${deployment.file}...</echo> + <delete file="${deployment.file}" /> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>deploy-jar-meta-inf</id> + <phase>package</phase> + <configuration> + <tasks> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Updating META-INF dir in ${deployment.file}...</echo> + <unjar src="${project.build.directory}/${project.build.finalName}.jar" dest="${project.build.outputDirectory}"> + <patternset> + <include name="META-INF/**" /> + </patternset> + </unjar> + <jar destfile="${deployment.file}" manifest="${project.build.outputDirectory}/META-INF/MANIFEST.MF" + update="true"> + </jar> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + </executions> + </plugin> + + </plugins> + </build> + </profile> + + </profiles> + +</project> \ No newline at end of file diff --git a/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java b/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java new file mode 100644 index 0000000..15e4ecb --- /dev/null +++ b/modules/enterprise/server/plugins/ant-bundle/src/main/java/org/rhq/enterprise/server/plugins/ant/AntBundleServerPluginComponent.java @@ -0,0 +1,125 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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.enterprise.server.plugins.ant; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.HashSet; +import java.util.Map; + +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.stream.StreamUtil; +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; + +/** + * 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 final Log log = LogFactory.getLog(AntBundleServerPluginComponent.class); + + private ServerPluginContext context; + private File tmpDirectory; + + public void initialize(ServerPluginContext context) throws Exception { + this.context = context; + this.tmpDirectory = new File(this.context.getTemporaryDirectory(), "ant-bundle-server-plugin"); + this.tmpDirectory.mkdirs(); + if (!this.tmpDirectory.exists() || !this.tmpDirectory.isDirectory()) { + throw new Exception("Failed to create tmp dir [" + this.tmpDirectory + "] - cannot process ant bundles"); + } + log.debug("The ant bundle plugin has been initialized: " + this); + } + + public void start() { + log.debug("The ant bundle plugin has started: " + this); + } + + public void stop() { + log.debug("The ant bundle plugin has stopped: " + this); + } + + public void shutdown() { + log.debug("The ant bundle plugin has been shut down: " + this); + } + + public RecipeParseResults parseRecipe(String recipe) throws Exception { + + Map<String, String> bundleFiles = null; + ConfigurationDefinition configDef = null; + 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(); + BundleAntProject project = antLauncher.startAnt(recipeFile, null, null, null, logFile, false, false); + + // obtain the parse results + bundleFiles = project.getBundleFiles(); + configDef = project.getConfigurationDefinition(); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + try { + log.debug(new String(StreamUtil.slurp(new FileInputStream(logFile)))); + } catch (Exception e) { + } + } + throw new Exception("Failed to parse the bundle ANT script", t); + } finally { + recipeFile.delete(); + logFile.delete(); + } + + results = new RecipeParseResults(configDef, new HashSet<String>(bundleFiles.values())); + return results; + + } + + @Override + public String toString() { + if (this.context == null) { + return "<no context>"; + } + + StringBuilder str = new StringBuilder(); + str.append("plugin-key=").append(this.context.getPluginEnvironment().getPluginKey()).append(","); + str.append("plugin-url=").append(this.context.getPluginEnvironment().getPluginUrl()); + return str.toString(); + } +} diff --git a/modules/enterprise/server/plugins/ant-bundle/src/main/resources/META-INF/rhq-serverplugin.xml b/modules/enterprise/server/plugins/ant-bundle/src/main/resources/META-INF/rhq-serverplugin.xml new file mode 100644 index 0000000..23208b7 --- /dev/null +++ b/modules/enterprise/server/plugins/ant-bundle/src/main/resources/META-INF/rhq-serverplugin.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<bundle-plugin name="AntBundleServerPlugin" + displayName="Ant Bundle Processor" + description="Processes bundles whose recipes are Ant scripts" + package="org.rhq.enterprise.server.plugins.ant" + xmlns="urn:xmlns:rhq-serverplugin.bundle" + xmlns:serverplugin="urn:xmlns:rhq-serverplugin" + xmlns:c="urn:xmlns:rhq-configuration"> + + serverplugin:help<![CDATA[ + Processes Ant bundles on the server side. + ]]></serverplugin:help> + + <serverplugin:plugin-component class="AntBundleServerPluginComponent"> + </serverplugin:plugin-component> + + <bundle type="Ant Bundle"/> + +</bundle-plugin> diff --git a/modules/enterprise/server/plugins/pom.xml b/modules/enterprise/server/plugins/pom.xml index b86cde2..06f91cf 100644 --- a/modules/enterprise/server/plugins/pom.xml +++ b/modules/enterprise/server/plugins/pom.xml @@ -84,6 +84,7 @@ <module>alert-subject</module> <module>cobbler</module> <module>filetemplate-bundle</module> + <module>ant-bundle</module> <module>validate-all-serverplugins</module> </modules>
diff --git a/modules/enterprise/server/plugins/validate-all-serverplugins/pom.xml b/modules/enterprise/server/plugins/validate-all-serverplugins/pom.xml index 58e3d40..9c7cc74 100644 --- a/modules/enterprise/server/plugins/validate-all-serverplugins/pom.xml +++ b/modules/enterprise/server/plugins/validate-all-serverplugins/pom.xml @@ -54,6 +54,7 @@ <pathelement location="../alert-subject/target/alert-subject-${project.version}.jar" /> <pathelement location="../cobbler/target/cobbler-${project.version}.jar" /> <pathelement location="../filetemplate-bundle/target/rhq-serverplugin-filetemplate-bundle-${project.version}.jar" /> + <pathelement location="../ant-bundle/target/rhq-serverplugin-ant-bundle-${project.version}.jar" /> <pathelement location="../perspectives/core/target/rhq-core-perspective-${project.version}.jar" /> </classpath> <sysproperty key="org.apache.commons.logging.Log" value="org.apache.commons.logging.impl.SimpleLog" /> diff --git a/modules/plugins/ant-bundle/pom.xml b/modules/plugins/ant-bundle/pom.xml new file mode 100644 index 0000000..3777af9 --- /dev/null +++ b/modules/plugins/ant-bundle/pom.xml @@ -0,0 +1,267 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.rhq</groupId> + <artifactId>rhq-plugins-parent</artifactId> + <version>3.0.0-SNAPSHOT</version> + </parent> + + <groupId>org.rhq</groupId> + <artifactId>rhq-ant-bundle-plugin</artifactId> + <packaging>jar</packaging> + + <name>RHQ Ant Bundle Plugin</name> + <description>a plugin that processes ant-based bundles</description> + + <scm> + <connection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/plugins/ant-bundle/</connection> + <developerConnection>scm:git:ssh://git.fedorahosted.org/git/rhq.git/modules/plugins/ant-bundle/</developerConnection> + </scm> + + <properties> + <scm.module.path>modules/plugins/ant-bundle/</scm.module.path> + </properties> + + <dependencies> + + <dependency> + <groupId>org.rhq</groupId> + <artifactId>rhq-ant-bundle-common</artifactId> + <version>${project.version}</version> + </dependency> + + </dependencies> + + <build> + <plugins> + + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.0</version> + <executions> + <execution> + <id>copy-rhq-plugins</id> + <phase>process-resources</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + + <artifactItem> + <groupId>org.rhq</groupId> + <artifactId>rhq-ant-bundle-common</artifactId> + <version>${project.version}</version> + </artifactItem> + + <artifactItem> + <groupId>ant</groupId> + <artifactId>ant</artifactId> + <version>1.6.5</version> + </artifactItem> + + <artifactItem> + <groupId>ant</groupId> + <artifactId>ant-launcher</artifactId> + <version>1.6.5</version> + </artifactItem> + + <!-- include some optional ant tasks for users to be able to use --> + <artifactItem> + <groupId>ant-contrib</groupId> + <artifactId>ant-contrib</artifactId> + <version>1.0b3</version> + </artifactItem> + + </artifactItems> + <outputDirectory>${project.build.outputDirectory}/lib</outputDirectory> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + </build> + + <profiles> + <profile> + <id>integration-tests</id> + <activation> + <property> + <name>maven.test.skip</name> + <value>!true</value> + </property> + </activation> + + <build> + <plugins> + <!-- Integration testing voodoo to load and test this plugin with its plugin dependencies --> + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <executions> + <execution> + <phase>pre-integration-test</phase> + <configuration> + <tasks> + <echo>Setting up plugin dependencies for ${project.artifactId}-${project.version}.jar...</echo> + <property name="settings.localRepository" location="${user.home}/.m2/repository" /> + <mkdir dir="target/itest" /> + <mkdir dir="target/itest/plugins" /> + <mkdir dir="target/itest/lib" /> + <copy toDir="target/itest/plugins" flatten="true"> + <fileset dir="${settings.localRepository}/"> + <include name="org/rhq/rhq-platform-plugin/${project.version}/rhq-platform-plugin-${project.version}.jar" /> + </fileset> + <fileset dir="${project.build.directory}"> + <include name="${project.artifactId}-${project.version}.jar" /> + </fileset> + </copy> + <unzip dest="target/itest/lib"> + <fileset dir="${settings.localRepository}/org/hyperic/sigar-dist/${sigar.version}" includes="*.zip" /> + <patternset> + <include name="**/lib/sigar.jar" /> + <include name="**/lib/bcel*.jar" /> + <include name="**/lib/*.so" /> + <include name="**/lib/*.sl" /> + <include name="**/lib/*.dll" /> + <include name="**/lib/*.dylib" /> + </patternset> + </unzip> + <move todir="target/itest/lib" flatten="true"> + <fileset dir="target/itest/lib"> + <include name="**/lib/*" /> + </fileset> + </move> + <delete dir="target/itest/lib/hyperic-sigar-${sigar.version}" /> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + <executions> + <execution> + <id>surefire-it</id> + <phase>integration-test</phase> + <goals> + <goal>test</goal> + </goals> + <configuration> + <skip>${maven.test.skip}</skip> + <excludedGroups>${rhq.testng.excludedGroups}</excludedGroups> + <useSystemClassLoader>false</useSystemClassLoader> + <argLine>-Dorg.hyperic.sigar.path=${basedir}/target/itest/lib</argLine> + <!-- + <argLine>-Dorg.hyperic.sigar.path=${basedir}/target/itest/lib -Xdebug -Xnoagent -Djava.compiler=NONE + -Xrunjdwp:transport=dt_socket,address=8787,server=y,suspend=y</argLine> + --> + <systemProperties> + <property> + <name>project.artifactId</name> + <value>${project.artifactId}</value> + </property> + <property> + <name>project.version</name> + <value>${project.version}</value> + </property> + </systemProperties> + </configuration> + </execution> + </executions> + </plugin> + + </plugins> + + </build> + </profile> + + <profile> + <id>dev</id> + + <properties> + <rhq.rootDir>../../..</rhq.rootDir> + <rhq.containerDir>${rhq.rootDir}/${rhq.defaultDevContainerPath}</rhq.containerDir> + <rhq.deploymentDir>${rhq.containerDir}/jbossas/server/default/deploy/${rhq.earName}/rhq-downloads/rhq-plugins</rhq.deploymentDir> + </properties> + + <build> + <plugins> + + <plugin> + <artifactId>maven-antrun-plugin</artifactId> + <version>1.1</version> + <executions> + + <execution> + <id>deploy</id> + <phase>compile</phase> + <configuration> + <tasks> + <mkdir dir="${rhq.deploymentDir}" /> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Updating ${deployment.file}...</echo> + <jar destfile="${deployment.file}" basedir="${project.build.outputDirectory}" update="true" /> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>deploy-jar-meta-inf</id> + <phase>package</phase> + <configuration> + <tasks> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Updating META-INF dir in ${deployment.file}...</echo> + <unjar src="${project.build.directory}/${project.build.finalName}.jar" dest="${project.build.outputDirectory}"> + <patternset> + <include name="META-INF/**" /> + </patternset> + </unjar> + <jar destfile="${deployment.file}" manifest="${project.build.outputDirectory}/META-INF/MANIFEST.MF" + update="true"> + </jar> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + <execution> + <id>undeploy</id> + <phase>clean</phase> + <configuration> + <tasks> + <property name="deployment.file" location="${rhq.deploymentDir}/${project.build.finalName}.jar" /> + <echo>*** Deleting ${deployment.file}...</echo> + <delete file="${deployment.file}" /> + </tasks> + </configuration> + <goals> + <goal>run</goal> + </goals> + </execution> + + </executions> + </plugin> + + </plugins> + </build> + </profile> + + </profiles> + +</project> 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 new file mode 100644 index 0000000..f523be1 --- /dev/null +++ b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginComponent.java @@ -0,0 +1,136 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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.plugins.ant; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.util.Map; +import java.util.Properties; + +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.bundle.BundleDeployDefinition; +import org.rhq.core.domain.bundle.BundleVersion; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.Property; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.domain.measurement.AvailabilityType; +import org.rhq.core.pluginapi.bundle.BundleDeployRequest; +import org.rhq.core.pluginapi.bundle.BundleDeployResult; +import org.rhq.core.pluginapi.bundle.BundleFacet; +import org.rhq.core.pluginapi.inventory.ResourceComponent; +import org.rhq.core.pluginapi.inventory.ResourceContext; +import org.rhq.core.system.SystemInfoFactory; +import org.rhq.core.util.stream.StreamUtil; + +/** + * @author John Mazzitelli + */ +@SuppressWarnings("unchecked") +public class AntBundlePluginComponent implements ResourceComponent, BundleFacet { + + private final Log log = LogFactory.getLog(AntBundlePluginComponent.class); + + private ResourceContext resourceContext; + + private File tmpDirectory; + + public void start(ResourceContext context) throws Exception { + resourceContext = context; + this.tmpDirectory = new File(context.getTemporaryDirectory(), "ant-bundle-plugin"); + this.tmpDirectory.mkdirs(); + if (!this.tmpDirectory.exists() || !this.tmpDirectory.isDirectory()) { + throw new Exception("Failed to create tmp dir [" + this.tmpDirectory + "] - cannot process ant bundles"); + } + } + + public void stop() { + } + + public AvailabilityType getAvailability() { + return AvailabilityType.UP; + } + + public BundleDeployResult deployBundle(BundleDeployRequest request) { + BundleDeployResult result = new BundleDeployResult(); + try { + BundleDeployDefinition bundleDeployDef = request.getBundleDeployDefinition(); + BundleVersion bundleVersion = bundleDeployDef.getBundleVersion(); + + String recipe = bundleVersion.getRecipe(); + File recipeFile = File.createTempFile("ant-bundle-recipe", ".xml", request.getBundleFilesLocation()); + 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); + + // get the bundle's configuration values and the global system facts and + // add them as ant properties so the ant script can get their values + Configuration config = bundleDeployDef.getConfiguration(); + Map<String, String> sysFacts = SystemInfoFactory.fetchTemplateEngine().getTokens(); + Properties antProps = new Properties(); + for (Map.Entry<String, String> fact : sysFacts.entrySet()) { + antProps.setProperty(fact.getKey(), fact.getValue()); + } + if (config != null) { + Map<String, Property> allProperties = config.getAllProperties(); + for (Map.Entry<String, Property> entry : allProperties.entrySet()) { + String name = entry.getKey(); + Property prop = entry.getValue(); + String value; + if (prop instanceof PropertySimple) { + value = ((PropertySimple) prop).getStringValue(); + } else { + // for now, just skip all property lists and maps, just assume we are getting simples + continue; + } + antProps.setProperty(name, value); + } + } + + // parse & execute, the ant script + AntLauncher antLauncher = new AntLauncher(); + BundleAntProject project = antLauncher.startAnt(recipeFile, null, null, antProps, logFile, false, true); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + try { + log.debug(new String(StreamUtil.slurp(new FileInputStream(logFile)))); + } catch (Exception e) { + } + } + throw new Exception("Failed to parse the bundle ANT script", t); + } finally { + recipeFile.delete(); + logFile.delete(); + } + + } catch (Throwable t) { + log.error("Failed to deploy bundle [" + request + "]", t); + result.setErrorMessage(t); + } + return result; + } +} diff --git a/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginDiscoveryComponent.java b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginDiscoveryComponent.java new file mode 100644 index 0000000..50a2f86 --- /dev/null +++ b/modules/plugins/ant-bundle/src/main/java/org/rhq/plugins/ant/AntBundlePluginDiscoveryComponent.java @@ -0,0 +1,51 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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.plugins.ant; + +import java.util.HashSet; +import java.util.Set; + +import org.rhq.core.pluginapi.inventory.DiscoveredResourceDetails; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryComponent; +import org.rhq.core.pluginapi.inventory.ResourceDiscoveryContext; + +/** + * @author John Mazzitelli + */ +@SuppressWarnings("unchecked") +public class AntBundlePluginDiscoveryComponent implements ResourceDiscoveryComponent { + //private final Log log = LogFactory.getLog(FileTemplateBundlePluginDiscoveryComponent.class); + + public Set<DiscoveredResourceDetails> discoverResources(ResourceDiscoveryContext context) { + + HashSet<DiscoveredResourceDetails> set = new HashSet<DiscoveredResourceDetails>(); + + String key = "ant-bundle"; + String name = "Ant Bundle Handler"; + String version = this.getClass().getPackage().getImplementationVersion(); + String description = "Processes bundles whose recipes are Ant scripts"; + + DiscoveredResourceDetails resource = new DiscoveredResourceDetails(context.getResourceType(), key, name, + version, description, null, null); + + set.add(resource); + + return set; + } +} \ No newline at end of file diff --git a/modules/plugins/ant-bundle/src/main/resources/META-INF/rhq-plugin.xml b/modules/plugins/ant-bundle/src/main/resources/META-INF/rhq-plugin.xml new file mode 100644 index 0000000..ce2b150 --- /dev/null +++ b/modules/plugins/ant-bundle/src/main/resources/META-INF/rhq-plugin.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8" ?> + +<plugin name="AntBundlePlugin" + displayName="Ant Bundle Plugin" + package="org.rhq.plugins.ant" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns="urn:xmlns:rhq-plugin" + xmlns:c="urn:xmlns:rhq-configuration"> + + + <server name="Ant Bundle Handler Server" + discovery="AntBundlePluginDiscoveryComponent" + class="AntBundlePluginComponent" + singleton="true" + description="This plugin is used to process Ant bundles"> + + <bundle type="Ant Bundle" /> + + </server> +</plugin> diff --git a/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java b/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java new file mode 100644 index 0000000..4f2f28b --- /dev/null +++ b/modules/plugins/ant-bundle/src/test/java/org/rhq/plugins/ant/AntBundlePluginComponentTest.java @@ -0,0 +1,158 @@ +/* + * RHQ Management Platform + * Copyright (C) 2005-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, version 2, as + * published by the Free Software Foundation, and/or the GNU Lesser + * General Public License, version 2.1, also as published by the Free + * Software Foundation. + * + * 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 and the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * and the GNU Lesser 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.plugins.ant; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Properties; + +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import org.rhq.core.domain.bundle.Bundle; +import org.rhq.core.domain.bundle.BundleDeployDefinition; +import org.rhq.core.domain.bundle.BundleType; +import org.rhq.core.domain.bundle.BundleVersion; +import org.rhq.core.domain.configuration.Configuration; +import org.rhq.core.domain.configuration.PropertySimple; +import org.rhq.core.domain.resource.Resource; +import org.rhq.core.domain.resource.ResourceCategory; +import org.rhq.core.domain.resource.ResourceType; +import org.rhq.core.pluginapi.bundle.BundleDeployRequest; +import org.rhq.core.pluginapi.bundle.BundleDeployResult; +import org.rhq.core.pluginapi.inventory.ResourceContext; +import org.rhq.core.system.SystemInfoFactory; +import org.rhq.core.util.stream.StreamUtil; + +@Test +public class AntBundlePluginComponentTest { + + private AntBundlePluginComponent plugin; + private File tmpDir; + + @BeforeMethod + public void beforeMethod() throws Exception { + tmpDir = new File("target/antbundletest"); + tmpDir.mkdirs(); + plugin = new AntBundlePluginComponent(); + ResourceType type = new ResourceType("antBundleTestType", "antBundleTestPlugin", ResourceCategory.SERVER, null); + Resource resource = new Resource("antBundleTestKey", "antBundleTestName", type); + ResourceContext<?> context = new ResourceContext(resource, null, null, + SystemInfoFactory.createJavaSystemInfo(), tmpDir, null, "antBundleTestPC", null, null, null, null, null); + plugin.start(context); + } + + @BeforeClass + @AfterMethod + public void cleanTmpDir() { + if (tmpDir != null) { + File[] files = tmpDir.listFiles(); + if (files != null) { + for (File file : files) { + file.delete(); + } + } + } + } + + public void testSimpleBundle() throws Exception { + ResourceType resourceType = new ResourceType("testSimpleBundle", "plugin", ResourceCategory.SERVER, null); + BundleType bundleType = new BundleType("testSimpleBundle", resourceType); + Bundle bundle = new Bundle("testSimpleBundle", bundleType); + BundleVersion bundleVersion = new BundleVersion("testSimpleBundle", "1.0", bundle, + getRecipeFromFile("simple-build.xml")); + + BundleDeployDefinition deployDef = new BundleDeployDefinition(); + deployDef.setBundleVersion(bundleVersion); + deployDef.setConfiguration(null); + + BundleDeployRequest request = new BundleDeployRequest(); + request.setBundleFilesLocation(tmpDir); + request.setBundleDeployDefinition(deployDef); + + BundleDeployResult results = plugin.deployBundle(request); + + assertResultsSuccess(results); + + // our ant script wrote some output that we should verify to make sure we ran it + File outputFile = new File(tmpDir, "output.1"); + String output = new String(StreamUtil.slurp(new FileInputStream(outputFile))); + assert output.equals("HELLO WORLD") : output; + + } + + public void testAntBundle() throws Exception { + ResourceType resourceType = new ResourceType("testSimpleBundle", "plugin", ResourceCategory.SERVER, null); + BundleType bundleType = new BundleType("testSimpleBundle", resourceType); + Bundle bundle = new Bundle("testSimpleBundle", bundleType); + BundleVersion bundleVersion = new BundleVersion("testSimpleBundle", "1.0", bundle, + getRecipeFromFile("test-build.xml")); + + Configuration config = new Configuration(); + config.put(new PropertySimple("custom.prop1", "custom property 1")); + config.put(new PropertySimple("custom.prop2", "custom property 2")); + + BundleDeployDefinition deployDef = new BundleDeployDefinition(); + deployDef.setBundleVersion(bundleVersion); + deployDef.setConfiguration(config); + + File file1 = new File(tmpDir, "file.txt"); + File file2 = new File(tmpDir, "package.zip"); + assert file1.createNewFile() : "could not create our mock bundle file"; + assert file2.createNewFile() : "could not create our mock bundle file"; + + BundleDeployRequest request = new BundleDeployRequest(); + request.setBundleFilesLocation(tmpDir); + request.setBundleDeployDefinition(deployDef); + + BundleDeployResult results = plugin.deployBundle(request); + + assertResultsSuccess(results); + + // our ant script wrote some output that we should verify to make sure we ran it + File outputFile = new File(tmpDir, "output.2"); + Properties props = new Properties(); + props.load(new FileInputStream(outputFile)); + assert props.getProperty("prop1").equals("custom property 1") : props; + assert props.getProperty("prop2").equals("custom property 2") : props; + assert props.getProperty("f.exists").equals("true") : props; + assert props.getProperty("pkg.exists").equals("true") : props; + assert props.getProperty("hostname").equals(SystemInfoFactory.createSystemInfo().getHostname()) : props; + assert props.getProperty("tmpdir").equals(System.getProperty("java.io.tmpdir")) : props; + } + + private void assertResultsSuccess(BundleDeployResult results) { + if (results.getErrorMessage() != null) { + assert false : "Failed to process bundle: [" + results.getErrorMessage() + "]"; + } + } + + private String getRecipeFromFile(String filename) { + InputStream stream = getClass().getClassLoader().getResourceAsStream(filename); + byte[] contents = StreamUtil.slurp(stream); + return new String(contents); + } +} diff --git a/modules/plugins/ant-bundle/src/test/resources/log4j.xml b/modules/plugins/ant-bundle/src/test/resources/log4j.xml new file mode 100644 index 0000000..181834e --- /dev/null +++ b/modules/plugins/ant-bundle/src/test/resources/log4j.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> + +<!-- tests configuration that only dumps WARN or higher messages due to appender threadhold --> + +<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false"> + + <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender"> + <param name="Threshold" value="ERROR"/> + <param name="Target" value="System.out"/> + + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%t] (%c{5}) - %m%n"/> + </layout> + </appender> + + <appender name="FILE" class="org.apache.log4j.FileAppender"> + <param name="File" value="target/test.log"/> + <param name="Threshold" value="DEBUG"/> + <param name="Append" value="false"/> + <layout class="org.apache.log4j.PatternLayout"> + <param name="ConversionPattern" value="%-5p %d{dd-MM HH:mm:ss,SSS} (%F:%M:%L) -%m%n"/> + </layout> + </appender> + + <category name="org.rhq"> + <priority value="DEBUG"/> + </category> + + <root> + <appender-ref ref="CONSOLE"/> + <appender-ref ref="FILE"/> + </root> + +</log4j:configuration> diff --git a/modules/plugins/ant-bundle/src/test/resources/simple-build.xml b/modules/plugins/ant-bundle/src/test/resources/simple-build.xml new file mode 100644 index 0000000..c1606dc --- /dev/null +++ b/modules/plugins/ant-bundle/src/test/resources/simple-build.xml @@ -0,0 +1,8 @@ +<?xml version="1.0"?> +<project name="test" default="init"> + <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-build.xml b/modules/plugins/ant-bundle/src/test/resources/test-build.xml new file mode 100644 index 0000000..4b0b778 --- /dev/null +++ b/modules/plugins/ant-bundle/src/test/resources/test-build.xml @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<project name="simple-build" default="first-target"> + <property id="_bundlefile.1" name="f" location="file.txt" /> + <property id="_bundleconfig.1" name="custom.prop1" location="1" /> + + <property name="outfile" value="${basedir}/output.2" /> + + <target name="first-target"> + <property id="_bundlefile.2" name="pkg" value="${basedir}/package.zip" /> + <property id="_bundleconfig.2" name="custom.prop2" value="2" /> + + <condition property="file.f.exists"> + <available file="${f}" /> + </condition> + <condition property="file.pkg.exists"> + <available file="${pkg}" /> + </condition> + + <echo file="${outfile}">prop1=${custom.prop1} +prop2=${custom.prop2} +f.exists=${file.f.exists} +pkg.exists=${file.pkg.exists} +hostname=${rhq.system.hostname} +tmpdir=${rhq.system.sysprop.java.io.tmpdir} + </echo> + </target> +</project> \ No newline at end of file diff --git a/modules/plugins/pom.xml b/modules/plugins/pom.xml index d41b7b1..76ee0ee 100644 --- a/modules/plugins/pom.xml +++ b/modules/plugins/pom.xml @@ -162,6 +162,7 @@
<!-- bundle plugins --> <module>filetemplate-bundle</module> + <module>ant-bundle</module> </modules> </profile>
diff --git a/modules/plugins/validate-all-plugins/pom.xml b/modules/plugins/validate-all-plugins/pom.xml index 01e2a34..b3d5e87 100644 --- a/modules/plugins/validate-all-plugins/pom.xml +++ b/modules/plugins/validate-all-plugins/pom.xml @@ -62,6 +62,7 @@ <pathelement location="../virt/target/rhq-virt-plugin-${project.version}.jar" /> <pathelement location="../kickstart/target/rhq-kickstart-plugin-${project.version}.jar" /> <pathelement location="../filetemplate-bundle/target/rhq-filetemplate-bundle-plugin-${project.version}.jar" /> + <pathelement location="../ant-bundle/target/rhq-ant-bundle-plugin-${project.version}.jar" /> </classpath> <sysproperty key="org.apache.commons.logging.Log" value="org.apache.commons.logging.impl.SimpleLog" /> <!--
commit d4e2842142ab368dee94fdee322f8168837956aa Author: John Mazzitelli mazz@redhat.com Date: Mon Mar 29 00:29:04 2010 -0400
force the filetemplate plugin to use its own gnu getopt just to isolate it from the servers's version (this probably isn't that important to do)
diff --git a/modules/enterprise/server/plugins/filetemplate-bundle/pom.xml b/modules/enterprise/server/plugins/filetemplate-bundle/pom.xml index 4a3536e..44cdb03 100644 --- a/modules/enterprise/server/plugins/filetemplate-bundle/pom.xml +++ b/modules/enterprise/server/plugins/filetemplate-bundle/pom.xml @@ -101,6 +101,12 @@ <version>${project.version}</version> </artifactItem>
+ <artifactItem> + <groupId>gnu-getopt</groupId> + <artifactId>getopt</artifactId> + <!-- NOTE: The version is defined in the root POM's dependencyManagement section. --> + </artifactItem> + </artifactItems> <outputDirectory>${project.build.outputDirectory}/lib</outputDirectory> </configuration>
commit 5f33867f613ccc768ef2e30efb9ffc722d6b77fa Author: John Mazzitelli mazz@redhat.com Date: Mon Mar 29 00:27:49 2010 -0400
allow public API to obtain tokens from the template engine
diff --git a/modules/core/util/src/main/java/org/rhq/core/template/TemplateEngine.java b/modules/core/util/src/main/java/org/rhq/core/template/TemplateEngine.java index d748463..79ad1ff 100644 --- a/modules/core/util/src/main/java/org/rhq/core/template/TemplateEngine.java +++ b/modules/core/util/src/main/java/org/rhq/core/template/TemplateEngine.java @@ -37,6 +37,10 @@ public class TemplateEngine implements Serializable { this.tokens = tokens; }
+ public Map<String, String> getTokens() { + return this.tokens; + } + public String replaceTokens(String input) { StringBuffer buffer = new StringBuffer(); Matcher matcher = tokenPattern.matcher(input);
commit 0c03d1eb6b3b03cabe58a17dbb98bd43307ca127 Author: John Mazzitelli mazz@redhat.com Date: Mon Mar 29 00:27:11 2010 -0400
make the parse call directly in the bundle PC so we can set context CL
diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java index 7b41da0..61715df 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/bundle/BundleManagerBean.java @@ -79,7 +79,6 @@ import org.rhq.enterprise.server.authz.RequiredPermission; import org.rhq.enterprise.server.content.ContentManagerLocal; import org.rhq.enterprise.server.content.RepoManagerLocal; import org.rhq.enterprise.server.core.AgentManagerLocal; -import org.rhq.enterprise.server.plugin.pc.bundle.BundleServerPluginFacet; import org.rhq.enterprise.server.util.CriteriaQueryGenerator; import org.rhq.enterprise.server.util.CriteriaQueryRunner; import org.rhq.enterprise.server.util.HibernateDetachUtility; @@ -248,12 +247,11 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
// parse the recipe (validation occurs here) and get the config def and list of files BundleType bundleType = bundle.getBundleType(); - BundleServerPluginFacet bp = BundleManagerHelper.getPluginContainer().getBundleServerPluginManager() - .getBundleServerPluginFacet(bundleType.getName()); RecipeParseResults results;
try { - results = bp.parseRecipe(recipe); + results = BundleManagerHelper.getPluginContainer().getBundleServerPluginManager().parseRecipe( + bundleType.getName(), recipe); } catch (Exception e) { // ensure that we throw a runtime exception to force a rollback throw new RuntimeException("Failed to parse recipe", e); @@ -574,9 +572,8 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
// parse the recipe (validation occurs here) and get the config def and list of files BundleType bundleType = bundleVersion.getBundle().getBundleType(); - BundleServerPluginFacet bp = BundleManagerHelper.getPluginContainer().getBundleServerPluginManager() - .getBundleServerPluginFacet(bundleType.getName()); - RecipeParseResults parseResults = bp.parseRecipe(bundleVersion.getRecipe()); + RecipeParseResults parseResults = BundleManagerHelper.getPluginContainer().getBundleServerPluginManager() + .parseRecipe(bundleType.getName(), bundleVersion.getRecipe());
Set<String> result = parseResults.getBundleFileNames();
@@ -613,9 +610,8 @@ public class BundleManagerBean implements BundleManagerLocal, BundleManagerRemot
// parse the recipe (validation occurs here) and get the config def and list of files BundleType bundleType = bundleVersion.getBundle().getBundleType(); - BundleServerPluginFacet bp = BundleManagerHelper.getPluginContainer().getBundleServerPluginManager() - .getBundleServerPluginFacet(bundleType.getName()); - RecipeParseResults parseResults = bp.parseRecipe(bundleVersion.getRecipe()); + RecipeParseResults parseResults = BundleManagerHelper.getPluginContainer().getBundleServerPluginManager() + .parseRecipe(bundleType.getName(), bundleVersion.getRecipe());
Set<String> filenames = parseResults.getBundleFileNames(); Map<String, Boolean> result = new HashMap<String, Boolean>(filenames.size()); diff --git a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/bundle/BundleServerPluginManager.java b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/bundle/BundleServerPluginManager.java index 68f8a0f..7387f3a 100644 --- a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/bundle/BundleServerPluginManager.java +++ b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/bundle/BundleServerPluginManager.java @@ -18,6 +18,7 @@ */ package org.rhq.enterprise.server.plugin.pc.bundle;
+import org.rhq.enterprise.server.bundle.RecipeParseResults; import org.rhq.enterprise.server.plugin.pc.ServerPluginComponent; import org.rhq.enterprise.server.plugin.pc.ServerPluginEnvironment; import org.rhq.enterprise.server.plugin.pc.ServerPluginManager; @@ -68,28 +69,51 @@ public class BundleServerPluginManager extends ServerPluginManager { }
/** - * Given the {@link BundleType#getName() name of a bundle type}, this will return the stateful plugin component - * that manages bundles of that type. + * Given the {@link BundleType#getName() name of a bundle type}, this will parse the given recipe by asking the + * bundle plugin that can parse a recipe of that bundle type. * - * @param bundleTypeName + * @param bundleTypeName essentially identifies the kind of recipe that is to be parsed + * @param recipe the recipe to parse * - * @return the plugin component object that will manage bundles of the named bundle type; <code>null</code> if there is no plugin - * that can support the given bundle type + * @return the results of the parse + * + * @throws Exception if the recipe could not be parsed successfully */ - public BundleServerPluginFacet getBundleServerPluginFacet(String bundleTypeName) { + public RecipeParseResults parseRecipe(String bundleTypeName, String recipe) throws Exception { + if (bundleTypeName == null) { throw new IllegalArgumentException("bundleTypeName == null"); } + if (recipe == null) { + throw new IllegalArgumentException("recipe == null"); + }
+ // find the plugin environment for the bundle plugin of the given type + ServerPluginEnvironment pluginEnv = null; for (ServerPluginEnvironment env : getPluginEnvironments()) { BundlePluginDescriptorType descriptor = (BundlePluginDescriptorType) env.getPluginDescriptor(); if (bundleTypeName.equals(descriptor.getBundle().getType())) { - ServerPluginComponent component = getServerPluginComponent(env.getPluginKey().getPluginName()); - // we know this cast will work because our loadPlugin ensured that this component implements this interface - return (BundleServerPluginFacet) component; + pluginEnv = env; + break; } }
- return null; + if (pluginEnv == null) { + throw new IllegalArgumentException("Bundle type [" + bundleTypeName + "] is not known to the system"); + } + + // get the facet and call the parse method in the appropriate classloader + String pluginName = pluginEnv.getPluginKey().getPluginName(); + ServerPluginComponent component = getServerPluginComponent(pluginName); + BundleServerPluginFacet facet = (BundleServerPluginFacet) component; // we know this cast will work because our loadPlugin ensured so + getLog().debug("Bundle server plugin [" + pluginName + "] is parsing a bundle recipe"); + ClassLoader originalContextClassLoader = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(pluginEnv.getPluginClassLoader()); + RecipeParseResults results = facet.parseRecipe(recipe); + return results; + } finally { + Thread.currentThread().setContextClassLoader(originalContextClassLoader); + } } } \ No newline at end of file diff --git a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java index 90aab2f..20fa204 100644 --- a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java +++ b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/bundle/TestBundleServerPluginService.java @@ -187,9 +187,8 @@ public class TestBundleServerPluginService extends ServerPluginService implement }
@Override - public BundleServerPluginFacet getBundleServerPluginFacet(String bundleTypeName) { - - return new TestBundlePluginComponent(); + public RecipeParseResults parseRecipe(String bundleTypeName, String recipe) throws Exception { + return new TestBundlePluginComponent().parseRecipe(recipe); } }
rhq-commits@lists.fedorahosted.org