.classpath
| 9
modules/core/client-api/src/main/java/org/rhq/core/clientapi/descriptor/DescriptorPackages.java
| 3
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProvider.java
| 63 -
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetails.java
| 75 -
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetailsKey.java
| 119 --
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/InitializationException.java
| 43
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSource.java
| 61 -
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSyncReport.java
| 123 --
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoDetails.java
| 130 --
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoGroupDetails.java
| 104 --
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoImportReport.java
| 65 -
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoSource.java
| 44
modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/metadata/ContentSourcePluginMetadataManager.java
| 201 ---
modules/core/client-api/src/main/resources/rhq-contentsource-packagedetails.xsd
| 381 -------
modules/core/client-api/src/main/resources/rhq-perspective.xsd
| 163 ---
modules/core/client-api/src/main/resources/rhq-serverplugin-content.xsd
| 180 ---
modules/core/client-api/src/test/java/org/rhq/core/clientapi/server/plugin/content/ContentSourcePackageDetailsKeyTest.java
| 69 -
modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
| 22
modules/enterprise/server/jar/pom.xml
| 8
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginClassLoader.java
| 219 ----
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainer.java
| 234 ----
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainerConfiguration.java
| 68 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginEnvironment.java
| 248 ----
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginService.java
| 133 --
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginServiceManagement.java
| 82 -
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/RootServerPluginClassLoader.java
| 148 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginClassLoader.java
| 218 ++++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainer.java
| 236 ++++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainerConfiguration.java
| 98 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginEnvironment.java
| 247 ++++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java
| 137 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginServiceManagement.java
| 82 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProvider.java
| 63 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetails.java
| 75 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetailsKey.java
| 119 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/InitializationException.java
| 43
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSource.java
| 61 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSyncReport.java
| 123 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoDetails.java
| 130 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoGroupDetails.java
| 104 ++
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoImportReport.java
| 65 +
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoSource.java
| 44
modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/metadata/ContentSourcePluginMetadataManager.java
| 201 +++
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/content/ContentProviderManagerTest.java
| 368 -------
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerTest.java
| 368 +++++++
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentSourcePackageDetailsKeyTest.java
| 69 +
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginService.java
| 9
modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginServiceMBean.java
| 4
modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin-content.xml
| 33
modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin.xml
| 35
modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin-content.xml
| 38
modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin.xml
| 38
modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin-content.xml
| 49
modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin.xml
| 49
modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin-content.xml
| 74 -
modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin.xml
| 76 +
modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin-content.xml
| 23
modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin.xml
| 25
modules/enterprise/server/pom.xml
| 1
modules/enterprise/server/xml-schemas/pom.xml
| 161 +++
modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtil.java
| 266 +++++
modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/XmlSchemaPackages.java
| 37
modules/enterprise/server/xml-schemas/src/main/resources/rhq-contentsource-packagedetails.xsd
| 381 +++++++
modules/enterprise/server/xml-schemas/src/main/resources/rhq-server-configuration.xsd
| 517 ++++++++++
modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-content.xsd
| 170 +++
modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-generic.xsd
| 40
modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-perspective.xsd
| 163 +++
modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin.xsd
| 113 ++
modules/enterprise/server/xml-schemas/src/test/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtilTest.java
| 45
modules/enterprise/server/xml-schemas/src/test/resources/log4j.xml
| 45
modules/enterprise/server/xml-schemas/src/test/resources/test-serverplugin-generic.jar
|binary
modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml
| 16
72 files changed, 4831 insertions(+), 3423 deletions(-)
New commits:
commit ff570e1a4ff0ba07cca0de3664548328123b3bc4
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Sun Nov 1 02:31:34 2009 -0500
removing things that are no longer needed in their original packages
diff --git a/.classpath b/.classpath
index 7f1256c..f2e8012 100644
--- a/.classpath
+++ b/.classpath
@@ -48,6 +48,9 @@
<classpathentry kind="src"
path="modules/enterprise/agent/src/main/java"/>
<classpathentry kind="src"
path="modules/enterprise/agent/src/test/java"/>
<classpathentry kind="src"
path="modules/enterprise/agentupdate/src/main/java"/>
+ <classpathentry kind="src"
path="modules/enterprise/server/xml-schemas/src/main/java"/>
+ <classpathentry kind="src"
path="modules/enterprise/server/xml-schemas/src/test/java"/>
+ <classpathentry kind="src"
path="modules/enterprise/server/xml-schemas/target/generated-sources/xjc"/>
<classpathentry kind="src"
path="modules/enterprise/server/jar/src/main/java"/>
<classpathentry kind="src"
path="modules/enterprise/server/jar/src/test/java"/>
<classpathentry kind="src"
path="modules/enterprise/server/plugins/disk/src/main/java"/>
@@ -190,9 +193,9 @@
<classpathentry exported="true" kind="var"
path="M2_REPO/org/apache/xmlrpc/xmlrpc-client/3.1.2/xmlrpc-client-3.1.2.jar"
sourcepath="/M2_REPO/org/apache/xmlrpc/xmlrpc-client/3.1.2/xmlrpc-client-3.1.2-sources.jar"/>
<classpathentry exported="true" kind="var"
path="M2_REPO/org/apache/xmlrpc/xmlrpc-common/3.1.2/xmlrpc-common-3.1.2.jar"/>
<classpathentry exported="true" kind="var"
path="M2_REPO/org/apache/ws/commons/util/ws-commons-util/1.0.2/ws-commons-util-1.0.2.jar"/>
+ <classpathentry exported="true" kind="var"
path="M2_REPO/org/antlr/antlr-runtime/3.2/antlr-runtime-3.2.jar"/>
+ <classpathentry exported="true" kind="var"
path="M2_REPO/commons-digester/commons-digester/1.8/commons-digester-1.8.jar"/>
+ <classpathentry exported="true" kind="var"
path="M2_REPO/commons-codec/commons-codec/1.4/commons-codec-1.4.jar"/>
<classpathentry exported="true" kind="lib"
path="modules/enterprise/remoting/webservices/target/rhq-remoting-webservices-1.4.0-SNAPSHOT/wsconsume-output"/>
- <classpathentry kind="var"
path="M2_REPO/org/antlr/antlr-runtime/3.2/antlr-runtime-3.2.jar"/>
- <classpathentry kind="var"
path="M2_REPO/commons-digester/commons-digester/1.8/commons-digester-1.8.jar"/>
- <classpathentry kind="var"
path="M2_REPO/commons-codec/commons-codec/1.4/commons-codec-1.4.jar"/>
<classpathentry kind="output" path="eclipse-classes"/>
</classpath>
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProvider.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProvider.java
deleted file mode 100644
index c8da253..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProvider.java
+++ /dev/null
@@ -1,63 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content;
-
-import org.rhq.core.domain.configuration.Configuration;
-
-/**
- * Interface used by the server to communicate with a content provider. Content providers
implement this interface as
- * well as any other source interfaces to further describe what functionality is provided
by the provider.
- * <p/>
- * The class name of this interface's implementation is the class name specified in
the server plugin descriptor.
- *
- * @author Jason Dobies
- * @author John Mazzitelli
- *
- * @see RepoSource
- * @see PackageSource
- */
-public interface ContentProvider {
-
- /**
- * Initializes the adapter with the configuration values indicating how to connect to
the external source system.
- *
- * @param configuration user entered values describing how the content provider
should function.
- *
- * @throws Exception if the content provider has an issue being configured.
- */
- void initialize(Configuration configuration) throws Exception;
-
- /**
- * Informs the adapter that it should shutdown.
- */
- void shutdown();
-
- /**
- * Tests if the content provider can communicate with the external package source.
This will be called after
- * {@link #initialize(Configuration)} to ensure the adapter is in a configured state
to run the test.
- *
- * @throws Exception if the connection cannot be made to the external system.
- */
- void testConnection() throws Exception;
-
-}
\ No newline at end of file
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetails.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetails.java
deleted file mode 100644
index de5a659..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetails.java
+++ /dev/null
@@ -1,75 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content;
-
-import java.util.HashSet;
-import java.util.Set;
-import org.rhq.core.domain.content.PackageDetails;
-
-/**
- * These are the package details that a {@link ContentProvider} will use when refering to
package versions it finds
- * in the remote repository. It is the same as {@link PackageDetails} with the addition
of a resource type name, since
- * that is needed to make package types unique (along with the package type name itself,
which is specified in the
- * {@link PackageDetails} superclass).
- *
- * @author John Mazzitelli
- */
-public class ContentProviderPackageDetails extends PackageDetails {
- private static final long serialVersionUID = 1L;
-
- /**
- * Contains a set of specific versions of resources that this package can be applied
to. The resource type to which
- * these apply is found in the {@link ContentProviderPackageDetailsKey}. If there are
no entries in this list, the
- * package can be applied to any resource of the given type.
- */
- private Set<String> resourceVersions = new HashSet<String>();
-
- public ContentProviderPackageDetails(ContentProviderPackageDetailsKey key) {
- super(key);
- }
-
- /**
- * Just a convienence method to return the key cast to the appropriate type.
- *
- * @return the key cast to the appropriate sub-type
- */
- public ContentProviderPackageDetailsKey getContentProviderPackageDetailsKey() {
- return (ContentProviderPackageDetailsKey) super.getKey();
- }
-
- public Set<String> getResourceVersions() {
- return resourceVersions;
- }
-
- public void setResourceVersions(Set<String> resourceVersions) {
- if (resourceVersions == null) {
- throw new IllegalArgumentException("resourceVersions cannot be
null");
- }
-
- this.resourceVersions = resourceVersions;
- }
-
- public void addResourceVersion(String version) {
- this.resourceVersions.add(version);
- }
-}
\ No newline at end of file
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetailsKey.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetailsKey.java
deleted file mode 100644
index 5548c66..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/ContentProviderPackageDetailsKey.java
+++ /dev/null
@@ -1,119 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content;
-
-import org.rhq.core.domain.content.PackageDetailsKey;
-import org.rhq.core.domain.resource.ResourceType;
-
-/**
- * The key to a content provider package details that a {@link ContentProvider} will use
when referring to package
- * versions it finds in the remote repository. It is the same as {@link
PackageDetailsKey} with the addition of a
- * resource type natural key (which is name and agent plugin name), since that is needed
to make package types unique
- * (along with the package type name itself, which is specified in the {@link
PackageDetailsKey} superclass).
- */
-public class ContentProviderPackageDetailsKey extends PackageDetailsKey {
- private static final long serialVersionUID = 1L;
-
- private final String resourceTypeName;
- private final String resourceTypePluginName;
-
- public ContentProviderPackageDetailsKey(String name, String version, String
packageTypeName, String architectureName,
- String resourceTypeName, String resourceTypePluginName) {
- super(name, version, packageTypeName, architectureName);
-
- if (resourceTypeName == null) {
- throw new IllegalArgumentException("resourceTypeName cannot be
null");
- }
-
- if (resourceTypePluginName == null) {
- throw new IllegalArgumentException("resourceTypePluginName cannot be
null");
- }
-
- this.resourceTypeName = resourceTypeName;
- this.resourceTypePluginName = resourceTypePluginName;
- }
-
- /**
- * The name of the {@link ResourceType} that this package's type belongs to. All
package types are defined and
- * supported by a particular {@link ResourceType}, this name is part of the natural
key of a resource type. See
- * {@link #getResourceTypePluginName() plugin name} for the other part.
- *
- * @return resource type name
- */
- public String getResourceTypeName() {
- return resourceTypeName;
- }
-
- /**
- * The name of the plugin that defined the {@link ResourceType} that this
package's type belongs to. All package
- * types are defined and supported by a particular {@link ResourceType}, this plugin
name is part of the natural key
- * of a resource type. See {@link #getResourceTypeName() resource type name} for the
other part.
- *
- * @return the name of the plugin that defines the resource type that defined the
package type
- */
- public String getResourceTypePluginName() {
- return resourceTypePluginName;
- }
-
- @Override
- public String toString() {
- return "ContentProviderPackageDetailsKey[" + super.toString() + ",
ResourceTypeName=" + resourceTypeName
- + ", PluginName=" + resourceTypePluginName + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = (prime * result) + resourceTypeName.hashCode();
- result = (prime * result) + resourceTypePluginName.hashCode();
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
-
- if (!super.equals(obj)) {
- return false;
- }
-
- if (!(obj instanceof ContentProviderPackageDetailsKey)) {
- return false;
- }
-
- final ContentProviderPackageDetailsKey other = (ContentProviderPackageDetailsKey)
obj;
-
- if (!resourceTypeName.equals(other.resourceTypeName)) {
- return false;
- }
-
- if (!resourceTypePluginName.equals(other.resourceTypePluginName)) {
- return false;
- }
-
- return true;
- }
-}
\ No newline at end of file
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/InitializationException.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/InitializationException.java
deleted file mode 100644
index 786bdc7..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/InitializationException.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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.core.clientapi.server.plugin.content;
-
-/**
- *
- * @author pkilambi
- */
-public class InitializationException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public InitializationException() {
- }
-
- public InitializationException(String message) {
- super(message);
- }
-
- public InitializationException(Throwable cause) {
- super(cause);
- }
-
- public InitializationException(String message, Throwable cause) {
- super(message, cause);
- }
-}
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSource.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSource.java
deleted file mode 100644
index 15dd02a..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSource.java
+++ /dev/null
@@ -1,61 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content;
-
-import java.io.InputStream;
-import java.util.Collection;
-
-/**
- * Indicates a content provider has the capability to provide packages into the server.
Package synchronization will
- * be done through the calls defined in this interface. This interface should use the
configuration settings
- * passed into the plugin through {@link
ContentProvider#initialize(org.rhq.core.domain.configuration.Configuration)}
- *
- * @author Jason Dobies
- */
-public interface PackageSource {
-
- /**
- * Requests that this package source perform a synchronization with its external
package source.
- *
- * @param report used to populate the packages diff information necessary
to
- * bring the server up to date
- * with the current state of the external package source.
- * @param existingPackages collection of packages the server currently has in its
inventory for this package
- * source; used when determining package diff information for
the report.
- * @throws Exception if the package source is unable to perform the synchronization,
for instance if the external
- * source cannot be connected to.
- */
- void synchronizePackages(PackageSyncReport report,
Collection<ContentProviderPackageDetails> existingPackages)
- throws Exception;
-
- /**
- * Get an input stream for the specified package.
- *
- * @param location The location of the package. This is an adapter specific location
that was originally set in the
- * PackageDetails object as part of the synch report.
- * @return An initialized input stream. <b>The caller is responsible for
closing the stream.</b>
- * @throws Exception if failed to obtain the stream to the remote package data
- */
- InputStream getInputStream(String location) throws Exception;
-
-}
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSyncReport.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSyncReport.java
deleted file mode 100644
index 81d7729..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/PackageSyncReport.java
+++ /dev/null
@@ -1,123 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content;
-
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * Indicates the results of performing a syncronize with a package source. This object
carries the diff information
- * necessary to update the server's current knowledge of the source's packages.
- *
- * @author Jason Dobies
- */
-public class PackageSyncReport {
-
- /**
- * Set of packages that have been added to the external package source that are not
yet known to the server. A new
- * version of a package constitutes an entry in this list.
- */
- private final Set<ContentProviderPackageDetails> newPackages = new
HashSet<ContentProviderPackageDetails>();
-
- /**
- * Set of packages that are already known to the server and whose metadata has
changed in the external package
- * source. The data in each of these packages will be merged with the server's
existing knowledge of the package.
- * Packages should only be included in this list if the name and version are the same
as a package in the server;
- * new versions of a package belong in the <code>newPackages</code>
list.
- */
- private final Set<ContentProviderPackageDetails> updatedPackages = new
HashSet<ContentProviderPackageDetails>();
-
- /**
- * Set of packages that are known to the server but no longer in the external
source.
- */
- private final Set<ContentProviderPackageDetails> deletedPackages = new
HashSet<ContentProviderPackageDetails>();
-
- /**
- * The synchronization summary. Free form textual report.
- */
- private String summary;
-
- public Set<ContentProviderPackageDetails> getNewPackages() {
- return newPackages;
- }
-
- /**
- * Add to the set of packages that have been added to the external package source
that are not yet known to the
- * server. A new version of a package constitutes an entry in this list.
- *
- * @param newPackage contains the details of the new package to be added; should not
be <code>null</code>
- */
- public void addNewPackage(ContentProviderPackageDetails newPackage) {
- this.newPackages.add(newPackage);
- }
-
- public Set<ContentProviderPackageDetails> getUpdatedPackages() {
- return updatedPackages;
- }
-
- /**
- * Add to the set of packages that are already known to the server and whose metadata
has changed in the external
- * package source. The data in this package will be merged with the server's
existing knowledge of the package.
- * Packages should only be added to this updated list if the name and version are the
same as a package in the
- * server; new versions of a package belong in the
- * {@link #addNewPackage(ContentProviderPackageDetails) new packages list}.
- *
- * @param updatedPackage contains the new information of a package that was updated;
should not be
- * <code>null</code>
- */
- public void addUpdatedPackage(ContentProviderPackageDetails updatedPackage) {
- this.updatedPackages.add(updatedPackage);
- }
-
- public Set<ContentProviderPackageDetails> getDeletedPackages() {
- return deletedPackages;
- }
-
- /**
- * Add to the set of packages that are known to the server but no longer in the
external source.
- *
- * @param deletedPackage details object identifying the package that was removed;
should not be <code>null</code>
- */
- public void addDeletePackage(ContentProviderPackageDetails deletedPackage) {
- this.deletedPackages.add(deletedPackage);
- }
-
- public String getSummary() {
- return summary;
- }
-
- /**
- * The synchronization summary. Free form textual report that will be stored with the
content source sync report.
- *
- * @param summary should not be <code>null</code>
- */
- public void setSummary(String summary) {
- this.summary = summary;
- }
-
- @Override
- public String toString() {
- return "PackageSyncReport: new=[" + newPackages.size() + "],
updated=[" + updatedPackages.size()
- + "], deleted=[" + deletedPackages.size() + "]";
- }
-}
\ No newline at end of file
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoDetails.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoDetails.java
deleted file mode 100644
index 7d6ff58..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoDetails.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
-* 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, 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.core.clientapi.server.plugin.content;
-
-/**
- * Contains the information used to describe a single repo being introduced to the system
through the
- * {@link RepoSource} interface. The parent-child relationship between repos is done
through the call to
- * {@link #setParentRepoName(String)}.
- *
- * @author Jason Dobies
- */
-public class RepoDetails {
-
- private String name;
- private String description;
-
- private String parentRepoName;
-
- private String repoGroup;
-
- public RepoDetails(String name) {
- setName(name);
- }
-
- public RepoDetails(String name, String parentRepoName) {
- setName(name);
- setParentRepoName(parentRepoName);
- }
-
- /**
- * Returns the identifying name of the repo.
- *
- * @return cannot be <code>null</code>
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the name of the repo being represented.
- *
- * @param name cannot be <code>null</code>
- * @throws IllegalArgumentException is name is <code>null</code>
- */
- public void setName(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
- }
-
- this.name = name;
- }
-
- /**
- * Returns the name (identifier) of the parent repo for this repo. The name returned
here should match up with
- * the name returned the call to {@link #getName()} on the parent repo.
- *
- * @return may be <code>null</code>
- */
- public String getParentRepoName() {
- return parentRepoName;
- }
-
- /**
- * Sets the name of the parent repo to associate this repo with. See {@link
#getParentRepoName()} for more
- * details.
- *
- * @param parentRepoName may be <code>null</code>
- */
- public void setParentRepoName(String parentRepoName) {
- this.parentRepoName = parentRepoName;
- }
-
- /**
- * Returns a user-readable description of what the repo contains.
- *
- * @return may be <code>null</code>
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * Sets the name of the user-readable description of the repo contents.
- *
- * @param description may be <code>null</code>
- */
- public void setDescription(String description) {
- this.description = description;
- }
-
- /**
- * Returns the name (used to identify the group in the server) of the group the repo
should be belong to
- * when it is imported.
- *
- * @return may be <code>null</code>
- */
- public String getRepoGroup() {
- return repoGroup;
- }
-
- /**
- * Sets the name of the group to assign this repo to. If the group doesn't exist
in the system or elsewhere in
- * the import repos report, the repo will be created with no group membership.
- *
- * @param repoGroup may be <code>null</code> to indicate the repo does
not belong to a group
- */
- public void setRepoGroup(String repoGroup) {
- this.repoGroup = repoGroup;
- }
-}
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoGroupDetails.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoGroupDetails.java
deleted file mode 100644
index 707fcac..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoGroupDetails.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-* RHQ Management Platform
-* Copyright (C) 2009 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.core.clientapi.server.plugin.content;
-
-/**
- * Represents a repo group being introduced by a repo source.
- *
- * @author Jason Dobies
- *
- * @see RepoSource
- */
-public class RepoGroupDetails {
-
- private String name;
- private String typeName;
- private String description;
-
- public RepoGroupDetails(String name, String typeName) {
- setName(name);
- setTypeName(typeName);
- }
-
- /**
- * Returns the name of the group.
- *
- * @return will not be <code>null</code>
- */
- public String getName() {
- return name;
- }
-
- /**
- * Sets the name of the group being represented.
- *
- * @param name cannot be <code>null</code>
- */
- public void setName(String name) {
- if (name == null) {
- throw new IllegalArgumentException("name cannot be null");
- }
-
- this.name = name;
- }
-
- /**
- * Returns the name of the type of group this instance represents.
- *
- * @return will not be <code>null</code>
- */
- public String getTypeName() {
- return typeName;
- }
-
- /**
- * Sets the name of the group type this repo belongs to.
- *
- * @param typeName cannot be <code>null</code>
- */
- public void setTypeName(String typeName) {
- if (typeName == null) {
- throw new IllegalArgumentException("typeName cannot be null");
- }
-
- this.typeName = typeName;
- }
-
- /**
- * Returns the description of what this type represents.
- *
- * @return may be <code>null</code>
- */
- public String getDescription() {
- return description;
- }
-
- /**
- * Sets the description the group type should display to users.
- *
- * @param description may be <code>null</code>
- */
- public void setDescription(String description) {
- this.description = description;
- }
-}
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoImportReport.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoImportReport.java
deleted file mode 100644
index 2035db7..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoImportReport.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-* RHQ Management Platform
-* Copyright (C) 2009 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.core.clientapi.server.plugin.content;
-
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Holds on to the repos and repo groups to be imported into the server through a {@link
RepoSource}.
- *
- * @author Jason Dobies
- */
-public class RepoImportReport {
-
- private List<RepoDetails> repos = new ArrayList<RepoDetails>();
- private List<RepoGroupDetails> repoGroups = new
ArrayList<RepoGroupDetails>();
-
- public RepoImportReport() {
- }
-
- public List<RepoDetails> getRepos() {
- return repos;
- }
-
- public void addRepo(RepoDetails repo) {
- repos.add(repo);
- }
-
- public void addRepos(Collection<RepoDetails> repos) {
- repos.addAll(repos);
- }
-
- public List<RepoGroupDetails> getRepoGroups() {
- return repoGroups;
- }
-
- public void addRepoGroup(RepoGroupDetails repoGroup) {
- repoGroups.add(repoGroup);
- }
-
- public void addRepoGroups(Collection<RepoGroupDetails> repoGroups) {
- repoGroups.addAll(repoGroups);
- }
-}
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoSource.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoSource.java
deleted file mode 100644
index 6cff5e4..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/RepoSource.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-* 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, 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.core.clientapi.server.plugin.content;
-
-/**
- * Indicates a content provider has the capability to provide repos into the server. Repo
synchronization will be
- * done through calls defined in this interface. This interface should use the
configuration settings
- * passed into the plugin through {@link
ContentProvider#initialize(org.rhq.core.domain.configuration.Configuration)}
- *
- * @author Jason Dobies
- */
-public interface RepoSource {
-
- /**
- * Requests the content provider return a list of all repos it wants to ensure exist
in the server. This call
- * should return the current state of the repos as known to the content provider, not
a diff of what has
- * changed from the previous call to it. The server will resolve the differences.
- *
- * @return contains a list of all groups and repos to be imported into the system
- * @throws Exception if there is an error retrieving the repos that should be
reported to the user
- */
- RepoImportReport importRepos() throws Exception;
-
-}
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/metadata/ContentSourcePluginMetadataManager.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/metadata/ContentSourcePluginMetadataManager.java
deleted file mode 100644
index a45f882..0000000
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/server/plugin/content/metadata/ContentSourcePluginMetadataManager.java
+++ /dev/null
@@ -1,201 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content.metadata;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.rhq.core.clientapi.agent.metadata.ConfigurationMetadataParser;
-import
org.rhq.core.clientapi.descriptor.serverplugin.content.ContentSourcePluginDescriptor;
-import
org.rhq.core.clientapi.descriptor.serverplugin.content.ContentSourceTypeDefinition;
-import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
-import org.rhq.core.domain.content.ContentSourceType;
-import org.rhq.core.domain.content.DownloadMode;
-
-/**
- * This is meant to provide an interface to the underlying metadata of a server plugin
for content. It will load,
- * translate and cache the metadata for the rest of the services in the form of the
domain object classes and the jaxb
- * version of the descriptors.
- *
- * @author John Mazzitelli
- */
-public class ContentSourcePluginMetadataManager {
- private Log log = LogFactory.getLog(ContentSourcePluginMetadataManager.class);
-
- // outer map is keyed by plugin name; inner map keyed by content source type name
- private Map<String, Map<String, ContentSourceType>> loadedPlugins;
-
- public ContentSourcePluginMetadataManager() {
- loadedPlugins = new HashMap<String, Map<String,
ContentSourceType>>();
- }
-
- /**
- * This will remove all knowledge of the given plugin - that is, all content source
types deployed by the plugin
- * will be removed from this manager.
- *
- * @param pluginName the plugin whose types are to be removed
- */
- public synchronized void unloadPlugin(String pluginName) {
- loadedPlugins.remove(pluginName);
- }
-
- /**
- * Transforms the pluginDescriptor into domain object form and stores those objects.
- *
- * @param pluginDescriptor the descriptor to transform
- *
- * @return the new content source types represented by this descriptor (not a copy)
- */
- public synchronized Collection<ContentSourceType>
loadPlugin(ContentSourcePluginDescriptor pluginDescriptor) {
- try {
- Map<String, ContentSourceType> pluginTypes =
loadedPlugins.get(pluginDescriptor.getName());
-
- if (pluginTypes != null) {
- pluginTypes.clear(); // this is a redeploy, delete the original types
- } else {
- pluginTypes = new HashMap<String, ContentSourceType>();
- loadedPlugins.put(pluginDescriptor.getName(), pluginTypes);
- }
-
- for (ContentSourceTypeDefinition newType :
pluginDescriptor.getContentSourceType()) {
- // TODO: right now, content source types cannot have the same name as any
other one
- // even if defined in another plugin (i.e plugin's content
types are not scoped)
- // Do we care? This just means one plugin dev cannot name a
content source type
- // something that another plugin dev used already in another
plugin.
- if (getContentSourceType(newType.getName()) == null) {
- // create the new domain object represented by the XML
- ContentSourceType contentSourceType = new ContentSourceType();
- contentSourceType.setName(newType.getName());
- contentSourceType.setDisplayName(newType.getDisplayName());
- contentSourceType.setDescription(newType.getDescription());
- contentSourceType.setPluginName(pluginDescriptor.getName());
- contentSourceType.setDefaultLazyLoad(newType.isLazyLoad());
-
contentSourceType.setDefaultDownloadMode(DownloadMode.valueOf(newType.getDownloadMode()
- .toUpperCase()));
- contentSourceType.setDefaultSyncSchedule(newType.getSyncSchedule());
- contentSourceType.setContentSourceApiClass(newType.getApiClass());
-
- ConfigurationDefinition configDef =
ConfigurationMetadataParser.parse(newType.getName(), newType
- .getConfiguration());
-
contentSourceType.setContentSourceConfigurationDefinition(configDef);
-
- // add the new domain object to the list of domain objects for this
plugin
- pluginTypes.put(contentSourceType.getName(), contentSourceType);
- } else {
- throw new Exception("Cannot redefine an existing content source
type:" + newType.getName());
- }
- }
-
- return pluginTypes.values();
- } catch (Exception e) {
- log.error("Error transforming plugin descriptor [" +
pluginDescriptor.getName() + "]", e);
- }
-
- return null;
- }
-
- /**
- * Returns the {@link ContentSourceType} that has the given name. If no plugin
defined a type with that name, <code>
- * null</code> is returned.
- *
- * @param typeName the name of the content source type to return
- *
- * @return the content source type with the given name or
<code>null</code> if none exists
- */
- public synchronized ContentSourceType getContentSourceType(String typeName) {
- for (Map<String, ContentSourceType> pluginTypes : loadedPlugins.values())
{
- ContentSourceType type = pluginTypes.get(typeName);
- if (type != null) {
- return type;
- }
- }
-
- return null;
- }
-
- /**
- * Returns all the {@link ContentSourceType}s that have been defined in all plugins.
- *
- * @return all content source types defined; will be empty if there are none
- */
- public synchronized Set<ContentSourceType> getAllContentSourceTypes() {
- Set<ContentSourceType> allTypes = new HashSet<ContentSourceType>();
-
- for (Map<String, ContentSourceType> pluginTypes : loadedPlugins.values())
{
- allTypes.addAll(pluginTypes.values());
- }
-
- return allTypes;
- }
-
- /**
- * Returns the names of all plugins that defined content source types.
- *
- * @return all plugin names
- */
- public synchronized Set<String> getPluginNames() {
- return this.loadedPlugins.keySet();
- }
-
- /**
- * Returns the {@link ContentSourceType}s defined by the given plugin. If there is no
plugin with that name, <code>
- * null</code> is returned.
- *
- * @param pluginName the name of the plugin whose types are to be returned
- *
- * @return the content source types defined by the given plugin or
<code>null</code> if no plugin exists with that
- * name - the returned collection is not a copy, its backed by this manager
- */
- public synchronized Collection<ContentSourceType>
getContentSourceTypesByPlugin(String pluginName) {
- Map<String, ContentSourceType> pluginTypes =
loadedPlugins.get(pluginName);
-
- if (pluginTypes == null) {
- return null;
- }
-
- return pluginTypes.values();
- }
-
- /**
- * Returns the name of the plugin that deployed the given content source type.
<code>null</code> will be returned if
- * unknown.
- *
- * @param type the name of the plugin that deployed this type is to be returned
- *
- * @return name of the plugin
- */
- public synchronized String getPluginNameFromContentSourceType(ContentSourceType type)
{
- Set<String> pluginNames = loadedPlugins.keySet();
- for (String pluginName : pluginNames) {
- if (loadedPlugins.get(pluginName).containsValue(type)) {
- return pluginName;
- }
- }
-
- return null;
- }
-}
\ No newline at end of file
diff --git
a/modules/core/client-api/src/main/resources/rhq-contentsource-packagedetails.xsd
b/modules/core/client-api/src/main/resources/rhq-contentsource-packagedetails.xsd
deleted file mode 100644
index 7ece6dc..0000000
--- a/modules/core/client-api/src/main/resources/rhq-contentsource-packagedetails.xsd
+++ /dev/null
@@ -1,381 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
-<xs:schema
-
xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns:rhq="urn:xmlns:rhq-contentsource-packagedetails"
- targetNamespace="urn:xmlns:rhq-contentsource-packagedetails"
- elementFormDefault="qualified"
- jaxb:version="2.0"
-
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
- blockDefault="">
-
- <xs:annotation>
- <xs:documentation>
- Schema for content source package details metadata. This schema will provide the
structure
- that XML content sources (e.g. HttpSource) will use for their XML index files.
This is
- how such content sources can advertise what content they have available.
- </xs:documentation>
- <xs:appinfo>
- <jaxb:schemaBindings>
- <jaxb:package
name="org.rhq.core.clientapi.descriptor.contentsource.packagedetails" />
- </jaxb:schemaBindings>
- </xs:appinfo>
- </xs:annotation>
-
- <xs:complexType name="packageDetailsKeyType">
- <xs:annotation>
- <xs:documentation>
- The key to details of a package that a content source
- provides. This key is used when referring to a package
- version found in the remote content source repository.
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:element name="name">
- <xs:annotation>
- <xs:documentation>
- The name of the package.This name, combined with the
- version, identifies an individual package within its
- package type family.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="version">
- <xs:annotation>
- <xs:documentation>
- The version of the package. The format of this
- attribute will vary based on the package and the
- package type.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="package-type-name">
- <xs:annotation>
- <xs:documentation>
- Fully qualified name of the package type which defines
- the family of packages that this package belongs to
- (e.g. "rpm"). This is defined in the product plugin where
- the package type is defined.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="architecture-name">
- <xs:annotation>
- <xs:documentation>
- The architecture on which this package can be
- deployed. If there is no specific architecture that is
- associated with this package, then "noarch" should be
- used.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="resource-type-name">
- <xs:annotation>
- <xs:documentation>
- The name of the resource type for which this package
- is applicable. In other words, this is the resource
- type on which this package can be deployed. Because a
- resource type name itself is not unique, this type
- name must be paired with the product plugin name that defines
- the resource type.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="resource-type-plugin">
- <xs:annotation>
- <xs:documentation>
- The name of the product plugin that defined the resource type
- for which this package is applicable.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
-
- <xs:complexType name="packageDetailsType">
- <xs:sequence>
- <xs:element name="package-details-key"
type="rhq:packageDetailsKeyType">
- </xs:element>
- <xs:element name="resource-versions"
type="rhq:resourceVersionsType" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The versions of the resource type which this package
- is applicable. In other words, this package is
- deployable only on resources that match these version
- strings.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- <xs:element name="display-name" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The human-readable name of the package suitable to be
- displayed on a user interface.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="display-version" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The human-readable version of the package suitable to
- be displayed on a user interface.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="short-description" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- Just a few words that briefly describe this package.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="long-description" type="xs:string"
minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The details that describe this package.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- <xs:element name="classification" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- Provides additional classification metadata to
- describe the package. The possible values for this
- attribute will vary based on package type. For
- instance, two packages of the same package type may be
- differentiated as a "bug fix" or a "security
update".
- Another way to use this would be to group packages
- together, such as "System Patches" or
"Applications".
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="file-name" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The name of the file that this package should be
- stored as. This typically is a combination of the
- package name and version, but it is not required to be
- so.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="file-size" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The size, in bytes, of the package content.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:long">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="file-created-date" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The date and time when the original content was
- created. This value is specified in epoch milliseconds.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:long">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="md5" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The package content's md5 hashcode.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="sha256" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The package content's sha256 hashcode.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="license-name" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The name of the license that governs the usage of the
- package.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="license-version" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- The version of the license that governs the usage of
- the package.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- <xs:element name="metadata" type="xs:string"
minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- Generic metadata that is used to extend the metadata
- for a particular package. This metadata is custom for
- a particular package type and can include things such
- as install instructions or errata information.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- <xs:element name="extra-properties"
type="rhq:configurationType" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- If the package type defines an extra set of custom
- properties, these are this package's property values.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- <xs:element name="location" minOccurs="0"
maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- Defines the location where this package's content can
- be found on the content source remote repository.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
-
- <xs:complexType name="resourceVersionsType">
- <xs:sequence>
- <xs:element name="resource-version" minOccurs="1"
maxOccurs="unbounded">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse"></xs:whiteSpace>
- </xs:restriction>
- </xs:simpleType>
- </xs:element>
- </xs:sequence>
- </xs:complexType>
-
- <xs:complexType name="packageType">
- <xs:sequence>
- <xs:element name="package" type="rhq:packageDetailsType"
minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="packages"
type="rhq:packageType"></xs:element>
-
- <!-- configuration property values schema -->
-
- <xs:complexType name="configurationType">
- <xs:annotation>
- <xs:documentation>Describes all configurable
elements.</xs:documentation>
- </xs:annotation>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element name="simple-property"
type="rhq:simplePropertyType" />
- <xs:element name="list-property"
type="rhq:listPropertyType" />
- <xs:element name="map-property"
type="rhq:mapPropertyType" />
- </xs:choice>
- </xs:complexType>
-
- <xs:complexType name="simplePropertyType">
- <xs:simpleContent>
- <xs:extension base="xs:string">
- <xs:attribute name="name" type="xs:string"/>
- </xs:extension>
- </xs:simpleContent>
- </xs:complexType>
-
- <xs:complexType name="listPropertyType">
- <xs:complexContent>
- <xs:extension base="rhq:configurationType">
- <xs:attribute name="name" type="xs:string"/>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
-
- <xs:complexType name="mapPropertyType">
- <xs:complexContent>
- <xs:extension base="rhq:configurationType">
- <xs:attribute name="name" type="xs:string"/>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
-
-</xs:schema>
diff --git a/modules/core/client-api/src/main/resources/rhq-perspective.xsd
b/modules/core/client-api/src/main/resources/rhq-perspective.xsd
deleted file mode 100644
index 0d25e69..0000000
--- a/modules/core/client-api/src/main/resources/rhq-perspective.xsd
+++ /dev/null
@@ -1,163 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
-
-<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns:rhq="urn:xmlns:rhq-perspective"
- targetNamespace="urn:xmlns:rhq-perspective"
- elementFormDefault="qualified"
- jaxb:version="2.0"
-
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
blockDefault="">
-
-
-
- <xs:annotation>
- <xs:documentation>Schema for the definition Perspective service objects
- </xs:documentation>
- <xs:appinfo>
- <jaxb:schemaBindings>
- <jaxb:package
name="org.rhq.core.clientapi.descriptor.perspective"/>
- </jaxb:schemaBindings>
- </xs:appinfo>
- </xs:annotation>
-
-
- <xs:element name="perspective">
- <xs:annotation>
- <xs:documentation>
-Perspective is a collection of user interface screens and defined URL access points to
-get to high level functionality within the Perspective.
-
- Fields:
-
- name: Name of the Perspective.
-
- url: Root URL of the Perspective.
-
- description: Description of Perspective
-
- tasks: The set of Tasks this Perspective 'owns' and shares as available for
users to
- navigate to.
-
- navigation: The List of NavigationItem objects associated with this Perspective.
- NavigationItems are name/path pairs that represent high level navigation links this
- Perspective desires to show. Examples would for an Administration Perspective:
-
- Name , Path
- Users , /admin/users
- Systems , /admin/systems
- Configuration, /admin/configuration
-
- </xs:documentation>
- <xs:appinfo>
- <jaxb:class name="Perspective"/>
- </xs:appinfo>
- </xs:annotation>
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="rhq:task" minOccurs="0"
maxOccurs="unbounded">
- <xs:annotation>
- <xs:documentation>
- Defines child server types that can be embedded in this server
type.
- </xs:documentation>
- <xs:appinfo>
- <jaxb:property name="tasks" />
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
- <xs:element ref="rhq:navigationitem" minOccurs="0"
maxOccurs="unbounded">
- <xs:annotation>
- <xs:documentation>
- Defines child server types that can be embedded in this server
type.
- </xs:documentation>
- <xs:appinfo>
- <jaxb:property name="navigationItems" />
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
- </xs:sequence>
- <xs:attribute name="name" use="required"
type="xs:string"/>
- <xs:attribute name="path" type="xs:string"/>
- <xs:attribute name="description"
type="xs:string"/>
-
- </xs:complexType>
- </xs:element>
-
-
- <xs:element name="task">
- <xs:annotation>
- <xs:documentation>
-Tasks are high level UI concepts that a Perspectives are responsible for. The Task will
-provide a URL that allows the user to access the starting point for that Task.
-
-For example, common tasks in most web applications involve creation and management of
-Users of the system. A common task in managing users is the step of actually creating a
-User. In order to designate the starting point for creating a user you would create a
-Task object:
-
-Task.name = "user create"
-Task.url = "/users/create"
-Task.display = "Create a new User in the system"
-Task.urlmatches = "/users/*"
-
-Fields:
-
-The name field is a progmatically referenceable name that isn't intended to change.
Code
-will reference Tasks by name.
-
-The url field will allow UIs to build a link to the Task's starting point.
-
-The display can be used when linking to the Task to show a display value describing what
-the Task does
-
-The urlmatches is used to indicate a list of URLs that this Task should be visible to.
-This can allow GUI developers a way to specify the relationship of this Task to specific
-pages or a tree of URLs. The above example indicates that urlmatches is
"/users/*" which
-is an indication that the task is relative to all the pages in the /users tree of URLs.
-This can be used by a page rendering to show a link to the 'user create' Task if
the user
-was looking at a page with a path starting with /users/
- </xs:documentation>
- <xs:appinfo>
- <jaxb:class name="Task"/>
- </xs:appinfo>
- </xs:annotation>
- <xs:complexType>
- <xs:sequence>
- <xs:element name="pathmatches" type="xs:string"
minOccurs="0" maxOccurs="unbounded">
- <xs:annotation>
- <xs:documentation>
- The pathMatches is used to indicate a list of rooted paths that this
Task should be visible to.
- This can allow GUI developers a way to specify the relationship of
this Task to specific
- pages or a tree of URLs. The above example indicates that urlmatches
is "/users/*" which
- is an indication that the task is relative to all the pages in the
/users tree of URLs.
- This can be used by a page rendering to show a link to the 'user
create' Task if the user
- was looking at a page with a path starting with /users/
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- </xs:sequence>
-
- <xs:attribute name="name" use="required"
type="xs:string"/>
- <xs:attribute name="path" use="required"
type="xs:string"/>
- <xs:attribute name="description" type="xs:string"/>
- <xs:attribute name="context" type="xs:string"/>
- </xs:complexType>
- </xs:element>
-
- <xs:element name="navigationitem">
- <xs:annotation>
- <xs:documentation>
-NavigationItem is a class that represents named paths that a Perspective can show in a
-GUI to get to high-level areas of a Perspective's pages. An example would be:
Typical web
-applications include a Top Level navigation bar. You could represent a Perspective's
top
-nav with a set of NavigationItems
- </xs:documentation>
- <xs:appinfo>
- <jaxb:class name="NavigationItem"/>
- </xs:appinfo>
- </xs:annotation>
- <xs:complexType>
- <xs:attribute name="name" use="required"
type="xs:string"/>
- <xs:attribute name="path" type="xs:string"/>
- </xs:complexType>
- </xs:element>
-
-</xs:schema>
diff --git a/modules/core/client-api/src/main/resources/rhq-serverplugin-content.xsd
b/modules/core/client-api/src/main/resources/rhq-serverplugin-content.xsd
deleted file mode 100644
index d221e1f..0000000
--- a/modules/core/client-api/src/main/resources/rhq-serverplugin-content.xsd
+++ /dev/null
@@ -1,180 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
-
-<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns:config="urn:xmlns:rhq-configuration"
- xmlns:rhq="urn:xmlns:rhq-serverplugin.content"
- targetNamespace="urn:xmlns:rhq-serverplugin.content"
- elementFormDefault="qualified"
- jaxb:version="2.0"
-
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
blockDefault="">
-
- <xs:import namespace="urn:xmlns:rhq-configuration"
schemaLocation="rhq-configuration.xsd"/>
-
- <xs:annotation>
- <xs:documentation>
- Schema for server-side content source plugins. These plugins will provide
- implementations that allow remote repositories to feed content into
- the server's content subsystem.
- </xs:documentation>
- <xs:appinfo>
- <jaxb:schemaBindings>
- <jaxb:package
name="org.rhq.core.clientapi.descriptor.serverplugin.content"/>
- </jaxb:schemaBindings>
- </xs:appinfo>
- </xs:annotation>
-
- <xs:element name="plugin">
- <xs:annotation>
- <xs:documentation>
- Root of a plugin representing a set of defined server content source
implementations.
- </xs:documentation>
- <xs:appinfo>
- <jaxb:class name="ContentSourcePluginDescriptor"/>
- </xs:appinfo>
- </xs:annotation>
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="rhq:contentSourceType" minOccurs="1"
maxOccurs="unbounded">
- <xs:annotation>
- <xs:documentation>
- Defines a supported content source type that is able to feed content
into the server.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- </xs:sequence>
- <xs:attribute name="name" use="required">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:minLength value="1"/>
- <xs:maxLength value="200"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
-
- <xs:element name="contentSourceType">
- <xs:annotation>
- <xs:appinfo>
- <jaxb:class name="ContentSourceTypeDefinition" />
- </xs:appinfo>
- </xs:annotation>
- <xs:complexType>
- <xs:sequence>
- <xs:element name="configuration"
type="config:configuration" minOccurs="0" maxOccurs="1">
- <xs:annotation>
- <xs:documentation>
- Defines the configuration properties that must be set when creating
a
- content source of this type. Typically, this will define the
properties
- necessary for specifying how to connect to the underlying source.
- </xs:documentation>
- </xs:annotation>
- </xs:element>
- </xs:sequence>
- <xs:attribute name="name" use="required">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:minLength value="1"/>
- <xs:maxLength value="200"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="displayName" use="optional">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:minLength value="1"/>
- <xs:maxLength value="200"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="description" use="optional">
- <xs:annotation>
- <xs:documentation>
- Describes this type of content source. This usually
- provides information such as what type of remote endpoint
- the content source uses (http or some kind of file
- transport protocol) and the types of packages the content
- source can serve up, if known.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:minLength value="1"/>
- <xs:maxLength value="500"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="lazyLoad" use="required"
type="xs:boolean">
- <xs:annotation>
- <xs:documentation>
- If set to true, the content bits for all packages coming from
- content sources of this type will, by default, only be loaded on
demand.
- This means the package contents will only be loaded when they are
- asked for the very first time. If false, the default for all content
- sources of this type will be that they should attempt to download all
- packages as soon as possible. Note that this is only the default,
- suggested value. When creating a content source, the user will be
- given the chance to override this default.
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="downloadMode" use="optional"
default="database">
- <xs:annotation>
- <xs:documentation>
- Indicates where (and even if) package bits are
- downloaded, when they are downloaded. If 'never', then
- package bits are never downloaded from the content
- source, effectively creating a pass-through directly
- to the remote repository for every request for package
- bits. If 'database', when package bits are downloaded,
- they are stored in the database. If 'filesystem',
- package bits will be stored somewhere on the
- filesystem.
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value="never"></xs:enumeration>
- <xs:enumeration
value="database"></xs:enumeration>
- <xs:enumeration
value="filesystem"></xs:enumeration>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="syncSchedule" use="optional"
type="xs:string" default="0 0 3 * * ?">
- <xs:annotation>
- <xs:documentation>
- Periodically, the content source plugin adapter will be asked to
- synchronize with the remote content source repository. This gives
- the adapter a chance to see if any content has been added, updated
- or removed from the remote repository.
- This attribute defines the schedule, as a cron string. The default
- will be set for everyday at 3:00am local time. If you never want
- the content source to be automatically synced, set this value to
- an empty string.
- For documentation on the syntax of this cron string, please see:
-
http://www.opensymphony.com/quartz/wikidocs/CronTriggers%20Tutorial.html
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="apiClass" type="rhq:classNameType"
use="required">
- <xs:annotation>
- <xs:documentation>
- This specifies the fully qualified class name of the
- implementation class that provides a way for the server
- to interface with the remote content store. This API
- class must implement the ContentSourceAdapter interface.
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
-
- <xs:simpleType name="classNameType">
- <xs:restriction base="xs:string">
- <xs:whiteSpace value="collapse" />
- <xs:minLength value="1" />
- <xs:maxLength value="100" />
- <xs:pattern
value="[a-zA-Z_][a-zA-Z_0-9]*(.[a-zA-Z_][a-zA-Z_0-9]*)*" />
- </xs:restriction>
- </xs:simpleType>
-</xs:schema>
\ No newline at end of file
diff --git
a/modules/core/client-api/src/test/java/org/rhq/core/clientapi/server/plugin/content/ContentSourcePackageDetailsKeyTest.java
b/modules/core/client-api/src/test/java/org/rhq/core/clientapi/server/plugin/content/ContentSourcePackageDetailsKeyTest.java
deleted file mode 100644
index d889e03..0000000
---
a/modules/core/client-api/src/test/java/org/rhq/core/clientapi/server/plugin/content/ContentSourcePackageDetailsKeyTest.java
+++ /dev/null
@@ -1,69 +0,0 @@
- /*
- * 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, 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.core.clientapi.server.plugin.content;
-
-import org.testng.annotations.Test;
-
-@Test
-public class ContentSourcePackageDetailsKeyTest {
- public void testEqualsHashcode() {
- ContentProviderPackageDetailsKey key1;
- ContentProviderPackageDetailsKey key2;
-
- key1 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "rt1", "plugin1");
- key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "rt1", "plugin1");
- assert key1.equals(key2);
- assert key2.equals(key1);
- assert key1.hashCode() == key2.hashCode();
-
- key2 = new ContentProviderPackageDetailsKey("BLAH", "ver1",
"pt1", "arch1", "rt1", "plugin1");
- assert !key1.equals(key2);
- assert !key2.equals(key1);
- assert key1.hashCode() != key2.hashCode();
-
- key2 = new ContentProviderPackageDetailsKey("name1", "BLAH",
"pt1", "arch1", "rt1", "plugin1");
- assert !key1.equals(key2);
- assert !key2.equals(key1);
- assert key1.hashCode() != key2.hashCode();
-
- key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"BLAH", "arch1", "rt1", "plugin1");
- assert !key1.equals(key2);
- assert !key2.equals(key1);
- assert key1.hashCode() != key2.hashCode();
-
- key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "BLAH", "rt1", "plugin1");
- assert !key1.equals(key2);
- assert !key2.equals(key1);
- assert key1.hashCode() != key2.hashCode();
-
- key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "BLAH", "plugin1");
- assert !key1.equals(key2);
- assert !key2.equals(key1);
- assert key1.hashCode() != key2.hashCode();
-
- key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "rt1", "BLAH");
- assert !key1.equals(key2);
- assert !key2.equals(key1);
- assert key1.hashCode() != key2.hashCode();
- }
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginClassLoader.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginClassLoader.java
deleted file mode 100644
index 9203edc..0000000
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginClassLoader.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * 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.enterprise.server.plugin.content;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-/**
- * Classloader for the plugin jar itself and any embedded lib/* jars. TODO: ghinkle, Dec
14, 2006: Consider using a
- * deepjar: direct style classloader instead of the temporary file system.
- */
-// Note that this is almost a direct copy of the agent-side plugin container's
PluginClassLoader
-public class ContentProviderPluginClassLoader extends URLClassLoader {
- private File embeddedJarsDirectory = null;
-
- public ContentProviderPluginClassLoader(URL[] urls, ClassLoader parent) {
- super(urls, parent);
- }
-
- public void destroy() {
- purge(embeddedJarsDirectory, true);
- }
-
- public static ContentProviderPluginClassLoader create(String pluginJarName, URL
pluginUrl, boolean unpackNestedJars,
- ClassLoader parent, File tmpDirectory) throws Exception {
- return create(pluginJarName, new URL[] { pluginUrl }, unpackNestedJars, parent,
tmpDirectory);
- }
-
- public static ContentProviderPluginClassLoader create(String pluginJarName, URL[]
pluginUrls,
- boolean unpackNestedJars, ClassLoader parent, File tmpDirectory) throws Exception
{
- List<URL> classpathUrlList = new ArrayList<URL>();
- File unpackedDirectory = null;
-
- for (URL pluginUrl : pluginUrls) {
- classpathUrlList.add(pluginUrl);
-
- if (unpackNestedJars) {
- try {
- unpackedDirectory = unpackEmbeddedJars(pluginJarName, pluginUrl,
classpathUrlList, tmpDirectory);
- } catch (Exception e) {
- throw new Exception("Failed to unpack embedded JARs within:
" + pluginUrl);
- }
- }
- }
-
- URL[] classpath = classpathUrlList.toArray(new URL[classpathUrlList.size()]);
- ContentProviderPluginClassLoader newLoader = new
ContentProviderPluginClassLoader(classpath, parent);
- newLoader.embeddedJarsDirectory = unpackedDirectory;
-
- return newLoader;
- }
-
- /**
- * Unpacks all lib/* resources into a temporary directory, adds URLs to those newly
extracted resources and returns
- * the directory where the jars were extracted. This will actually create a unique
subdirectory under the given
- * <code>tmpDirectory</code>) which is where the extracted resources will
be placed. If the give <code>
- * tmpDirectory</code> is <code>null</code>, the standard
platform's tmp directory will be used.
- *
- * @param pluginJarName name of the main plugin jar, used as part of the name to the
tmp directory
- * @param pluginUrl the URL to the main plugin jar we are unpacking
- * @param urls the URLs to the tmp directory resources that were unpacked
- * @param tmpDirectory the parent directory that will contain the child directory
which will contain all extracted
- * resources
- *
- * @return the location where all the extract files are now located
- *
- * @throws IOException
- */
- private static File unpackEmbeddedJars(String pluginJarName, URL pluginUrl,
List<URL> urls, File tmpDirectory)
- throws IOException {
- InputStream pluginStream = pluginUrl.openStream();
- ZipInputStream zis = new ZipInputStream(new BufferedInputStream(pluginStream));
- ZipEntry entry;
- File extractionDirectory = null; // this is where we will actually store the
files we extract
-
- try {
- while ((entry = zis.getNextEntry()) != null) {
- String entryName = entry.getName();
-
- // Only care about entries in the lib directory
- if (entryName.startsWith("lib") && (entryName.length()
> 4)) {
- if (extractionDirectory == null) {
- extractionDirectory = createTempDirectory(tmpDirectory,
pluginJarName);
- }
-
- int i = entryName.lastIndexOf('/');
- if (i < 0) {
- i = entryName.lastIndexOf('\\');
- }
-
- String s = entryName.substring(i + 1);
-
- File file = null;
- try {
- if (s.endsWith(".jar")) {
- file = File.createTempFile(s, null, extractionDirectory);
- urls.add(file.toURI().toURL());
- } else {
- // All non-jar files are extracted as-is with the
- // same filename.
- file = new File(extractionDirectory, s);
-
- // since we have a regular file, we need to make sure the tmp
dir is in classpath so it can be found
- URL tmpUrl = extractionDirectory.toURI().toURL();
- if (!urls.contains(tmpUrl)) {
- urls.add(tmpUrl);
- }
- }
-
- BufferedOutputStream outputStream;
- try {
- outputStream = new BufferedOutputStream(new
FileOutputStream(file));
- } catch (FileNotFoundException ex) {
- if (file.exists() && (file.length() > 0)) {
- // e.g. on win32, agent running w/ dll loaded
PluginDumper cannot overwrite file inuse.
- continue;
- }
-
- throw ex;
- }
-
- try {
- file.deleteOnExit();
-
- BufferedInputStream inputStream = new
BufferedInputStream(zis);
-
- int count = 0;
- byte[] b = new byte[8192];
- while ((count = inputStream.read(b)) > -1) {
- outputStream.write(b, 0, count);
- }
- } finally {
- outputStream.flush();
- outputStream.close();
- }
- } catch (IOException ioe) {
- if (file != null) {
- file.delete();
- }
-
- throw ioe;
- }
- }
- }
- } finally {
- try {
- zis.close();
- } catch (Exception e) {
- }
- }
-
- return extractionDirectory;
- }
-
- private static File createTempDirectory(File tmpDirectory, String pluginName) throws
IOException {
- // Let's reuse the algorithm the JDK uses to determine a unique name:
- // 1) create a temp file to get a unique name using JDK createTempFile
- // 2) then quickly delete the file and...
- // 3) convert it to a directory
-
- File tmpDir = File.createTempFile(pluginName, ".classloader",
tmpDirectory); // create file with unique name
- boolean deleteOk = tmpDir.delete(); // delete the tmp file and...
- boolean mkdirsOk = tmpDir.mkdirs(); // ...convert it to a directory
-
- if (!deleteOk || !mkdirsOk) {
- throw new IOException("Failed to create temp classloader directory named
[" + tmpDir + "]");
- }
-
- tmpDir.deleteOnExit();
-
- return tmpDir;
- }
-
- private void purge(File dir, boolean deleteIt) {
- if (dir != null) {
- if (dir.isDirectory()) {
- File[] doomedFiles = dir.listFiles();
- if (doomedFiles != null) {
- for (File doomedFile : doomedFiles) {
- purge(doomedFile, true); // call this method recursively
- }
- }
- }
-
- if (deleteIt) {
- dir.delete();
- }
- }
-
- return;
- }
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainer.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainer.java
deleted file mode 100644
index 9aa033e..0000000
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainer.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * 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.enterprise.server.plugin.content;
-
-import java.util.Date;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.quartz.JobDetail;
-import org.quartz.SchedulerException;
-import org.quartz.SimpleTrigger;
-
-import org.rhq.core.domain.content.ContentSource;
-import org.rhq.core.domain.content.PackageVersion;
-import org.rhq.core.clientapi.server.plugin.content.InitializationException;
-import org.rhq.enterprise.server.scheduler.SchedulerLocal;
-import org.rhq.enterprise.server.scheduler.jobs.ContentSourceSyncJob;
-import org.rhq.enterprise.server.util.LookupUtil;
-
-/**
- * The container repsonsible for managing the content source server plugins.
- *
- * @author John Mazzitelli
- */
-public class ContentProviderPluginContainer {
- private static final String SYNC_JOB_GROUP_NAME = "syncContentSource";
-
- private static final Log log =
LogFactory.getLog(ContentProviderPluginContainer.class);
-
- private ContentProviderPluginContainerConfiguration configuration;
- private ContentProviderPluginManager pluginManager;
- private ContentProviderManager adapterManager;
-
- /**
- * Starts the plugin container, which will load all plugins and begin managing them.
- *
- * @param config
- */
- public void initialize(ContentProviderPluginContainerConfiguration config) throws
InitializationException {
- log.debug("Content server plugin container has been initialized with config:
" + config);
-
- this.configuration = config;
- this.pluginManager = createPluginManager();
- this.adapterManager = createAdapterManager(this.pluginManager);
-
- return;
- }
-
- /**
- * Stops all plugins and cleans up after them.
- */
- public void shutdown() {
- log.debug("Content server plugin container is being shutdown");
-
- this.adapterManager.shutdown();
- this.pluginManager.shutdown();
- this.configuration = null;
- }
-
- /**
- * Returns the configuration that this object was initialized with. If this plugin
container was not
- * {@link #initialize(ContentProviderPluginContainerConfiguration)} or has been
{@link #shutdown()}, this will return
- * <code>null</code>.
- *
- * @return the configuration
- */
- public ContentProviderPluginContainerConfiguration getConfiguration() {
- return configuration;
- }
-
- /**
- * Returns the object that is responsible for managing all {@link
org.rhq.core.clientapi.server.plugin.content.ContentProvider adapters} which are the
- * things that know how to download content from a specific {@link ContentSource}.
- *
- * @return adapter manager
- */
- public ContentProviderManager getAdapterManager() {
- return adapterManager;
- }
-
- /**
- * Returns the object that is responsible for managing all plugins and their
metadata.
- *
- * <p>This is protected to only allow subclasses access to this - external
clients to this PC should never have
- * direct access to this plugin manager.</p>
- *
- * @return plugin manager
- */
- protected ContentProviderPluginManager getPluginManager() {
- return pluginManager;
- }
-
- /**
- * This will syncronize the given content source, meaning its {@link PackageVersion}s
will be updated and, if not
- * lazy-loading, will load the package versions that are not loaded yet.
- *
- * <p>Note that this will perform the sync asynchronously in a separate thread.
This is because this sync operation
- * can potentially run for hours and we do not want to block the calling
thread.</p>
- *
- * @param contentSource the content source to sync
- *
- * @throws SchedulerException if failed to schedule the job for immediate execution
- */
- public void syncNow(final ContentSource contentSource) throws SchedulerException {
- // Create our job with a trigger that fires immediately and doesn't repeat.
- // Make the name unique - we may already have our cron job schedules.
- // What happens if this is triggered when our cron job is triggered? the job will
abort and let the current job finish
- JobDetail job = new
JobDetail(ContentSourceSyncJob.createUniqueJobName(contentSource), SYNC_JOB_GROUP_NAME,
- ContentSourceSyncJob.class, false, false, false);
-
- ContentSourceSyncJob.createJobDataMap(contentSource, job);
-
- SimpleTrigger trigger = new SimpleTrigger(job.getName(), job.getGroup());
- trigger.setVolatility(false);
-
- SchedulerLocal scheduler = LookupUtil.getSchedulerBean();
- Date next = scheduler.scheduleJob(job, trigger);
-
- log.info("Scheduled content source sync job [" + job.getName() +
':' + job.getGroup() + "] to fire now at ["
- + next + "] for [" + contentSource + "]");
-
- return;
- }
-
- /**
- * This will schedule the sync job for the given content source. Once the scheduling
is complete, the content
- * source's adapter will be asked to synchronize with the remote content source
according to the time(s) specified
- * in the {@link ContentSource#getSyncSchedule() schedule}.
- *
- * <p>If the content source's sync schedule is empty, this method assumes
it should not be automatically sync'ed so
- * no schedule will be created and this method simply returns.</p>
- *
- * @param contentSource
- *
- * @throws SchedulerException if failed to schedule the job
- */
- public void scheduleSyncJob(ContentSource contentSource) throws SchedulerException {
- String syncSchedule = contentSource.getSyncSchedule();
- if ((syncSchedule == null) || (syncSchedule.trim().length() == 0)) {
- log.debug(contentSource.toString() + " does not define a sync schedule -
not scheduling");
- return;
- }
-
- SchedulerLocal scheduler = LookupUtil.getSchedulerBean();
- scheduler.scheduleCronJob(ContentSourceSyncJob.createJobName(contentSource),
SYNC_JOB_GROUP_NAME,
- ContentSourceSyncJob.createJobDataMap(contentSource, null),
ContentSourceSyncJob.class, true, false,
- syncSchedule);
-
- return;
- }
-
- /**
- * It will schedule one job per adapter such that each adapter is scheduled to be
synchronized as per its defined
- * sync schedule. This must only be called when all content source adapters have been
initialized.
- */
- public void scheduleSyncJobs() {
- if (this.adapterManager != null) {
- for (ContentSource contentSource :
this.adapterManager.getAllContentSources()) {
- try {
- scheduleSyncJob(contentSource);
- } catch (Exception e) {
- log.warn("Could not schedule sync job for content source ["
+ contentSource + "]", e);
- }
- }
- }
-
- return;
- }
-
- /**
- * This will unschedule the sync job for the given content source. Once unscheduled,
the content source's adapter
- * will not be asked to synchronize with the remote content source.
- *
- * @param contentSource
- *
- * @throws SchedulerException if failed to unschedule the job
- */
- public void unscheduleSyncJob(ContentSource contentSource) throws SchedulerException
{
- SchedulerLocal scheduler = LookupUtil.getSchedulerBean();
- scheduler.deleteJob(ContentSourceSyncJob.createJobName(contentSource),
SYNC_JOB_GROUP_NAME);
-
- return;
- }
-
- /**
- * Creates, configures and initializes the plugin manager that the PC will use.
- *
- * <p>This is protected scope so subclasses can define their own plugin manager
to use. This is mainly to support
- * tests.</p>
- *
- * @return the new plugin manager
- */
- protected ContentProviderPluginManager createPluginManager() {
- ContentProviderPluginManager pm = new ContentProviderPluginManager();
- pm.setConfiguration(getConfiguration());
- pm.initialize();
- return pm;
- }
-
- /**
- * Creates, configures and initializes the adapter manager that the PC will use.
- *
- * <p>This is protected scope so subclasses can define their own adapter
manager to use. This is mainly to support
- * tests.</p>
- *
- * @param pluginManager the plugin manager that was {@link #createPluginManager()
created} for use in the PC. The
- * adapter manager can use this to obtain information about
plugins.
- *
- * @return the new adapter manager
- */
- protected ContentProviderManager createAdapterManager(ContentProviderPluginManager
pluginManager)
- throws InitializationException {
- ContentProviderManager am = new ContentProviderManager();
- am.setConfiguration(getConfiguration());
- am.initialize(pluginManager);
- return am;
- }
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainerConfiguration.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainerConfiguration.java
deleted file mode 100644
index d7f1d48..0000000
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginContainerConfiguration.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.enterprise.server.plugin.content;
-
-import java.io.File;
-
-/**
- * A very simple object used to contain content source server plugin container
configuration.
- *
- * @author John Mazzitelli
- */
-public class ContentProviderPluginContainerConfiguration {
- private File pluginDirectory;
- private File tmpDirectory;
-
- public File getPluginDirectory() {
- return pluginDirectory;
- }
-
- public void setPluginDirectory(File pluginDirectory) {
- if (pluginDirectory == null) {
- throw new IllegalArgumentException("pluginDirectory == null");
- }
-
- this.pluginDirectory = pluginDirectory;
- }
-
- public File getTemporaryDirectory() {
- if (tmpDirectory != null) {
- return tmpDirectory;
- }
-
- return new File(System.getProperty("java.io.tmpdir", "."));
- }
-
- public void setTemporaryDirectory(File tmpDir) {
- this.tmpDirectory = tmpDir;
- }
-
- @Override
- public String toString() {
- File pdir = getPluginDirectory();
- File tdir = getTemporaryDirectory();
-
- StringBuilder str = new
StringBuilder("ContentSourcePluginContainerConfiguration: ");
- str.append("plugin-dir=[" + ((pdir != null) ? pdir.getAbsolutePath() :
"<null>"));
- str.append("], tmp-dir=[" + ((tdir != null) ? tdir.getAbsolutePath() :
"<null>"));
- str.append("]");
-
- return str.toString();
- }
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginEnvironment.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginEnvironment.java
deleted file mode 100644
index a5be44a..0000000
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginEnvironment.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.enterprise.server.plugin.content;
-
-import java.io.File;
-import java.net.URL;
-import java.util.jar.JarEntry;
-import java.util.jar.JarInputStream;
-
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
-import javax.xml.bind.ValidationEvent;
-import javax.xml.bind.util.ValidationEventCollector;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.rhq.core.clientapi.descriptor.DescriptorPackages;
-import
org.rhq.core.clientapi.descriptor.serverplugin.content.ContentSourcePluginDescriptor;
-import org.rhq.core.util.exception.WrappedRemotingException;
-
-/**
- * Manages the context of a loaded plugin. This includes a classloader created
specifically for the plugin and access to
- * its XML descriptor file.
- *
- * @author Greg Hinkle
- * @author John Mazzitelli
- */
-// this is almost a direct copy of the agent plugin container's PluginEnvironment
-public class ContentProviderPluginEnvironment {
- private static final Log log =
LogFactory.getLog(ContentProviderPluginEnvironment.class);
-
- private static final String DEFAULT_PLUGIN_DESCRIPTOR_PATH =
"META-INF/rhq-serverplugin-content.xml";
-
- // make these protected mainly to allow unit tests to extend this class to customize
these
- protected URL pluginUrl;
- protected String pluginName;
- protected ClassLoader pluginClassLoader;
- protected ContentSourcePluginDescriptor pluginDescriptor;
- protected String pluginDescriptorPath;
-
- /**
- * Creates a new plugin environment. If <code>classLoader</code> is
specified, it will be used as the environment's
- * classloader and <code>parentClassLoader</code> will be ignored. If
<code>classLoader</code> is <code>null</code>,
- * then a {@link ContentProviderPluginClassLoader} will be created with the given
parent classloader and it will
- * unpack all embedded jars found in the given plugin URL's
<code>/lib</code> directory.
- *
- * @param pluginUrl where the plugin jar is located (may be
<code>null</code>, mainly to support tests)
- * @param classLoader the classloader used by this environment
- * @param parentClassLoader the parent classloader, if
<code>null</code>, will use this class's classloader - this
- * is ignored if <code>classloader</code> is
not <code>null</code>
- * @param tmpdir a directory where the jars are placed when unpacked
- *
- * @throws Exception
- */
- public ContentProviderPluginEnvironment(URL pluginUrl, ClassLoader classLoader,
ClassLoader parentClassLoader,
- File tmpdir) throws Exception {
- initialize(pluginUrl, DEFAULT_PLUGIN_DESCRIPTOR_PATH, classLoader,
parentClassLoader, true, tmpdir);
- }
-
- /**
- * This creates a {@link ContentProviderPluginEnvironment} that will allow you to
specify the plugin's new class
- * loader to not unpack its embedded jars, if they exist. You normally only pass in
<code>false</code> for <code>
- * unpackJars</code> if you only want to process/parse the plugin descriptor
but do not plan on using this
- * environment instance for actual runtime of the plugin (because it won't work
since you haven't unpacked the
- * jars).
- *
- * <p>If you pass in a non-<code>null</code>
<code>classLoader</code>, then both <code>parentClassLoader</code>
and
- * <code>unpackJars</code> is ignored since you are saying you already
know how to find the classes for this
- * environment.</p>
- *
- * @param pluginUrl where the plugin jar is located (may be
<code>null</code>, mainly to support tests)
- * @param classLoader the classloader used by this environment
- * @param parentClassLoader the parent classloader, if
<code>null</code>, will use this class's classloader - this
- * is ignored if <code>classloader</code> is
not <code>null</code>
- * @param unpackJars if <code>true</code> and plugin jar has
embedded jars, they will be unpacked - this is
- * ignored if <code>classloader</code> is not
<code>null</code>
- * @param tmpdir a directory where the jars are placed if they are to be
unpacked; only meaningful when
- * <code>unpackJars</code> is
<code>true</code>
- *
- * @throws Exception
- */
- public ContentProviderPluginEnvironment(URL pluginUrl, ClassLoader classLoader,
ClassLoader parentClassLoader,
- boolean unpackJars, File tmpdir) throws Exception {
- initialize(pluginUrl, DEFAULT_PLUGIN_DESCRIPTOR_PATH, classLoader,
parentClassLoader, unpackJars, tmpdir);
- }
-
- public void destroy() {
- // if its our own plugin classloader, let's tell it to clean up its directory
where the jars were unpacked
- if (pluginClassLoader instanceof ContentProviderPluginClassLoader) {
- ((ContentProviderPluginClassLoader) pluginClassLoader).destroy();
- }
- }
-
- /**
- * This will create the plugin's {@link #getClassLoader() classloader}, then read
and parse the
- * {@link #getDescriptor() XML plugin descriptor} to make sure its valid.
- *
- * @param pluginJarUrl where the plugin jar is located (may be
<code>null</code>, mainly to support tests)
- * @param descriptorPath the path within the plugin classloader where the XML
descriptor is found
- * @param classLoader the classloader used by this environment
- * @param parentClassLoader the parent classloader, if
<code>null</code>, will use this class's classloader - this
- * is ignored if <code>classloader</code> is
not <code>null</code>
- * @param unpackJars if <code>true</code> and plugin jar has
embedded jars, they will be unpacked - this is
- * ignored if <code>classloader</code> is not
<code>null</code>
- * @param tmpDirectory a directory where the jars are placed if they are to be
unpacked; only meaningful when
- * <code>unpackJars</code> is
<code>true</code>
- *
- * @throws Exception
- */
- protected void initialize(URL pluginJarUrl, String descriptorPath, ClassLoader
classLoader,
- ClassLoader parentClassLoader, boolean unpackJars, File tmpDirectory) throws
Exception {
- if (classLoader == null) {
- if (parentClassLoader == null) {
- parentClassLoader = this.getClass().getClassLoader();
- }
-
- if (pluginJarUrl != null) {
- classLoader = ContentProviderPluginClassLoader.create(new
File(pluginJarUrl.getPath()).getName(),
- pluginJarUrl, unpackJars, parentClassLoader, tmpDirectory);
- } else {
- // this is mainly to support tests
- classLoader = parentClassLoader;
- }
- }
-
- initializeDescriptor(classLoader, descriptorPath, pluginJarUrl);
-
- this.pluginUrl = pluginJarUrl;
- this.pluginDescriptorPath = descriptorPath;
- this.pluginClassLoader = classLoader;
- this.pluginName = this.pluginDescriptor.getName();
- }
-
- private void initializeDescriptor(ClassLoader classloader, String descriptorPath, URL
pluginJarUrl)
- throws Exception {
- // purpose of this method is to set the this.pluginDescriptor field and verify
the XML is valid
-
- if (pluginJarUrl == null) {
- throw new Exception("A valid plugin JAR URL must be supplied");
- }
-
- JAXBContext jaxbContext;
-
- try {
- jaxbContext = JAXBContext.newInstance(DescriptorPackages.CONTENT);
- } catch (JAXBException e) {
- throw new Exception("Could not instantiate the JAXB Context", new
WrappedRemotingException(e));
- }
-
- JarInputStream jis = null;
- JarEntry descriptorEntry = null;
-
- try {
- jis = new JarInputStream(pluginJarUrl.openStream());
- JarEntry nextEntry = jis.getNextJarEntry();
- while (nextEntry != null && descriptorEntry == null) {
- if (DEFAULT_PLUGIN_DESCRIPTOR_PATH.equals(nextEntry.getName())) {
- descriptorEntry = nextEntry;
- } else {
- jis.closeEntry();
- nextEntry = jis.getNextJarEntry();
- }
- }
-
- if (descriptorEntry == null) {
- throw new Exception("The plugin descriptor does not exist");
- }
-
- Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
-
- // Enable schema validation. (see
http://jira.jboss.com/jira/browse/JBNADM-1539)
- URL pluginSchemaURL =
getClass().getClassLoader().getResource("rhq-serverplugin-content.xsd");
- Schema pluginSchema =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
- pluginSchemaURL);
- unmarshaller.setSchema(pluginSchema);
-
- ValidationEventCollector vec = new ValidationEventCollector();
- unmarshaller.setEventHandler(vec);
-
- this.pluginDescriptor = (ContentSourcePluginDescriptor)
unmarshaller.unmarshal(jis);
-
- for (ValidationEvent event : vec.getEvents()) {
- log.debug("Plugin [" + this.pluginDescriptor.getName() +
"] descriptor messages {Severity: "
- + event.getSeverity() + ", Message: " + event.getMessage()
+ ", Exception: "
- + event.getLinkedException() + "}");
- }
- } catch (Exception e) {
- throw new Exception("Could not successfully parse the plugin descriptor
[" + descriptorPath
- + " found in URL [" + pluginJarUrl + "]", new
WrappedRemotingException(e));
- } finally {
- if (jis != null) {
- try {
- jis.close();
- } catch (Exception e) {
- log.warn("Cannot close jar stream [" + pluginJarUrl +
"]. Cause: " + e);
- }
- }
- }
-
- return;
- }
-
- public String getPluginName() {
- return pluginName;
- }
-
- public URL getPluginUrl() {
- return pluginUrl;
- }
-
- public ClassLoader getClassLoader() {
- return pluginClassLoader;
- }
-
- public ContentSourcePluginDescriptor getDescriptor() {
- return pluginDescriptor;
- }
-
- public String getPluginDescriptorPath() {
- return pluginDescriptorPath;
- }
-
- @Override
- public String toString() {
- return pluginName + ": url=[" + pluginUrl + "],
descriptor-path=[" + pluginDescriptorPath + "]";
- }
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginService.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginService.java
deleted file mode 100644
index d1c6f60..0000000
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginService.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.enterprise.server.plugin.content;
-
-import java.io.File;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.annotation.ejb.Management;
-import org.jboss.annotation.ejb.Service;
-import org.jboss.system.server.ServerConfig;
-import org.rhq.enterprise.server.RHQConstants;
-import org.rhq.core.clientapi.server.plugin.content.InitializationException;
-
-/**
- * This is the singleton management service responsible for managing the lifecycle of
the
- * {@link ContentProviderPluginContainer}. It will be started when the entire server
starts and shutdown when the entire
- * server shuts down. It has a management interface to allow it to be recycled on demand
when desired.
- *
- * @author John Mazzitelli
- */
-(a)Management(ContentProviderPluginServiceManagement.class)
-@Service(objectName = ContentProviderPluginServiceManagement.OBJECT_NAME_STR)
-public class ContentProviderPluginService implements
ContentProviderPluginServiceManagement {
- private static final Log log =
LogFactory.getLog(ContentProviderPluginService.class);
-
- private boolean started;
- private ContentProviderPluginContainer pluginContainer;
-
- public synchronized void start() {
- log.debug("The content source plugin service has been deployed (but plugin
container will not be started yet)");
- this.started = true;
- return;
- }
-
- public synchronized void startPluginContainer() {
- if (!this.started) {
- throw new IllegalStateException(
- "The content source plugin service is not started - cannot start the
plugin container");
- }
-
- // only initialize if not already started; if already started/initialized, just
ignore
- if (this.pluginContainer == null) {
- log.debug("The content source plugin service is now starting the content
server plugin container");
- this.pluginContainer = createPluginContainer();
- }
-
- return;
- }
-
- public synchronized void stopPluginContainer() {
- if (this.started && (this.pluginContainer != null)) {
- log
- .info("The content source plugin service is now stopping - the
content server plugin container will be shutdown now");
-
- this.pluginContainer.shutdown();
- this.pluginContainer = null;
- }
-
- return;
- }
-
- public synchronized void stop() {
- if (this.started) {
- stopPluginContainer();
- this.started = false;
- }
-
- return;
- }
-
- public synchronized void restartPluginContainer() {
- stopPluginContainer();
- startPluginContainer();
- }
-
- public ContentProviderPluginContainer getPluginContainer() {
- return this.pluginContainer;
- }
-
- public boolean isStarted() {
- return this.started;
- }
-
- public boolean isPluginContainerStarted() {
- return this.pluginContainer != null;
- }
-
- /**
- * This will create, configure and initialize the plugin container and return it.
- *
- * <p>This is protected to allow subclasses to override the PC that is created
by this service (mainly to support
- * tests).</p>
- *
- * @return the PC that this service will use
- */
- protected ContentProviderPluginContainer createPluginContainer() {
- ContentProviderPluginContainer pc = new ContentProviderPluginContainer();
-
- ContentProviderPluginContainerConfiguration config = new
ContentProviderPluginContainerConfiguration();
-
- String pluginDirStr = System.getProperty(ServerConfig.SERVER_HOME_DIR);
- config
- .setPluginDirectory(new File(pluginDirStr, "deploy/" +
RHQConstants.EAR_FILE_NAME + "/rhq-serverplugins"));
-
- String tmpDirStr = System.getProperty(ServerConfig.SERVER_TEMP_DIR);
- config.setTemporaryDirectory(new File(tmpDirStr));
-
- try {
- pc.initialize(config);
- }
- catch (InitializationException e) {
- log.error("Error initializing plugin container [" + pc +
"]", e);
- }
-
- return pc;
- }
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginServiceManagement.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginServiceManagement.java
deleted file mode 100644
index 248bdf3..0000000
---
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/content/ContentProviderPluginServiceManagement.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.enterprise.server.plugin.content;
-
-/**
- * The MBean management interface that defines the lifecycle methods for the {@link
ContentProviderPluginService} service.
- *
- * @author John Mazzitelli
- */
-public interface ContentProviderPluginServiceManagement {
- String OBJECT_NAME_STR =
"rhq.serverplugin:service=ContentProviderPluginService";
-
- /**
- * Starts the service but will <b>not</b> start the {@link
#getPluginContainer() plugin container}. After the server
- * fully initializes, it should only then {@link #startPluginContainer() start the
plugin container}.
- */
- void start();
-
- /**
- * Shuts down this service along with the {@link #stopPluginContainer() plugin
container}.
- */
- void stop();
-
- /**
- * Starts the {@link #getPluginContainer() plugin container} which will load in all
plugins and start them. You
- * cannot start the plugin container unless this service has {@link #start() been
started}. If the plugin container
- * {@link #isPluginContainerStarted() is already started}, this does nothing and
returns.
- */
- void startPluginContainer();
-
- /**
- * Stops the {@link #getPluginContainer() plugin container} which will shuts down all
plugins. If the plugin
- * container {@link #isPluginContainerStarted() is already shutdown}, this does
nothing and returns.
- */
- void stopPluginContainer();
-
- /**
- * Convienence method that first does a {@link #stopPluginContainer()} and then a
{@link #startPluginContainer()}.
- */
- void restartPluginContainer();
-
- /**
- * Returns the server side content source plugin container that will be responsible
for managing all plugins and
- * their classloaders.
- *
- * @return the plugin container, if started. Will be <code>null</code> if
not started
- */
- ContentProviderPluginContainer getPluginContainer();
-
- /**
- * Returns <code>true</code> if this service has been started. This does
not necessarily mean the
- * {@link #getPluginContainer() plugin container} has be started - see {@link
#isPluginContainerStarted()} for that.
- *
- * @return <code>true</code> if this service has been started
- */
- boolean isStarted();
-
- /**
- * Returns <code>true</code> if the {@link #getPluginContainer() plugin
container} has be started. Note that this is
- * <b>not</b> an indication if this service has started - see {@link
#isStarted()} for that. But, if the plugin
- * container has been started, then by definition this service has also been
started.
- *
- * @return <code>true</code> if the plugin container has been started
- */
- boolean isPluginContainerStarted();
-}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/content/ContentProviderManagerTest.java
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/content/ContentProviderManagerTest.java
deleted file mode 100644
index da041b1..0000000
---
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/content/ContentProviderManagerTest.java
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
-* RHQ Management Platform
-* Copyright (C) 2009 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.enterprise.server.plugin.content;
-
-import org.rhq.core.clientapi.server.plugin.content.ContentProvider;
-import org.rhq.core.clientapi.server.plugin.content.ContentProviderPackageDetails;
-import org.rhq.core.clientapi.server.plugin.content.ContentProviderPackageDetailsKey;
-import org.rhq.core.clientapi.server.plugin.content.PackageSource;
-import org.rhq.core.clientapi.server.plugin.content.PackageSyncReport;
-import org.rhq.core.clientapi.server.plugin.content.RepoDetails;
-import org.rhq.core.clientapi.server.plugin.content.RepoGroupDetails;
-import org.rhq.core.clientapi.server.plugin.content.RepoImportReport;
-import org.rhq.core.clientapi.server.plugin.content.RepoSource;
-import org.rhq.core.domain.auth.Subject;
-import org.rhq.core.domain.configuration.Configuration;
-import org.rhq.core.domain.content.ContentSource;
-import org.rhq.core.domain.content.ContentSourceType;
-import org.rhq.core.domain.content.PackageType;
-import org.rhq.core.domain.content.PackageVersion;
-import org.rhq.core.domain.content.PackageVersionContentSource;
-import org.rhq.core.domain.content.Repo;
-import org.rhq.core.domain.content.RepoGroup;
-import org.rhq.core.domain.content.RepoRepoGroup;
-import org.rhq.core.domain.content.RepoRepoRelationship;
-import org.rhq.core.domain.content.RepoRelationship;
-import org.rhq.core.domain.criteria.RepoCriteria;
-import org.rhq.core.domain.resource.ResourceCategory;
-import org.rhq.core.domain.resource.ResourceType;
-import org.rhq.core.domain.util.PageList;
-import org.rhq.enterprise.server.auth.SubjectManagerLocal;
-import org.rhq.enterprise.server.content.ContentSourceManagerLocal;
-import org.rhq.enterprise.server.content.RepoManagerLocal;
-import org.rhq.enterprise.server.test.AbstractEJB3Test;
-import org.rhq.enterprise.server.test.TestContentSourcePluginService;
-import org.rhq.enterprise.server.util.LookupUtil;
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-
-import javax.persistence.EntityManager;
-import javax.persistence.Query;
-import javax.transaction.TransactionManager;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author Jason Dobies
- */
-public class ContentProviderManagerTest extends AbstractEJB3Test {
-
- private static final String PACKAGE_TYPE_NAME = "testPackageType";
- private static final String RESOURCE_TYPE_NAME = "testResourceType";
- private static final String PLUGIN_NAME = "testPlugin";
- private static final String PACKAGE_NAME = "package1";
- private static final String PACKAGE_VERSION = "1.0";
- private static final String PACKAGE_ARCH = "noarch";
-
- // The following variables need to be cleaned up at the end of the test
-
- private ContentSourceType testSourceType;
-
- private ContentSource testSource;
- private PackageType testPackageType;
-
- private ResourceType testResourceType;
- private List<Integer> reposToDelete = new ArrayList<Integer>();
- private List<Integer> repoGroupsToDelete = new ArrayList<Integer>();
- private List<Integer> packagesToDelete = new ArrayList<Integer>();
- private Integer repoId;
- private Integer relatedRepoId;
-
- @BeforeMethod
- public void setupBeforeMethod() throws Exception {
-
- // Plugin service setup
- prepareScheduler();
- TestContentSourcePluginService pluginService =
prepareContentSourcePluginService();
- pluginService.startPluginContainer();
-
- // Because of the (current) transaction settings of some of the nested methods
(i.e. REQUIRES_NEW),
- // this test must commit its data and clean up after itself, as compared to
simply rolling back the
- // transaction at the end.
- TransactionManager tx = getTransactionManager();
- tx.begin();
- EntityManager entityManager = getEntityManager();
-
- ContentSourceManagerLocal contentManager = LookupUtil.getContentSourceManager();
- SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
- Subject overlord = subjectManager.getOverlord();
-
- // Create a sample content source type that will be used in this test
- testSourceType = new ContentSourceType("testType");
- entityManager.persist(testSourceType);
-
- // Add a content source to the DB to hang the sync against
- testSource = new ContentSource("testSource", testSourceType);
- contentManager.simpleCreateContentSource(overlord, testSource);
-
- // Create a sample package type that will be used for packages sync'd in the
test
- testResourceType = new ResourceType(RESOURCE_TYPE_NAME, PLUGIN_NAME,
ResourceCategory.PLATFORM, null);
- entityManager.persist(testResourceType);
-
- testPackageType = new PackageType(PACKAGE_TYPE_NAME, testResourceType);
- entityManager.persist(testPackageType);
-
- tx.commit();
- }
-
- @AfterMethod
- public void tearDownAfterMethod() throws Exception {
-
- // Transactional stuff
- TransactionManager tx = getTransactionManager();
- tx.begin();
- EntityManager entityManager = getEntityManager();
-
- RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
- SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
- Subject overlord = subjectManager.getOverlord();
-
- // Delete the repo relationships
-
entityManager.createNamedQuery(RepoRepoRelationship.DELETE_BY_REPO_ID).setParameter(
- "repoId", repoId).executeUpdate();
-
-
entityManager.createNamedQuery(RepoRelationship.DELETE_BY_RELATED_REPO_ID).setParameter(
- "relatedRepoId", relatedRepoId).executeUpdate();
-
- // Delete any repos that were created in this test
- for (Integer repoId : reposToDelete) {
- repoManager.deleteRepo(overlord, repoId);
- }
-
- // Delete any repo groups that were created in this test
- for (Integer repoGroupId : repoGroupsToDelete) {
- repoManager.deleteRepoGroup(overlord, repoGroupId);
- }
-
- // First disassociate packages from the content source
-
entityManager.createNamedQuery(PackageVersionContentSource.DELETE_BY_CONTENT_SOURCE_ID).setParameter(
- "contentSourceId", testSource.getId()).executeUpdate();
-
- // Delete any packages created in this test
- for (Integer packageId : packagesToDelete) {
- PackageVersion deleteMe = entityManager.find(PackageVersion.class,
packageId);
- entityManager.remove(deleteMe);
- }
-
- // Delete the source that was created
- testSource = entityManager.find(ContentSource.class, testSource.getId());
- entityManager.remove(testSource);
-
- // Delete the fake package type
- testPackageType = entityManager.find(PackageType.class,
testPackageType.getId());
- entityManager.remove(testPackageType);
-
- // Delete the fake resource type
- testResourceType = entityManager.find(ResourceType.class,
testResourceType.getId());
- entityManager.remove(testResourceType);
-
- // Delete the fake source type
- testSourceType = entityManager.find(ContentSourceType.class,
testSourceType.getId());
- entityManager.remove(testSourceType);
-
- tx.commit();
-
- // Plugin service teardown
- unprepareContentSourcePluginService();
- unprepareScheduler();
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void synchronizeContentSource() throws Exception {
-
- // Setup
- RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
- SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
- Subject overlord = subjectManager.getOverlord();
-
- TestContentProviderManager providerManager = new TestContentProviderManager();
-
- // Test
- boolean completed =
providerManager.synchronizeContentSource(testSource.getId());
- assert completed;
-
- // Verify RepoGroups
- RepoGroup repoGroup = repoManager.getRepoGroupByName("testRepoGroup");
- assert repoGroup != null;
- repoGroupsToDelete.add(repoGroup.getId());
-
- // Verify Repos
- List<Repo> retrievedRepos;
-
- // -> Simple Repo
- retrievedRepos = repoManager.getRepoByName("testRepo1");
- assert retrievedRepos.size() == 1;
- reposToDelete.add(retrievedRepos.get(0).getId());
-
- // -> Repo in a group
- retrievedRepos = repoManager.getRepoByName("testRepo2");
- assert retrievedRepos.size() == 1;
- reposToDelete.add(retrievedRepos.get(0).getId());
-
- Repo repoInGroup = retrievedRepos.get(0);
-
- RepoCriteria findWithRepoGroup = new RepoCriteria();
- findWithRepoGroup.fetchRepoRepoGroups(true);
- findWithRepoGroup.addFilterId(repoInGroup.getId());
-
- PageList<Repo> repoPageList = repoManager.findReposByCriteria(overlord,
findWithRepoGroup);
- repoInGroup = repoPageList.get(0);
-
- Set<RepoRepoGroup> repoGroups = repoInGroup.getRepoRepoGroups();
- assert repoGroups.size() == 1;
-
- RepoRepoGroup repoRepoGroup = repoGroups.iterator().next();
- assert
repoRepoGroup.getRepoRepoGroupPK().getRepoGroup().getName().equals("testRepoGroup");
- assert
repoRepoGroup.getRepoRepoGroupPK().getRepo().getName().equals("testRepo2");
-
- // -> Repo with a parent
- retrievedRepos = repoManager.getRepoByName("testRepo3");
- assert retrievedRepos.size() == 1;
- reposToDelete.add(retrievedRepos.get(0).getId());
- relatedRepoId = retrievedRepos.get(0).getId();
-
- retrievedRepos = repoManager.getRepoByName("testRepo4");
- assert retrievedRepos.size() == 1;
- reposToDelete.add(retrievedRepos.get(0).getId());
- repoId = retrievedRepos.get(0).getId();
-
- RepoCriteria findWithRelationships = new RepoCriteria();
- findWithRelationships.addFilterName("testRepo4");
- findWithRelationships.fetchRepoRepoRelationships(true);
- PageList<Repo> childRepoList = repoManager.findReposByCriteria(overlord,
findWithRelationships);
- assert childRepoList.size() == 1;
-
- Repo childRepo = childRepoList.get(0);
- Set<RepoRepoRelationship> childRepoRepoRelationship =
childRepo.getRepoRepoRelationships();
- assert childRepoRepoRelationship.size() == 1;
-
- // -> Non-existent repo
- retrievedRepos = repoManager.getRepoByName("testRepoFoo");
- assert retrievedRepos.size() == 0;
-
- // Verify Packages
- TransactionManager tx = getTransactionManager();
- tx.begin();
- EntityManager entityManager = getEntityManager();
-
- try {
- Query packageQuery =
entityManager.createNamedQuery(PackageVersion.QUERY_FIND_BY_PACKAGE_DETAILS_KEY);
- packageQuery.setParameter("packageName", PACKAGE_NAME);
- packageQuery.setParameter("packageTypeName", PACKAGE_TYPE_NAME);
- packageQuery.setParameter("resourceTypeId",
testResourceType.getId());
- packageQuery.setParameter("architectureName", PACKAGE_ARCH);
- packageQuery.setParameter("version", PACKAGE_VERSION);
-
- List<PackageVersion> packageList = packageQuery.getResultList();
- assert packageList.size() == 1;
- packagesToDelete.add(packageList.get(0).getId());
- } finally {
- tx.rollback();
- }
-
- }
-
- /**
- * Mock implementation of a content provider that will return known data.
- */
- private class TestContentProvider implements ContentProvider, PackageSource,
RepoSource {
-
- public RepoImportReport importRepos() throws Exception {
- RepoImportReport report = new RepoImportReport();
-
- // Create a repo group in the system
- RepoGroupDetails group1 = new RepoGroupDetails("testRepoGroup",
"family");
- report.addRepoGroup(group1);
-
- // Simple repo
- RepoDetails repo1 = new RepoDetails("testRepo1");
- repo1.setDescription("First test repo");
- report.addRepo(repo1);
-
- // Repo belonging to a group that was created in the sync
- RepoDetails repo2 = new RepoDetails("testRepo2");
- repo2.setRepoGroup("testRepoGroup");
- report.addRepo(repo2);
-
- // Repo with a parent repo created in this sync
- // Parent explicitly added to this list *after* this child to ensure
that's not a problem
- RepoDetails repo3 = new RepoDetails("testRepo3");
- report.addRepo(repo3);
-
- RepoDetails repo4 = new RepoDetails("testRepo4");
- repo4.setParentRepoName("testRepo3");
- report.addRepo(repo4);
-
- return report;
- }
-
- public void synchronizePackages(PackageSyncReport report,
- Collection<ContentProviderPackageDetails>
existingPackages) throws Exception {
- ContentProviderPackageDetailsKey key1 =
- new ContentProviderPackageDetailsKey(PACKAGE_NAME, PACKAGE_VERSION,
PACKAGE_TYPE_NAME,
- PACKAGE_ARCH, RESOURCE_TYPE_NAME, PLUGIN_NAME);
- ContentProviderPackageDetails pkg1 = new
ContentProviderPackageDetails(key1);
- pkg1.setLocation("repo/foo");
-
- report.addNewPackage(pkg1);
- }
-
- public void initialize(Configuration configuration) throws Exception {
- // No-op
- }
-
- public void shutdown() {
- // No-op
- }
-
- public void testConnection() throws Exception {
- // No-op
- }
-
-
- public InputStream getInputStream(String location) throws Exception {
- // No-op
- return null;
- }
-
- }
-
- /**
- * Stubs out the methods in {@link ContentProviderManager} that would go out and
expect a fully packaged plugin.
- * Instead, use the mock implementation provided above.
- */
- private class TestContentProviderManager extends ContentProviderManager {
-
- private ContentProvider testProvider = new TestContentProvider();
-
- protected ContentProvider getIsolatedContentProvider(int contentProviderId)
throws RuntimeException {
- return testProvider;
- }
- }
-
-}
diff --git
a/modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin-content.xml
b/modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin-content.xml
deleted file mode 100644
index 866999d..0000000
---
a/modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin-content.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<plugin name="DiskContentSourcePlugin"
- xmlns="urn:xmlns:rhq-serverplugin.content"
- xmlns:c="urn:xmlns:rhq-configuration">
-
- <contentSourceType name="DiskSource"
- displayName="Local Disk Storage Content Source"
- description="This content source retrieves packages from a
local file system. If deployed in an HA environment, this must be on a distributed file
system that all servers can access."
- lazyLoad="true"
- downloadMode="never"
-
apiClass="org.rhq.enterprise.server.plugins.disk.DiskSource">
-
- <configuration>
- <c:simple-property name="rootDirectory" type="directory"
required="true" description="The root directory that contains all content
that is to be served by this content source. In an HA environment, this must be on a
distributed file system that all servers can access."/>
- <!-- would like to be able to define multiple package types, but the UI
doesn't allow editing maps yet
- <c:list-property name="packageTypes" required="true"
description="Defines the different package types that can be found on this disk
content source">
- <c:map-property name="packageType">
- -->
- <c:simple-property name="filenameFilter"
required="true" summary="true" default=".*"
description="A regular expression that identifies a file of this package type (e.g.
'.*\.jar', '.*/i686/.*\.rpm$')"/>
- <c:simple-property name="packageTypeName"
required="true" summary="true" description="The name that
identifies the kind of package this type represents (e.g. 'ear',
'rpm')"/>
- <c:simple-property name="architectureName"
required="true" summary="true" default="noarch"
description="The specific hardware architecture this type of package can be deployed
on. If there is no specific architecture required, use 'noarch'. (e.g.
'i686', 'amd64')"/>
- <c:simple-property name="resourceTypeName"
required="true" summary="true" description="The name of the
resource type on which this package can be deployed. This is the resource type name as
defined in the agent plugin. (e.g. 'Linux', 'JBossAS Server')"/>
- <c:simple-property name="resourceTypePluginName"
required="true" summary="true" description="The name of the
plugin that defined the resource type. (e.g. 'Platform',
'JBossAS')"/>
- <!--
- </c:map-property>
- </c:list-property>
- -->
- </configuration>
-
- </contentSourceType>
-
-</plugin>
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin-content.xml
b/modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin-content.xml
deleted file mode 100644
index 2cf4110..0000000
---
a/modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin-content.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<plugin name="JBossASPatchContentSourcePlugin"
- xmlns="urn:xmlns:rhq-serverplugin.content"
- xmlns:c="urn:xmlns:rhq-configuration">
-
- <contentSourceType name="JBossASPatchSource"
- displayName="JBoss AS Patch Content Source"
- description="This content source retrieves packages from the
JBoss CSP RSS feed."
- lazyLoad="true"
-
apiClass="org.rhq.enterprise.server.plugins.jboss.software.JBossSoftwareContentSourceAdapter">
-
- <configuration>
- <c:group name="csp" displayName="CSP Feed Settings">
- <c:simple-property name="url" displayName="Feed URL"
type="string" required="true"
- description="Destination URL of the feed."/>
- <c:simple-property name="username"
displayName="Username" type="string" required="false"
- description="Username used to log into the
feed."/>
- <c:simple-property name="password"
displayName="Password" type="password" required="false"
- description="Password used to log into the
feed."/>
- <c:simple-property name="active" displayName="Active"
type="boolean" required="true" default="true"
- description="Indicates if this instance should go out
and check the feed for packages."/>
- </c:group>
- <c:group name="proxy" displayName="Proxy Settings"
hiddenByDefault="true">
- <c:simple-property name="proxyUrl" displayName="Proxy
URL" type="string" required="false"
- description="Optional. URL of the proxy server to use
for this connection."/>
- <c:simple-property name="proxyPort" displayName="Proxy
Port" type="string" required="false"
- description="Optional. Port of the proxy server to
use for this connection."/>
- <c:simple-property name="proxyUsername" displayName="Proxy
Username" type="string" required="false"
- description="Optional. If the proxy requires
authentication, this is the user to log in as."/>
- <c:simple-property name="proxyPassword" displayName="Proxy
Password" type="password" required="false"
- description="Optional. If the proxy requires
authentitcation, this is the password for the user."/>
- </c:group>
- </configuration>
-
- </contentSourceType>
-
-</plugin>
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin-content.xml
b/modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin-content.xml
deleted file mode 100644
index bb3c87a..0000000
---
a/modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin-content.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<plugin name="RHNHostedPlugin"
- xmlns="urn:xmlns:rhq-serverplugin.content"
- xmlns:c="urn:xmlns:rhq-configuration">
-
- <contentSourceType name="RHNSource"
- displayName="RHN Hosted Source"
- description="This plugin facilitates communication with Red
Hat Network."
- lazyLoad="false"
- downloadMode="filesystem"
-
apiClass="org.rhq.enterprise.server.plugins.rhnhosted.RHNProvider">
-
- <configuration>
- <c:simple-property
- name="location"
- type="string"
- required="true"
-
default="http://satellite.rhn.redhat.com/"
- description="RHN Hosted server url for connection."/>
-
- <c:simple-property
- name="certificate"
- type="longString"
- required="true"
- description="RHQ subscription Certificate for activation
."/>
-
- <!--<c:group name="repos" displayName="repo list">
- <c:simple-property name="repos" type="string"
default="rhn-tools-rhel-i386-server-5"/>
- </c:group>-->
-
- <c:simple-property name="SyncableChannels"
required="true" default="rhel-i386-server-vt-5"
- description="list of syncable channels.">
- <c:property-options>
- <c:option name="rhel-i386-server-5"
value="rhel-i386-server-5"/>
- <c:option name="rhn-tools-rhel-i386-server-5"
value="rhn-tools-rhel-i386-server-5"/>
- <c:option name="rhel-i386-server-vt-5"
value="rhel-i386-server-vt-5"/>
- <c:option name="rhel-x86_64-server-5"
value="rhel-x86_64-server-5"/>
- <c:option name="rhn-tools-rhel-x86_64-server-5"
value="rhn-tools-rhel-x86_64-server-5"/>
- <c:option name="rhel-x86_64-server-vt-5"
value="rhel-x86_64-server-vt-5"/>
- </c:property-options>
- </c:simple-property>
-
-
- </configuration>
-
- </contentSourceType>
-
-</plugin>
diff --git
a/modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin-content.xml
b/modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin-content.xml
deleted file mode 100644
index f31e7fc..0000000
---
a/modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin-content.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<plugin name="UrlContentSourcePlugin"
- xmlns="urn:xmlns:rhq-serverplugin.content"
- xmlns:c="urn:xmlns:rhq-configuration">
-
- <contentSourceType name="UrlSource"
- displayName="Remote URL Content Source"
- description="This content source retrieves packages from a
remote system identified by a URL."
- lazyLoad="true"
- downloadMode="database"
-
apiClass="org.rhq.enterprise.server.plugins.url.UrlProvider">
-
- <configuration>
- <c:simple-property name="rootUrl" type="string"
required="true" description="The URL that contains all content that is to
be served by this content source."/>
- <c:simple-property name="indexFile" type="string"
required="true" default="content-index.txt" description="The
index file that defines all the content that can be found on the remote server. If this is
not a full URL, it is assumed to be relative to the root URL."/>
-
- <c:list-property name="packageTypes" required="true"
min="0"
- description="Defines the different package types
associated with specific filename filters. These are used only if the index file does not
provide the package type information.">
- <c:map-property name="packageType">
- <c:simple-property name="filenameFilter"
required="true" summary="true" default=".*"
description="A regular expression that identifies a file of this package type (e.g.
'.*\.jar', '.*/i686/.*\.rpm$')"/>
- <c:simple-property name="packageTypeName"
required="true" summary="true" description="The name that
identifies the kind of package this type represents (e.g. 'ear',
'rpm')"/>
- <c:simple-property name="architectureName"
required="true" summary="true" default="noarch"
description="The specific hardware architecture this type of package can be deployed
on. If there is no specific architecture required, use 'noarch'. (e.g.
'i686', 'amd64')"/>
- <c:simple-property name="resourceTypeName"
required="true" summary="true" description="The name of the
resource type on which this package can be deployed. This is the resource type name as
defined in the agent plugin. (e.g. 'Linux', 'JBossAS Server')"/>
- <c:simple-property name="resourceTypePluginName"
required="true" summary="true" description="The name of the
plugin that defined the resource type. (e.g. 'Platform',
'JBossAS')"/>
- </c:map-property>
- </c:list-property>
- </configuration>
-
- </contentSourceType>
-
- <contentSourceType name="HttpSource"
- displayName="HTTP Content Source"
- description="This content source retrieves packages from a
remote HTTP server, possibly via a proxy."
- lazyLoad="true"
- downloadMode="database"
-
apiClass="org.rhq.enterprise.server.plugins.url.HttpProvider">
-
- <configuration>
- <c:simple-property name="rootUrl" type="string"
required="true" description="The HTTP URL that contains all content that is
to be served by this content source."/>
- <c:simple-property name="indexFile" type="string"
required="true" default="content-index.txt" description="The
index file that defines all the content that can be found on the remote server. If this is
not a full URL, it is assumed to be relative to the root URL."/>
-
- <c:list-property name="packageTypes" required="true"
min="0"
- description="Defines the different package types
associated with specific filename filters. These are used only if the index file does not
provide the package type information.">
- <c:map-property name="packageType">
- <c:simple-property name="filenameFilter"
required="true" summary="true" default=".*"
description="A regular expression that identifies a file of this package type (e.g.
'.*\.jar', '.*/i686/.*\.rpm$')"/>
- <c:simple-property name="packageTypeName"
required="true" summary="true" description="The name that
identifies the kind of package this type represents (e.g. 'ear',
'rpm')"/>
- <c:simple-property name="architectureName"
required="true" summary="true" default="noarch"
description="The specific hardware architecture this type of package can be deployed
on. If there is no specific architecture required, use 'noarch'. (e.g.
'i686', 'amd64')"/>
- <c:simple-property name="resourceTypeName"
required="true" summary="true" description="The name of the
resource type on which this package can be deployed. This is the resource type name as
defined in the agent plugin. (e.g. 'Linux', 'JBossAS Server')"/>
- <c:simple-property name="resourceTypePluginName"
required="true" summary="true" description="The name of the
plugin that defined the resource type. (e.g. 'Platform',
'JBossAS')"/>
- </c:map-property>
- </c:list-property>
-
- <c:group name="security" displayName="Security
Settings">
- <c:simple-property name="username"
displayName="Username" type="string" required="false"
- description="Username used to log into the HTTP
server"/>
- <c:simple-property name="password"
displayName="Password" type="password" required="false"
- description="Password used to log into the HTTP
server"/>
- </c:group>
- <c:group name="proxy" displayName="Proxy Settings"
hiddenByDefault="true">
- <c:simple-property name="proxyUrl" displayName="Proxy
URL" type="string" required="false"
- description="Optional. URL of the proxy server to use
for this connection."/>
- <c:simple-property name="proxyPort" displayName="Proxy
Port" type="string" required="false"
- description="Optional. Port of the proxy server to
use for this connection."/>
- <c:simple-property name="proxyUsername" displayName="Proxy
Username" type="string" required="false"
- description="Optional. If the proxy requires
authentication, this is the user to log in as."/>
- <c:simple-property name="proxyPassword" displayName="Proxy
Password" type="password" required="false"
- description="Optional. If the proxy requires
authentitcation, this is the password for the user."/>
- </c:group>
- </configuration>
-
- </contentSourceType>
-
-</plugin>
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin-content.xml
b/modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin-content.xml
deleted file mode 100644
index ca6aef9..0000000
---
a/modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin-content.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-
-<plugin name="YumContentSourcePlugin"
- xmlns="urn:xmlns:rhq-serverplugin.content"
- xmlns:c="urn:xmlns:rhq-configuration">
-
- <contentSourceType name="YumSource"
- displayName="Yum Repository Content Source"
- description="This content source retrieves packages from a
local or remote Yum repository."
- lazyLoad="true"
- downloadMode="filesystem"
-
apiClass="org.rhq.enterprise.server.plugins.yum.RepoProvider">
-
- <configuration>
- <c:simple-property
- name="location"
- type="string"
- required="true"
- description="The URL or path to the Yum repository" />
- </configuration>
- </contentSourceType>
-
-</plugin>
\ No newline at end of file
commit f515baaf1b5f6607be0db871943cbcf1750fae0d
Author: John Mazzitelli <mazz(a)redhat.com>
Date: Sun Nov 1 02:24:53 2009 -0500
cracking a whole bunch of eggs to start to make a plugin container omelet. this branch
doesn't come close to successfully building right now. refactored out the server-side
xml schemas to a server only mvn module. xml-schemas now contains server side schemas
leaving client-api to contain only those schemas needed on both server and agent (as it
should be)
diff --git
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/descriptor/DescriptorPackages.java
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/descriptor/DescriptorPackages.java
index c55e94c..432696a 100644
---
a/modules/core/client-api/src/main/java/org/rhq/core/clientapi/descriptor/DescriptorPackages.java
+++
b/modules/core/client-api/src/main/java/org/rhq/core/clientapi/descriptor/DescriptorPackages.java
@@ -30,7 +30,4 @@ package org.rhq.core.clientapi.descriptor;
public interface DescriptorPackages {
String CONFIGURATION = "org.rhq.core.clientapi.descriptor.configuration";
String PC_PLUGIN = "org.rhq.core.clientapi.descriptor.plugin";
- String PERSPECTIVE = "org.rhq.core.clientapi.descriptor.perspective";
- String CONTENT = "org.rhq.core.clientapi.descriptor.serverplugin.content";
- String CONTENTSOURCE_PACKAGEDETAILS =
"org.rhq.core.clientapi.descriptor.contentsource.packagedetails";
}
\ No newline at end of file
diff --git
a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
index 2c77509..ad6f841 100644
---
a/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
+++
b/modules/enterprise/gui/portal-war/src/main/java/org/rhq/enterprise/gui/startup/StartupServlet.java
@@ -52,7 +52,7 @@ import org.rhq.enterprise.server.core.AgentManagerLocal;
import org.rhq.enterprise.server.core.CustomJaasDeploymentServiceMBean;
import org.rhq.enterprise.server.core.comm.ServerCommunicationsServiceUtil;
import org.rhq.enterprise.server.core.plugin.AgentPluginDeploymentScannerMBean;
-import org.rhq.enterprise.server.plugin.content.ContentProviderPluginServiceManagement;
+import org.rhq.enterprise.server.plugin.pc.ServerPluginServiceManagement;
import org.rhq.enterprise.server.resource.ResourceTypeManagerLocal;
import org.rhq.enterprise.server.scheduler.SchedulerLocal;
import org.rhq.enterprise.server.scheduler.jobs.AsyncResourceDeleteJob;
@@ -384,12 +384,12 @@ public class StartupServlet extends HttpServlet {
// Content Source Sync Jobs
try {
- ContentProviderPluginServiceManagement mbean;
+ ServerPluginServiceManagement mbean;
MBeanServer mbs = MBeanServerLocator.locateJBoss();
- ObjectName name =
ObjectNameFactory.create(ContentProviderPluginServiceManagement.OBJECT_NAME_STR);
- Class<?> iface = ContentProviderPluginServiceManagement.class;
- mbean = (ContentProviderPluginServiceManagement)
MBeanServerInvocationHandler.newProxyInstance(mbs, name,
- iface, false);
+ ObjectName name =
ObjectNameFactory.create(ServerPluginServiceManagement.OBJECT_NAME_STR);
+ Class<?> iface = ServerPluginServiceManagement.class;
+ mbean = (ServerPluginServiceManagement)
MBeanServerInvocationHandler.newProxyInstance(mbs, name, iface,
+ false);
mbean.getPluginContainer().scheduleSyncJobs();
} catch (Exception e) {
log("Cannot schedule content source sync jobs: " +
e.getMessage());
@@ -535,12 +535,12 @@ public class StartupServlet extends HttpServlet {
log("Starting the server plugin container...");
try {
- ContentProviderPluginServiceManagement mbean;
+ ServerPluginServiceManagement mbean;
MBeanServer mbs = MBeanServerLocator.locateJBoss();
- ObjectName name =
ObjectNameFactory.create(ContentProviderPluginServiceManagement.OBJECT_NAME_STR);
- Class<?> iface = ContentProviderPluginServiceManagement.class;
- mbean = (ContentProviderPluginServiceManagement)
MBeanServerInvocationHandler.newProxyInstance(mbs, name,
- iface, false);
+ ObjectName name =
ObjectNameFactory.create(ServerPluginServiceManagement.OBJECT_NAME_STR);
+ Class<?> iface = ServerPluginServiceManagement.class;
+ mbean = (ServerPluginServiceManagement)
MBeanServerInvocationHandler.newProxyInstance(mbs, name, iface,
+ false);
mbean.startPluginContainer();
} catch (Exception e) {
throw new ServletException("Cannot start the server plugin
container!", e);
diff --git a/modules/enterprise/server/jar/pom.xml
b/modules/enterprise/server/jar/pom.xml
index b8f3329..9f964ed 100644
--- a/modules/enterprise/server/jar/pom.xml
+++ b/modules/enterprise/server/jar/pom.xml
@@ -41,6 +41,12 @@
<dependency>
<groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server-xml-schemas</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.rhq</groupId>
<artifactId>rhq-core-domain</artifactId>
<version>${project.version}</version>
<scope>provided</scope> <!-- by ear -->
@@ -562,4 +568,4 @@
</profile>
</profiles>
-</project>
\ No newline at end of file
+</project>
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/RootServerPluginClassLoader.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/RootServerPluginClassLoader.java
new file mode 100644
index 0000000..500b775
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/RootServerPluginClassLoader.java
@@ -0,0 +1,148 @@
+/*
+ * 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, 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.enterprise.server.plugin.pc;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * This is the classloader that will be the parent to all plugin classloaders. It will be
created such that
+ * it essentially hides a set of excluded classes which typically means this this root
classloader (and its
+ * children plugin classloaders) will allow the following to be loaded:
+ * <ul>
+ * <li>the plugin itself (including its third-party libraries)</li>
+ * <li>core plugin container libraries required by all plugins, such as plugin API
classes</li>
+ * <li>plugin container jars that are configured to be unhidden</li>
+ * </ul>
+ *
+ * @author John Mazzitelli
+ */
+//Note that this was an almost direct copy of the agent-side plugin container's
RootPluginClassLoader at one time
+public class RootServerPluginClassLoader extends URLClassLoader {
+ private final Log log = LogFactory.getLog(RootServerPluginClassLoader.class);
+
+ private final Pattern classesToHideRegex;
+
+ /**
+ * Creates this classloader. <code>classesToHideRegexStr</code> is a
regular expression to use to match against names
+ * of classes to hide (i.e. not load). If a class that is to be loaded doesn't
match the regex, it will be loaded
+ * using parent-first semantics (i.e. it will first be searched in the parent
classloader, and only if it isn't found
+ * there will this classloader be checked for it). Otherwise, the class will be
loaded using this classloader
+ * only - the parent classloader will not be consulted so if this classloader does
not have the class to be loaded, a
+ * {@link ClassCastException} will be thrown.
+ *
+ * @param urls URLs to jar files where classes can be loaded by this classloader
+ * @param parent the parent to this classloader, used when loading classes via
parent-first semantics
+ * @param classesToHideRegexStr regular expression(s) to use to match against names
of classes to load.
+ * if <code>null</code> or empty, no classes
will be hidden, the parent will always
+ * be consulted first to load the classes.
+ * @throws PatternSyntaxException if the given regex is invalid (see {@link
Pattern#compile(String)})
+ */
+ public RootServerPluginClassLoader(URL[] urls, ClassLoader parent, String...
classesToHideRegexStr) {
+ super(urls, parent);
+
+ Pattern pattern;
+
+ if (classesToHideRegexStr != null && classesToHideRegexStr.length > 0)
{
+ StringBuilder fullPattern = new StringBuilder();
+ for (String regex : classesToHideRegexStr) {
+ if (fullPattern.length() > 0) {
+ fullPattern.append('|');
+ }
+ fullPattern.append('(').append(regex).append(')');
+ }
+ pattern = Pattern.compile(fullPattern.toString());
+ } else {
+ pattern = null;
+ }
+
+ this.classesToHideRegex = pattern;
+
+ log.debug("Root server plugin classloader: regex=[" +
this.classesToHideRegex + "], urls="
+ + Arrays.asList(urls));
+ }
+
+ protected synchronized Class<?> loadClass(String name, boolean resolve) throws
ClassNotFoundException {
+ // first see if the class has already been loaded, if so, return the cached
class
+ Class<?> clazz = findLoadedClass(name);
+
+ if (clazz == null) {
+
+ // The class has not yet been loaded.
+ // Check to see if the class does not match our regex; if it does not, the
class is not to be "hidden" so we
+ // will try to load it using parent-first semantics. This will give our
parent classloader (i.e. the
+ // plugin container, the agent and/or the embedding component) first dibs to
load the class. If it
+ // still can't be found, child classloaders will be checked.
+ //
+ // If the class does match the regex, the class is to be hidden, meaning if
we can't load the class
+ // ourself, that class is not to be loaded from any parent classloader. Only
we can supply the class.
+
+ if (this.classesToHideRegex == null ||
!this.classesToHideRegex.matcher(name).matches()) {
+ try {
+ clazz = super.loadClass(name, resolve);
+ } catch (ClassNotFoundException cnfe) {
+ if (log.isTraceEnabled()) {
+ log.trace("Root plugin classloader cannot find unhidden
class: " + name);
+ }
+ throw cnfe;
+ }
+ } else {
+ try {
+ clazz = findClass(name);
+ if (resolve) {
+ resolveClass(clazz);
+ }
+ } catch (ClassNotFoundException cnfe) {
+ if (log.isTraceEnabled()) {
+ log.trace("Root plugin classloader cannot find potentially
hidden class: " + name);
+ }
+ throw cnfe;
+ }
+ }
+ }
+ return clazz;
+ }
+
+ @Override
+ public URL getResource(String name) {
+ URL res;
+
+ // TODO: This doesn't follow the exact "hidden" semantics used when
loading classes - is this a problem?
+ if (this.classesToHideRegex == null) {
+ res = super.getResource(name);
+ } else {
+ res = findResource(name);
+ if (res == null) {
+ res = super.getResource(name);
+ }
+ }
+
+ return res;
+ }
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginClassLoader.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginClassLoader.java
new file mode 100644
index 0000000..9f27ce9
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginClassLoader.java
@@ -0,0 +1,218 @@
+/*
+ * 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.enterprise.server.plugin.pc;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Classloader for the plugin jar itself and any embedded lib.
+ */
+// Note that this was an almost direct copy of the agent-side plugin container's
PluginClassLoader at one time
+public class ServerPluginClassLoader extends URLClassLoader {
+ private File embeddedJarsDirectory = null;
+
+ public ServerPluginClassLoader(URL[] urls, ClassLoader parent) {
+ super(urls, parent);
+ }
+
+ public void destroy() {
+ purge(embeddedJarsDirectory, true);
+ }
+
+ public static ServerPluginClassLoader create(String pluginJarName, URL pluginUrl,
boolean unpackNestedJars,
+ ClassLoader parent, File tmpDirectory) throws Exception {
+ return create(pluginJarName, new URL[] { pluginUrl }, unpackNestedJars, parent,
tmpDirectory);
+ }
+
+ public static ServerPluginClassLoader create(String pluginJarName, URL[] pluginUrls,
boolean unpackNestedJars,
+ ClassLoader parent, File tmpDirectory) throws Exception {
+ List<URL> classpathUrlList = new ArrayList<URL>();
+ File unpackedDirectory = null;
+
+ for (URL pluginUrl : pluginUrls) {
+ classpathUrlList.add(pluginUrl);
+
+ if (unpackNestedJars) {
+ try {
+ unpackedDirectory = unpackEmbeddedJars(pluginJarName, pluginUrl,
classpathUrlList, tmpDirectory);
+ } catch (Exception e) {
+ throw new Exception("Failed to unpack embedded JARs within:
" + pluginUrl);
+ }
+ }
+ }
+
+ URL[] classpath = classpathUrlList.toArray(new URL[classpathUrlList.size()]);
+ ServerPluginClassLoader newLoader = new ServerPluginClassLoader(classpath,
parent);
+ newLoader.embeddedJarsDirectory = unpackedDirectory;
+
+ return newLoader;
+ }
+
+ /**
+ * Unpacks all lib/* resources into a temporary directory, adds URLs to those newly
extracted resources and returns
+ * the directory where the jars were extracted. This will actually create a unique
subdirectory under the given
+ * <code>tmpDirectory</code>) which is where the extracted resources will
be placed. If the give <code>
+ * tmpDirectory</code> is <code>null</code>, the standard
platform's tmp directory will be used.
+ *
+ * @param pluginJarName name of the main plugin jar, used as part of the name to the
tmp directory
+ * @param pluginUrl the URL to the main plugin jar we are unpacking
+ * @param urls the URLs to the tmp directory resources that were unpacked
+ * @param tmpDirectory the parent directory that will contain the child directory
which will contain all extracted
+ * resources
+ *
+ * @return the location where all the extract files are now located
+ *
+ * @throws IOException
+ */
+ private static File unpackEmbeddedJars(String pluginJarName, URL pluginUrl,
List<URL> urls, File tmpDirectory)
+ throws IOException {
+ InputStream pluginStream = pluginUrl.openStream();
+ ZipInputStream zis = new ZipInputStream(new BufferedInputStream(pluginStream));
+ ZipEntry entry;
+ File extractionDirectory = null; // this is where we will actually store the
files we extract
+
+ try {
+ while ((entry = zis.getNextEntry()) != null) {
+ String entryName = entry.getName();
+
+ // Only care about entries in the lib directory
+ if (entryName.startsWith("lib") && (entryName.length()
> 4)) {
+ if (extractionDirectory == null) {
+ extractionDirectory = createTempDirectory(tmpDirectory,
pluginJarName);
+ }
+
+ int i = entryName.lastIndexOf('/');
+ if (i < 0) {
+ i = entryName.lastIndexOf('\\');
+ }
+
+ String s = entryName.substring(i + 1);
+
+ File file = null;
+ try {
+ if (s.endsWith(".jar")) {
+ file = File.createTempFile(s, null, extractionDirectory);
+ urls.add(file.toURI().toURL());
+ } else {
+ // All non-jar files are extracted as-is with the
+ // same filename.
+ file = new File(extractionDirectory, s);
+
+ // since we have a regular file, we need to make sure the tmp
dir is in classpath so it can be found
+ URL tmpUrl = extractionDirectory.toURI().toURL();
+ if (!urls.contains(tmpUrl)) {
+ urls.add(tmpUrl);
+ }
+ }
+
+ BufferedOutputStream outputStream;
+ try {
+ outputStream = new BufferedOutputStream(new
FileOutputStream(file));
+ } catch (FileNotFoundException ex) {
+ if (file.exists() && (file.length() > 0)) {
+ // e.g. on win32, agent running w/ dll loaded
PluginDumper cannot overwrite file inuse.
+ continue;
+ }
+
+ throw ex;
+ }
+
+ try {
+ file.deleteOnExit();
+
+ BufferedInputStream inputStream = new
BufferedInputStream(zis);
+
+ int count = 0;
+ byte[] b = new byte[8192];
+ while ((count = inputStream.read(b)) > -1) {
+ outputStream.write(b, 0, count);
+ }
+ } finally {
+ outputStream.flush();
+ outputStream.close();
+ }
+ } catch (IOException ioe) {
+ if (file != null) {
+ file.delete();
+ }
+
+ throw ioe;
+ }
+ }
+ }
+ } finally {
+ try {
+ zis.close();
+ } catch (Exception e) {
+ }
+ }
+
+ return extractionDirectory;
+ }
+
+ private static File createTempDirectory(File tmpDirectory, String pluginName) throws
IOException {
+ // Let's reuse the algorithm the JDK uses to determine a unique name:
+ // 1) create a temp file to get a unique name using JDK createTempFile
+ // 2) then quickly delete the file and...
+ // 3) convert it to a directory
+
+ File tmpDir = File.createTempFile(pluginName, ".classloader",
tmpDirectory); // create file with unique name
+ boolean deleteOk = tmpDir.delete(); // delete the tmp file and...
+ boolean mkdirsOk = tmpDir.mkdirs(); // ...convert it to a directory
+
+ if (!deleteOk || !mkdirsOk) {
+ throw new IOException("Failed to create temp classloader directory named
[" + tmpDir + "]");
+ }
+
+ tmpDir.deleteOnExit();
+
+ return tmpDir;
+ }
+
+ private void purge(File dir, boolean deleteIt) {
+ if (dir != null) {
+ if (dir.isDirectory()) {
+ File[] doomedFiles = dir.listFiles();
+ if (doomedFiles != null) {
+ for (File doomedFile : doomedFiles) {
+ purge(doomedFile, true); // call this method recursively
+ }
+ }
+ }
+
+ if (deleteIt) {
+ dir.delete();
+ }
+ }
+
+ return;
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainer.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainer.java
new file mode 100644
index 0000000..3a2cf36
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainer.java
@@ -0,0 +1,236 @@
+/*
+ * 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.enterprise.server.plugin.pc;
+
+import java.util.Date;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.quartz.JobDetail;
+import org.quartz.SchedulerException;
+import org.quartz.SimpleTrigger;
+
+import org.rhq.core.clientapi.server.plugin.content.InitializationException;
+import org.rhq.core.domain.content.ContentSource;
+import org.rhq.core.domain.content.PackageVersion;
+import org.rhq.enterprise.server.plugin.content.ContentProviderManager;
+import org.rhq.enterprise.server.plugin.content.ContentProviderPluginManager;
+import org.rhq.enterprise.server.scheduler.SchedulerLocal;
+import org.rhq.enterprise.server.scheduler.jobs.ContentSourceSyncJob;
+import org.rhq.enterprise.server.util.LookupUtil;
+
+/**
+ * The container responsible for managing the lifecycle of all server-side plugins.
+ *
+ * @author John Mazzitelli
+ */
+public class ServerPluginContainer {
+ private static final String SYNC_JOB_GROUP_NAME = "syncContentSource";
+
+ private static final Log log = LogFactory.getLog(ServerPluginContainer.class);
+
+ private ServerPluginContainerConfiguration configuration;
+ private ContentProviderPluginManager pluginManager;
+ private ContentProviderManager adapterManager;
+
+ /**
+ * Starts the plugin container, which will load all plugins and begin managing them.
+ *
+ * @param config
+ */
+ public void initialize(ServerPluginContainerConfiguration config) throws
InitializationException {
+ log.debug("Server plugin container has been initialized with config: "
+ config);
+
+ this.configuration = config;
+ this.pluginManager = createPluginManager();
+ this.adapterManager = createAdapterManager(this.pluginManager);
+
+ return;
+ }
+
+ /**
+ * Stops all plugins and cleans up after them.
+ */
+ public void shutdown() {
+ log.debug("Server plugin container is being shutdown");
+
+ this.adapterManager.shutdown();
+ this.pluginManager.shutdown();
+ this.configuration = null;
+ }
+
+ /**
+ * Returns the configuration that this object was initialized with. If this plugin
container was not
+ * {@link #initialize(ServerPluginContainerConfiguration) initialized} or has been
{@link #shutdown() shutdown},
+ * this will return <code>null</code>.
+ *
+ * @return the configuration
+ */
+ public ServerPluginContainerConfiguration getConfiguration() {
+ return configuration;
+ }
+
+ /**
+ * Returns the object that is responsible for managing all {@link
org.rhq.core.clientapi.server.plugin.content.ContentProvider adapters} which are the
+ * things that know how to download content from a specific {@link ContentSource}.
+ *
+ * @return adapter manager
+ */
+ public ContentProviderManager getAdapterManager() {
+ return adapterManager;
+ }
+
+ /**
+ * Returns the object that is responsible for managing all plugins and their
metadata.
+ *
+ * <p>This is protected to only allow subclasses access to this - external
clients to this PC should never have
+ * direct access to this plugin manager.</p>
+ *
+ * @return plugin manager
+ */
+ protected ContentProviderPluginManager getPluginManager() {
+ return pluginManager;
+ }
+
+ /**
+ * This will syncronize the given content source, meaning its {@link PackageVersion}s
will be updated and, if not
+ * lazy-loading, will load the package versions that are not loaded yet.
+ *
+ * <p>Note that this will perform the sync asynchronously in a separate thread.
This is because this sync operation
+ * can potentially run for hours and we do not want to block the calling
thread.</p>
+ *
+ * @param contentSource the content source to sync
+ *
+ * @throws SchedulerException if failed to schedule the job for immediate execution
+ */
+ public void syncNow(final ContentSource contentSource) throws SchedulerException {
+ // Create our job with a trigger that fires immediately and doesn't repeat.
+ // Make the name unique - we may already have our cron job schedules.
+ // What happens if this is triggered when our cron job is triggered? the job will
abort and let the current job finish
+ JobDetail job = new
JobDetail(ContentSourceSyncJob.createUniqueJobName(contentSource), SYNC_JOB_GROUP_NAME,
+ ContentSourceSyncJob.class, false, false, false);
+
+ ContentSourceSyncJob.createJobDataMap(contentSource, job);
+
+ SimpleTrigger trigger = new SimpleTrigger(job.getName(), job.getGroup());
+ trigger.setVolatility(false);
+
+ SchedulerLocal scheduler = LookupUtil.getSchedulerBean();
+ Date next = scheduler.scheduleJob(job, trigger);
+
+ log.info("Scheduled content source sync job [" + job.getName() +
':' + job.getGroup() + "] to fire now at ["
+ + next + "] for [" + contentSource + "]");
+
+ return;
+ }
+
+ /**
+ * This will schedule the sync job for the given content source. Once the scheduling
is complete, the content
+ * source's adapter will be asked to synchronize with the remote content source
according to the time(s) specified
+ * in the {@link ContentSource#getSyncSchedule() schedule}.
+ *
+ * <p>If the content source's sync schedule is empty, this method assumes
it should not be automatically sync'ed so
+ * no schedule will be created and this method simply returns.</p>
+ *
+ * @param contentSource
+ *
+ * @throws SchedulerException if failed to schedule the job
+ */
+ public void scheduleSyncJob(ContentSource contentSource) throws SchedulerException {
+ String syncSchedule = contentSource.getSyncSchedule();
+ if ((syncSchedule == null) || (syncSchedule.trim().length() == 0)) {
+ log.debug(contentSource.toString() + " does not define a sync schedule -
not scheduling");
+ return;
+ }
+
+ SchedulerLocal scheduler = LookupUtil.getSchedulerBean();
+ scheduler.scheduleCronJob(ContentSourceSyncJob.createJobName(contentSource),
SYNC_JOB_GROUP_NAME,
+ ContentSourceSyncJob.createJobDataMap(contentSource, null),
ContentSourceSyncJob.class, true, false,
+ syncSchedule);
+
+ return;
+ }
+
+ /**
+ * It will schedule one job per adapter such that each adapter is scheduled to be
synchronized as per its defined
+ * sync schedule. This must only be called when all content source adapters have been
initialized.
+ */
+ public void scheduleSyncJobs() {
+ if (this.adapterManager != null) {
+ for (ContentSource contentSource :
this.adapterManager.getAllContentSources()) {
+ try {
+ scheduleSyncJob(contentSource);
+ } catch (Exception e) {
+ log.warn("Could not schedule sync job for content source ["
+ contentSource + "]", e);
+ }
+ }
+ }
+
+ return;
+ }
+
+ /**
+ * This will unschedule the sync job for the given content source. Once unscheduled,
the content source's adapter
+ * will not be asked to synchronize with the remote content source.
+ *
+ * @param contentSource
+ *
+ * @throws SchedulerException if failed to unschedule the job
+ */
+ public void unscheduleSyncJob(ContentSource contentSource) throws SchedulerException
{
+ SchedulerLocal scheduler = LookupUtil.getSchedulerBean();
+ scheduler.deleteJob(ContentSourceSyncJob.createJobName(contentSource),
SYNC_JOB_GROUP_NAME);
+
+ return;
+ }
+
+ /**
+ * Creates, configures and initializes the plugin manager that the PC will use.
+ *
+ * <p>This is protected scope so subclasses can define their own plugin manager
to use. This is mainly to support
+ * tests.</p>
+ *
+ * @return the new plugin manager
+ */
+ protected ContentProviderPluginManager createPluginManager() {
+ ContentProviderPluginManager pm = new ContentProviderPluginManager();
+ pm.setConfiguration(getConfiguration());
+ pm.initialize();
+ return pm;
+ }
+
+ /**
+ * Creates, configures and initializes the adapter manager that the PC will use.
+ *
+ * <p>This is protected scope so subclasses can define their own adapter
manager to use. This is mainly to support
+ * tests.</p>
+ *
+ * @param pluginManager the plugin manager that was {@link #createPluginManager()
created} for use in the PC. The
+ * adapter manager can use this to obtain information about
plugins.
+ *
+ * @return the new adapter manager
+ */
+ protected ContentProviderManager createAdapterManager(ContentProviderPluginManager
pluginManager)
+ throws InitializationException {
+ ContentProviderManager am = new ContentProviderManager();
+ am.setConfiguration(getConfiguration());
+ am.initialize(pluginManager);
+ return am;
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainerConfiguration.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainerConfiguration.java
new file mode 100644
index 0000000..4925253
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginContainerConfiguration.java
@@ -0,0 +1,98 @@
+/*
+ * 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.enterprise.server.plugin.pc;
+
+import java.io.File;
+
+/**
+ * A very simple object used to contain server plugin container configuration.
+ *
+ * @author John Mazzitelli
+ */
+public class ServerPluginContainerConfiguration {
+ private File pluginDirectory;
+ private File tmpDirectory;
+ private String rootClassLoaderRegex;
+
+ public File getPluginDirectory() {
+ return this.pluginDirectory;
+ }
+
+ public void setPluginDirectory(File pluginDirectory) {
+ if (pluginDirectory == null) {
+ throw new IllegalArgumentException("pluginDirectory == null");
+ }
+
+ this.pluginDirectory = pluginDirectory;
+ }
+
+ public File getTemporaryDirectory() {
+ if (this.tmpDirectory != null) {
+ return this.tmpDirectory;
+ }
+
+ return new File(System.getProperty("java.io.tmpdir", "."));
+ }
+
+ public void setTemporaryDirectory(File tmpDir) {
+ this.tmpDirectory = tmpDir;
+ }
+
+ /**
+ * Returns the regex that defines what classes the plugin container can provide to
its
+ * plugins from its own classloader and its parents. If not
<code>null</code>, any classes
+ * found in the plugin container's classloader (and its parent classloaders) that
do
+ * NOT match this regex will be hidden from the plugins. If
<code>null</code>, there
+ * are no hidden classes and any class the plugin container's classloader has is
visible
+ * to all plugins.
+ *
+ * @return regular expression (may be <code>null</code>)
+ *
+ * @see RootServerPluginClassLoader
+ */
+ public String getRootServerPluginClassLoaderRegex() {
+ return this.rootClassLoaderRegex;
+ }
+
+ /**
+ * Sets the regex that defines what classes the plugin container should hide from its
plugins.
+ *
+ * @param regex regular expression
+ *
+ * @see RootServerPluginClassLoader
+ */
+ public void setRootPluginClassLoaderRegex(String regex) {
+ this.rootClassLoaderRegex = regex;
+ }
+
+ @Override
+ public String toString() {
+ File pdir = getPluginDirectory();
+ File tdir = getTemporaryDirectory();
+ String regex = getRootServerPluginClassLoaderRegex();
+
+ StringBuilder str = new StringBuilder("ServerPluginContainerConfiguration:
");
+ str.append("plugin-dir=[" + ((pdir != null) ? pdir.getAbsolutePath() :
"<null>"));
+ str.append("], tmp-dir=[" + ((tdir != null) ? tdir.getAbsolutePath() :
"<null>"));
+ str.append("], root-cl-regex=[" + ((regex != null) ? regex :
"<null>"));
+ str.append("]");
+
+ return str.toString();
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginEnvironment.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginEnvironment.java
new file mode 100644
index 0000000..9d62328
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginEnvironment.java
@@ -0,0 +1,247 @@
+/*
+ * 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.enterprise.server.plugin.pc;
+
+import java.io.File;
+import java.net.URL;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.ValidationEvent;
+import javax.xml.bind.util.ValidationEventCollector;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.rhq.core.clientapi.descriptor.DescriptorPackages;
+import
org.rhq.core.clientapi.descriptor.serverplugin.content.ContentSourcePluginDescriptor;
+import org.rhq.core.util.exception.WrappedRemotingException;
+
+/**
+ * Manages the context of a loaded plugin. This includes a classloader created
specifically for the plugin and access to
+ * its XML descriptor file.
+ *
+ * @author Greg Hinkle
+ * @author John Mazzitelli
+ */
+// this was an almost direct copy of the agent plugin container's PluginEnvironment
at one time
+public class ServerPluginEnvironment {
+ private static final Log log = LogFactory.getLog(ServerPluginEnvironment.class);
+
+ private static final String DEFAULT_PLUGIN_DESCRIPTOR_PATH =
"META-INF/rhq-serverplugin-content.xml";
+
+ // make these protected mainly to allow unit tests to extend this class to customize
these
+ protected URL pluginUrl;
+ protected String pluginName;
+ protected ClassLoader pluginClassLoader;
+ protected ContentSourcePluginDescriptor pluginDescriptor;
+ protected String pluginDescriptorPath;
+
+ /**
+ * Creates a new plugin environment. If <code>classLoader</code> is
specified, it will be used as the environment's
+ * classloader and <code>parentClassLoader</code> will be ignored. If
<code>classLoader</code> is <code>null</code>,
+ * then a {@link ServerPluginClassLoader} will be created with the given parent
classloader and it will
+ * unpack all embedded jars found in the given plugin URL's
<code>/lib</code> directory.
+ *
+ * @param pluginUrl where the plugin jar is located (may be
<code>null</code>, mainly to support tests)
+ * @param classLoader the classloader used by this environment
+ * @param parentClassLoader the parent classloader, if
<code>null</code>, will use this class's classloader - this
+ * is ignored if <code>classloader</code> is
not <code>null</code>
+ * @param tmpdir a directory where the jars are placed when unpacked
+ *
+ * @throws Exception
+ */
+ public ServerPluginEnvironment(URL pluginUrl, ClassLoader classLoader, ClassLoader
parentClassLoader, File tmpdir)
+ throws Exception {
+ initialize(pluginUrl, DEFAULT_PLUGIN_DESCRIPTOR_PATH, classLoader,
parentClassLoader, true, tmpdir);
+ }
+
+ /**
+ * This creates a {@link ServerPluginEnvironment} that will allow you to specify the
plugin's new class
+ * loader to not unpack its embedded jars, if they exist. You normally only pass in
<code>false</code> for <code>
+ * unpackJars</code> if you only want to process/parse the plugin descriptor
but do not plan on using this
+ * environment instance for actual runtime of the plugin (because it won't work
since you haven't unpacked the
+ * jars).
+ *
+ * <p>If you pass in a non-<code>null</code>
<code>classLoader</code>, then both <code>parentClassLoader</code>
and
+ * <code>unpackJars</code> is ignored since you are saying you already
know how to find the classes for this
+ * environment.</p>
+ *
+ * @param pluginUrl where the plugin jar is located (may be
<code>null</code>, mainly to support tests)
+ * @param classLoader the classloader used by this environment
+ * @param parentClassLoader the parent classloader, if
<code>null</code>, will use this class's classloader - this
+ * is ignored if <code>classloader</code> is
not <code>null</code>
+ * @param unpackJars if <code>true</code> and plugin jar has
embedded jars, they will be unpacked - this is
+ * ignored if <code>classloader</code> is not
<code>null</code>
+ * @param tmpdir a directory where the jars are placed if they are to be
unpacked; only meaningful when
+ * <code>unpackJars</code> is
<code>true</code>
+ *
+ * @throws Exception
+ */
+ public ServerPluginEnvironment(URL pluginUrl, ClassLoader classLoader, ClassLoader
parentClassLoader,
+ boolean unpackJars, File tmpdir) throws Exception {
+ initialize(pluginUrl, DEFAULT_PLUGIN_DESCRIPTOR_PATH, classLoader,
parentClassLoader, unpackJars, tmpdir);
+ }
+
+ public void destroy() {
+ // if its our own plugin classloader, let's tell it to clean up its directory
where the jars were unpacked
+ if (this.pluginClassLoader instanceof ServerPluginClassLoader) {
+ ((ServerPluginClassLoader) this.pluginClassLoader).destroy();
+ }
+ }
+
+ /**
+ * This will create the plugin's {@link #getClassLoader() classloader}, then read
and parse the
+ * {@link #getDescriptor() XML plugin descriptor} to make sure its valid.
+ *
+ * @param pluginJarUrl where the plugin jar is located (may be
<code>null</code>, mainly to support tests)
+ * @param descriptorPath the path within the plugin classloader where the XML
descriptor is found
+ * @param classLoader the classloader used by this environment
+ * @param parentClassLoader the parent classloader, if
<code>null</code>, will use this class's classloader - this
+ * is ignored if <code>classloader</code> is
not <code>null</code>
+ * @param unpackJars if <code>true</code> and plugin jar has
embedded jars, they will be unpacked - this is
+ * ignored if <code>classloader</code> is not
<code>null</code>
+ * @param tmpDirectory a directory where the jars are placed if they are to be
unpacked; only meaningful when
+ * <code>unpackJars</code> is
<code>true</code>
+ *
+ * @throws Exception
+ */
+ protected void initialize(URL pluginJarUrl, String descriptorPath, ClassLoader
classLoader,
+ ClassLoader parentClassLoader, boolean unpackJars, File tmpDirectory) throws
Exception {
+ if (classLoader == null) {
+ if (parentClassLoader == null) {
+ parentClassLoader = this.getClass().getClassLoader();
+ }
+
+ if (pluginJarUrl != null) {
+ classLoader = ServerPluginClassLoader.create(new
File(pluginJarUrl.getPath()).getName(), pluginJarUrl,
+ unpackJars, parentClassLoader, tmpDirectory);
+ } else {
+ // this is mainly to support tests
+ classLoader = parentClassLoader;
+ }
+ }
+
+ initializeDescriptor(classLoader, descriptorPath, pluginJarUrl);
+
+ this.pluginUrl = pluginJarUrl;
+ this.pluginDescriptorPath = descriptorPath;
+ this.pluginClassLoader = classLoader;
+ this.pluginName = this.pluginDescriptor.getName();
+ }
+
+ private void initializeDescriptor(ClassLoader classloader, String descriptorPath, URL
pluginJarUrl)
+ throws Exception {
+ // purpose of this method is to set the this.pluginDescriptor field and verify
the XML is valid
+
+ if (pluginJarUrl == null) {
+ throw new Exception("A valid plugin JAR URL must be supplied");
+ }
+
+ JAXBContext jaxbContext;
+
+ try {
+ jaxbContext = JAXBContext.newInstance(DescriptorPackages.CONTENT);
+ } catch (JAXBException e) {
+ throw new Exception("Could not instantiate the JAXB Context", new
WrappedRemotingException(e));
+ }
+
+ JarInputStream jis = null;
+ JarEntry descriptorEntry = null;
+
+ try {
+ jis = new JarInputStream(pluginJarUrl.openStream());
+ JarEntry nextEntry = jis.getNextJarEntry();
+ while (nextEntry != null && descriptorEntry == null) {
+ if (DEFAULT_PLUGIN_DESCRIPTOR_PATH.equals(nextEntry.getName())) {
+ descriptorEntry = nextEntry;
+ } else {
+ jis.closeEntry();
+ nextEntry = jis.getNextJarEntry();
+ }
+ }
+
+ if (descriptorEntry == null) {
+ throw new Exception("The plugin descriptor does not exist");
+ }
+
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ URL pluginSchemaURL =
getClass().getClassLoader().getResource("rhq-serverplugin-content.xsd");
+ Schema pluginSchema =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(
+ pluginSchemaURL);
+ unmarshaller.setSchema(pluginSchema);
+
+ ValidationEventCollector vec = new ValidationEventCollector();
+ unmarshaller.setEventHandler(vec);
+
+ this.pluginDescriptor = (ServerPluginDescriptor)
unmarshaller.unmarshal(jis);
+
+ for (ValidationEvent event : vec.getEvents()) {
+ log.debug("Plugin [" + this.pluginDescriptor.getName() +
"] descriptor messages {Severity: "
+ + event.getSeverity() + ", Message: " + event.getMessage()
+ ", Exception: "
+ + event.getLinkedException() + "}");
+ }
+ } catch (Exception e) {
+ throw new Exception("Could not successfully parse the plugin descriptor
[" + descriptorPath
+ + " found in URL [" + pluginJarUrl + "]", new
WrappedRemotingException(e));
+ } finally {
+ if (jis != null) {
+ try {
+ jis.close();
+ } catch (Exception e) {
+ log.warn("Cannot close jar stream [" + pluginJarUrl +
"]. Cause: " + e);
+ }
+ }
+ }
+
+ return;
+ }
+
+ public String getPluginName() {
+ return this.pluginName;
+ }
+
+ public URL getPluginUrl() {
+ return this.pluginUrl;
+ }
+
+ public ClassLoader getClassLoader() {
+ return this.pluginClassLoader;
+ }
+
+ public ContentSourcePluginDescriptor getDescriptor() {
+ return this.pluginDescriptor;
+ }
+
+ public String getPluginDescriptorPath() {
+ return this.pluginDescriptorPath;
+ }
+
+ @Override
+ public String toString() {
+ return this.pluginName + ": url=[" + this.pluginUrl + "],
descriptor-path=[" + this.pluginDescriptorPath + "]";
+ }
+}
\ 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
new file mode 100644
index 0000000..55b5120
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginService.java
@@ -0,0 +1,137 @@
+/*
+ * 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.enterprise.server.plugin.pc;
+
+import java.io.File;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.jboss.annotation.ejb.Management;
+import org.jboss.annotation.ejb.Service;
+import org.jboss.system.server.ServerConfig;
+
+import org.rhq.core.clientapi.server.plugin.content.InitializationException;
+import org.rhq.enterprise.server.RHQConstants;
+
+/**
+ * This is the singleton management service responsible for managing the lifecycle of
the
+ * {@link ServerPluginContainer}. It will be started when the entire server starts and
shutdown when the entire
+ * server shuts down. It has a management interface to allow it to be recycled on demand
when desired.
+ *
+ * @author John Mazzitelli
+ */
+(a)Management(ServerPluginServiceManagement.class)
+@Service(objectName = ServerPluginServiceManagement.OBJECT_NAME_STR)
+public class ServerPluginService implements ServerPluginServiceManagement {
+ private static final Log log = LogFactory.getLog(ServerPluginService.class);
+
+ private boolean started;
+ private ServerPluginContainer pluginContainer;
+
+ public synchronized void start() {
+ log.debug("The server plugin service has been deployed (but plugin container
will not be started yet)");
+ this.started = true;
+ return;
+ }
+
+ public synchronized void startPluginContainer() {
+ if (!this.started) {
+ throw new IllegalStateException(
+ "The server plugin service is not started - cannot start the plugin
container");
+ }
+
+ // only initialize if not already started; if already started/initialized, just
ignore
+ if (this.pluginContainer == null) {
+ log.debug("The server plugin service is now starting the server plugin
container");
+ this.pluginContainer = createPluginContainer();
+ }
+
+ return;
+ }
+
+ public synchronized void stopPluginContainer() {
+ if (this.started && (this.pluginContainer != null)) {
+ log.info("The server plugin service is now stopping - the server plugin
container will be shutdown now");
+
+ this.pluginContainer.shutdown();
+ this.pluginContainer = null;
+ }
+
+ return;
+ }
+
+ public synchronized void stop() {
+ if (this.started) {
+ stopPluginContainer();
+ this.started = false;
+ }
+
+ return;
+ }
+
+ public synchronized void restartPluginContainer() {
+ stopPluginContainer();
+ startPluginContainer();
+ }
+
+ public ServerPluginContainer getPluginContainer() {
+ return this.pluginContainer;
+ }
+
+ public boolean isStarted() {
+ return this.started;
+ }
+
+ public boolean isPluginContainerStarted() {
+ return this.pluginContainer != null;
+ }
+
+ /**
+ * This will create, configure and initialize the plugin container and return it.
+ *
+ * <p>This is protected to allow subclasses to override the PC that is created
by this service (mainly to support
+ * tests).</p>
+ *
+ * @return the PC that this service will use
+ */
+ protected ServerPluginContainer createPluginContainer() {
+ ServerPluginContainer pc = new ServerPluginContainer();
+
+ ServerPluginContainerConfiguration config = new
ServerPluginContainerConfiguration();
+
+ String pluginDirStr = System.getProperty(ServerConfig.SERVER_HOME_DIR);
+ File pluginDir = new File(pluginDirStr, "deploy/" +
RHQConstants.EAR_FILE_NAME + "/rhq-serverplugins");
+ config.setPluginDirectory(pluginDir);
+
+ String tmpDirStr = System.getProperty(ServerConfig.SERVER_TEMP_DIR);
+ config.setTemporaryDirectory(new File(tmpDirStr));
+
+ // TODO: determine what things to hide from our war classloader
+ config.setRootPluginClassLoaderRegex(null);
+
+ try {
+ pc.initialize(config);
+ } catch (InitializationException e) {
+ log.error("Error initializing server plugin container [" + pc +
"]", e);
+ }
+
+ return pc;
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginServiceManagement.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginServiceManagement.java
new file mode 100644
index 0000000..5244383
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/ServerPluginServiceManagement.java
@@ -0,0 +1,82 @@
+/*
+ * 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.enterprise.server.plugin.pc;
+
+/**
+ * The MBean management interface that defines the lifecycle methods for the {@link
ServerPluginService} service.
+ *
+ * @author John Mazzitelli
+ */
+public interface ServerPluginServiceManagement {
+ String OBJECT_NAME_STR = "rhq.serverplugin:service=ServerPluginService";
+
+ /**
+ * Starts the service but will <b>not</b> start the {@link
#getPluginContainer() plugin container}. After the server
+ * fully initializes, it should only then {@link #startPluginContainer() start the
plugin container}.
+ */
+ void start();
+
+ /**
+ * Shuts down this service along with the {@link #stopPluginContainer() plugin
container}.
+ */
+ void stop();
+
+ /**
+ * Starts the {@link #getPluginContainer() plugin container} which will load in all
plugins and start them. You
+ * cannot start the plugin container unless this service has {@link #start() been
started}. If the plugin container
+ * {@link #isPluginContainerStarted() is already started}, this does nothing and
returns.
+ */
+ void startPluginContainer();
+
+ /**
+ * Stops the {@link #getPluginContainer() plugin container} which will shuts down all
plugins. If the plugin
+ * container {@link #isPluginContainerStarted() is already shutdown}, this does
nothing and returns.
+ */
+ void stopPluginContainer();
+
+ /**
+ * Convienence method that first does a {@link #stopPluginContainer()} and then a
{@link #startPluginContainer()}.
+ */
+ void restartPluginContainer();
+
+ /**
+ * Returns the server side content source plugin container that will be responsible
for managing all plugins and
+ * their classloaders.
+ *
+ * @return the plugin container, if started. Will be <code>null</code> if
not started
+ */
+ ServerPluginContainer getPluginContainer();
+
+ /**
+ * Returns <code>true</code> if this service has been started. This does
not necessarily mean the
+ * {@link #getPluginContainer() plugin container} has be started - see {@link
#isPluginContainerStarted()} for that.
+ *
+ * @return <code>true</code> if this service has been started
+ */
+ boolean isStarted();
+
+ /**
+ * Returns <code>true</code> if the {@link #getPluginContainer() plugin
container} has be started. Note that this is
+ * <b>not</b> an indication if this service has started - see {@link
#isStarted()} for that. But, if the plugin
+ * container has been started, then by definition this service has also been
started.
+ *
+ * @return <code>true</code> if the plugin container has been started
+ */
+ boolean isPluginContainerStarted();
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProvider.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProvider.java
new file mode 100644
index 0000000..c8da253
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProvider.java
@@ -0,0 +1,63 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content;
+
+import org.rhq.core.domain.configuration.Configuration;
+
+/**
+ * Interface used by the server to communicate with a content provider. Content providers
implement this interface as
+ * well as any other source interfaces to further describe what functionality is provided
by the provider.
+ * <p/>
+ * The class name of this interface's implementation is the class name specified in
the server plugin descriptor.
+ *
+ * @author Jason Dobies
+ * @author John Mazzitelli
+ *
+ * @see RepoSource
+ * @see PackageSource
+ */
+public interface ContentProvider {
+
+ /**
+ * Initializes the adapter with the configuration values indicating how to connect to
the external source system.
+ *
+ * @param configuration user entered values describing how the content provider
should function.
+ *
+ * @throws Exception if the content provider has an issue being configured.
+ */
+ void initialize(Configuration configuration) throws Exception;
+
+ /**
+ * Informs the adapter that it should shutdown.
+ */
+ void shutdown();
+
+ /**
+ * Tests if the content provider can communicate with the external package source.
This will be called after
+ * {@link #initialize(Configuration)} to ensure the adapter is in a configured state
to run the test.
+ *
+ * @throws Exception if the connection cannot be made to the external system.
+ */
+ void testConnection() throws Exception;
+
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetails.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetails.java
new file mode 100644
index 0000000..de5a659
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetails.java
@@ -0,0 +1,75 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.rhq.core.domain.content.PackageDetails;
+
+/**
+ * These are the package details that a {@link ContentProvider} will use when refering to
package versions it finds
+ * in the remote repository. It is the same as {@link PackageDetails} with the addition
of a resource type name, since
+ * that is needed to make package types unique (along with the package type name itself,
which is specified in the
+ * {@link PackageDetails} superclass).
+ *
+ * @author John Mazzitelli
+ */
+public class ContentProviderPackageDetails extends PackageDetails {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Contains a set of specific versions of resources that this package can be applied
to. The resource type to which
+ * these apply is found in the {@link ContentProviderPackageDetailsKey}. If there are
no entries in this list, the
+ * package can be applied to any resource of the given type.
+ */
+ private Set<String> resourceVersions = new HashSet<String>();
+
+ public ContentProviderPackageDetails(ContentProviderPackageDetailsKey key) {
+ super(key);
+ }
+
+ /**
+ * Just a convienence method to return the key cast to the appropriate type.
+ *
+ * @return the key cast to the appropriate sub-type
+ */
+ public ContentProviderPackageDetailsKey getContentProviderPackageDetailsKey() {
+ return (ContentProviderPackageDetailsKey) super.getKey();
+ }
+
+ public Set<String> getResourceVersions() {
+ return resourceVersions;
+ }
+
+ public void setResourceVersions(Set<String> resourceVersions) {
+ if (resourceVersions == null) {
+ throw new IllegalArgumentException("resourceVersions cannot be
null");
+ }
+
+ this.resourceVersions = resourceVersions;
+ }
+
+ public void addResourceVersion(String version) {
+ this.resourceVersions.add(version);
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetailsKey.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetailsKey.java
new file mode 100644
index 0000000..5548c66
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderPackageDetailsKey.java
@@ -0,0 +1,119 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content;
+
+import org.rhq.core.domain.content.PackageDetailsKey;
+import org.rhq.core.domain.resource.ResourceType;
+
+/**
+ * The key to a content provider package details that a {@link ContentProvider} will use
when referring to package
+ * versions it finds in the remote repository. It is the same as {@link
PackageDetailsKey} with the addition of a
+ * resource type natural key (which is name and agent plugin name), since that is needed
to make package types unique
+ * (along with the package type name itself, which is specified in the {@link
PackageDetailsKey} superclass).
+ */
+public class ContentProviderPackageDetailsKey extends PackageDetailsKey {
+ private static final long serialVersionUID = 1L;
+
+ private final String resourceTypeName;
+ private final String resourceTypePluginName;
+
+ public ContentProviderPackageDetailsKey(String name, String version, String
packageTypeName, String architectureName,
+ String resourceTypeName, String resourceTypePluginName) {
+ super(name, version, packageTypeName, architectureName);
+
+ if (resourceTypeName == null) {
+ throw new IllegalArgumentException("resourceTypeName cannot be
null");
+ }
+
+ if (resourceTypePluginName == null) {
+ throw new IllegalArgumentException("resourceTypePluginName cannot be
null");
+ }
+
+ this.resourceTypeName = resourceTypeName;
+ this.resourceTypePluginName = resourceTypePluginName;
+ }
+
+ /**
+ * The name of the {@link ResourceType} that this package's type belongs to. All
package types are defined and
+ * supported by a particular {@link ResourceType}, this name is part of the natural
key of a resource type. See
+ * {@link #getResourceTypePluginName() plugin name} for the other part.
+ *
+ * @return resource type name
+ */
+ public String getResourceTypeName() {
+ return resourceTypeName;
+ }
+
+ /**
+ * The name of the plugin that defined the {@link ResourceType} that this
package's type belongs to. All package
+ * types are defined and supported by a particular {@link ResourceType}, this plugin
name is part of the natural key
+ * of a resource type. See {@link #getResourceTypeName() resource type name} for the
other part.
+ *
+ * @return the name of the plugin that defines the resource type that defined the
package type
+ */
+ public String getResourceTypePluginName() {
+ return resourceTypePluginName;
+ }
+
+ @Override
+ public String toString() {
+ return "ContentProviderPackageDetailsKey[" + super.toString() + ",
ResourceTypeName=" + resourceTypeName
+ + ", PluginName=" + resourceTypePluginName + "]";
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = (prime * result) + resourceTypeName.hashCode();
+ result = (prime * result) + resourceTypePluginName.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!super.equals(obj)) {
+ return false;
+ }
+
+ if (!(obj instanceof ContentProviderPackageDetailsKey)) {
+ return false;
+ }
+
+ final ContentProviderPackageDetailsKey other = (ContentProviderPackageDetailsKey)
obj;
+
+ if (!resourceTypeName.equals(other.resourceTypeName)) {
+ return false;
+ }
+
+ if (!resourceTypePluginName.equals(other.resourceTypePluginName)) {
+ return false;
+ }
+
+ return true;
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/InitializationException.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/InitializationException.java
new file mode 100644
index 0000000..786bdc7
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/InitializationException.java
@@ -0,0 +1,43 @@
+/*
+ * 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.core.clientapi.server.plugin.content;
+
+/**
+ *
+ * @author pkilambi
+ */
+public class InitializationException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public InitializationException() {
+ }
+
+ public InitializationException(String message) {
+ super(message);
+ }
+
+ public InitializationException(Throwable cause) {
+ super(cause);
+ }
+
+ public InitializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSource.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSource.java
new file mode 100644
index 0000000..15dd02a
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSource.java
@@ -0,0 +1,61 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content;
+
+import java.io.InputStream;
+import java.util.Collection;
+
+/**
+ * Indicates a content provider has the capability to provide packages into the server.
Package synchronization will
+ * be done through the calls defined in this interface. This interface should use the
configuration settings
+ * passed into the plugin through {@link
ContentProvider#initialize(org.rhq.core.domain.configuration.Configuration)}
+ *
+ * @author Jason Dobies
+ */
+public interface PackageSource {
+
+ /**
+ * Requests that this package source perform a synchronization with its external
package source.
+ *
+ * @param report used to populate the packages diff information necessary
to
+ * bring the server up to date
+ * with the current state of the external package source.
+ * @param existingPackages collection of packages the server currently has in its
inventory for this package
+ * source; used when determining package diff information for
the report.
+ * @throws Exception if the package source is unable to perform the synchronization,
for instance if the external
+ * source cannot be connected to.
+ */
+ void synchronizePackages(PackageSyncReport report,
Collection<ContentProviderPackageDetails> existingPackages)
+ throws Exception;
+
+ /**
+ * Get an input stream for the specified package.
+ *
+ * @param location The location of the package. This is an adapter specific location
that was originally set in the
+ * PackageDetails object as part of the synch report.
+ * @return An initialized input stream. <b>The caller is responsible for
closing the stream.</b>
+ * @throws Exception if failed to obtain the stream to the remote package data
+ */
+ InputStream getInputStream(String location) throws Exception;
+
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSyncReport.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSyncReport.java
new file mode 100644
index 0000000..81d7729
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/PackageSyncReport.java
@@ -0,0 +1,123 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Indicates the results of performing a syncronize with a package source. This object
carries the diff information
+ * necessary to update the server's current knowledge of the source's packages.
+ *
+ * @author Jason Dobies
+ */
+public class PackageSyncReport {
+
+ /**
+ * Set of packages that have been added to the external package source that are not
yet known to the server. A new
+ * version of a package constitutes an entry in this list.
+ */
+ private final Set<ContentProviderPackageDetails> newPackages = new
HashSet<ContentProviderPackageDetails>();
+
+ /**
+ * Set of packages that are already known to the server and whose metadata has
changed in the external package
+ * source. The data in each of these packages will be merged with the server's
existing knowledge of the package.
+ * Packages should only be included in this list if the name and version are the same
as a package in the server;
+ * new versions of a package belong in the <code>newPackages</code>
list.
+ */
+ private final Set<ContentProviderPackageDetails> updatedPackages = new
HashSet<ContentProviderPackageDetails>();
+
+ /**
+ * Set of packages that are known to the server but no longer in the external
source.
+ */
+ private final Set<ContentProviderPackageDetails> deletedPackages = new
HashSet<ContentProviderPackageDetails>();
+
+ /**
+ * The synchronization summary. Free form textual report.
+ */
+ private String summary;
+
+ public Set<ContentProviderPackageDetails> getNewPackages() {
+ return newPackages;
+ }
+
+ /**
+ * Add to the set of packages that have been added to the external package source
that are not yet known to the
+ * server. A new version of a package constitutes an entry in this list.
+ *
+ * @param newPackage contains the details of the new package to be added; should not
be <code>null</code>
+ */
+ public void addNewPackage(ContentProviderPackageDetails newPackage) {
+ this.newPackages.add(newPackage);
+ }
+
+ public Set<ContentProviderPackageDetails> getUpdatedPackages() {
+ return updatedPackages;
+ }
+
+ /**
+ * Add to the set of packages that are already known to the server and whose metadata
has changed in the external
+ * package source. The data in this package will be merged with the server's
existing knowledge of the package.
+ * Packages should only be added to this updated list if the name and version are the
same as a package in the
+ * server; new versions of a package belong in the
+ * {@link #addNewPackage(ContentProviderPackageDetails) new packages list}.
+ *
+ * @param updatedPackage contains the new information of a package that was updated;
should not be
+ * <code>null</code>
+ */
+ public void addUpdatedPackage(ContentProviderPackageDetails updatedPackage) {
+ this.updatedPackages.add(updatedPackage);
+ }
+
+ public Set<ContentProviderPackageDetails> getDeletedPackages() {
+ return deletedPackages;
+ }
+
+ /**
+ * Add to the set of packages that are known to the server but no longer in the
external source.
+ *
+ * @param deletedPackage details object identifying the package that was removed;
should not be <code>null</code>
+ */
+ public void addDeletePackage(ContentProviderPackageDetails deletedPackage) {
+ this.deletedPackages.add(deletedPackage);
+ }
+
+ public String getSummary() {
+ return summary;
+ }
+
+ /**
+ * The synchronization summary. Free form textual report that will be stored with the
content source sync report.
+ *
+ * @param summary should not be <code>null</code>
+ */
+ public void setSummary(String summary) {
+ this.summary = summary;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageSyncReport: new=[" + newPackages.size() + "],
updated=[" + updatedPackages.size()
+ + "], deleted=[" + deletedPackages.size() + "]";
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoDetails.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoDetails.java
new file mode 100644
index 0000000..7d6ff58
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoDetails.java
@@ -0,0 +1,130 @@
+/*
+* 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, 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.core.clientapi.server.plugin.content;
+
+/**
+ * Contains the information used to describe a single repo being introduced to the system
through the
+ * {@link RepoSource} interface. The parent-child relationship between repos is done
through the call to
+ * {@link #setParentRepoName(String)}.
+ *
+ * @author Jason Dobies
+ */
+public class RepoDetails {
+
+ private String name;
+ private String description;
+
+ private String parentRepoName;
+
+ private String repoGroup;
+
+ public RepoDetails(String name) {
+ setName(name);
+ }
+
+ public RepoDetails(String name, String parentRepoName) {
+ setName(name);
+ setParentRepoName(parentRepoName);
+ }
+
+ /**
+ * Returns the identifying name of the repo.
+ *
+ * @return cannot be <code>null</code>
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the repo being represented.
+ *
+ * @param name cannot be <code>null</code>
+ * @throws IllegalArgumentException is name is <code>null</code>
+ */
+ public void setName(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+
+ this.name = name;
+ }
+
+ /**
+ * Returns the name (identifier) of the parent repo for this repo. The name returned
here should match up with
+ * the name returned the call to {@link #getName()} on the parent repo.
+ *
+ * @return may be <code>null</code>
+ */
+ public String getParentRepoName() {
+ return parentRepoName;
+ }
+
+ /**
+ * Sets the name of the parent repo to associate this repo with. See {@link
#getParentRepoName()} for more
+ * details.
+ *
+ * @param parentRepoName may be <code>null</code>
+ */
+ public void setParentRepoName(String parentRepoName) {
+ this.parentRepoName = parentRepoName;
+ }
+
+ /**
+ * Returns a user-readable description of what the repo contains.
+ *
+ * @return may be <code>null</code>
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the name of the user-readable description of the repo contents.
+ *
+ * @param description may be <code>null</code>
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Returns the name (used to identify the group in the server) of the group the repo
should be belong to
+ * when it is imported.
+ *
+ * @return may be <code>null</code>
+ */
+ public String getRepoGroup() {
+ return repoGroup;
+ }
+
+ /**
+ * Sets the name of the group to assign this repo to. If the group doesn't exist
in the system or elsewhere in
+ * the import repos report, the repo will be created with no group membership.
+ *
+ * @param repoGroup may be <code>null</code> to indicate the repo does
not belong to a group
+ */
+ public void setRepoGroup(String repoGroup) {
+ this.repoGroup = repoGroup;
+ }
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoGroupDetails.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoGroupDetails.java
new file mode 100644
index 0000000..707fcac
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoGroupDetails.java
@@ -0,0 +1,104 @@
+/*
+* RHQ Management Platform
+* Copyright (C) 2009 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.core.clientapi.server.plugin.content;
+
+/**
+ * Represents a repo group being introduced by a repo source.
+ *
+ * @author Jason Dobies
+ *
+ * @see RepoSource
+ */
+public class RepoGroupDetails {
+
+ private String name;
+ private String typeName;
+ private String description;
+
+ public RepoGroupDetails(String name, String typeName) {
+ setName(name);
+ setTypeName(typeName);
+ }
+
+ /**
+ * Returns the name of the group.
+ *
+ * @return will not be <code>null</code>
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name of the group being represented.
+ *
+ * @param name cannot be <code>null</code>
+ */
+ public void setName(String name) {
+ if (name == null) {
+ throw new IllegalArgumentException("name cannot be null");
+ }
+
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of the type of group this instance represents.
+ *
+ * @return will not be <code>null</code>
+ */
+ public String getTypeName() {
+ return typeName;
+ }
+
+ /**
+ * Sets the name of the group type this repo belongs to.
+ *
+ * @param typeName cannot be <code>null</code>
+ */
+ public void setTypeName(String typeName) {
+ if (typeName == null) {
+ throw new IllegalArgumentException("typeName cannot be null");
+ }
+
+ this.typeName = typeName;
+ }
+
+ /**
+ * Returns the description of what this type represents.
+ *
+ * @return may be <code>null</code>
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Sets the description the group type should display to users.
+ *
+ * @param description may be <code>null</code>
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoImportReport.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoImportReport.java
new file mode 100644
index 0000000..2035db7
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoImportReport.java
@@ -0,0 +1,65 @@
+/*
+* RHQ Management Platform
+* Copyright (C) 2009 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.core.clientapi.server.plugin.content;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Holds on to the repos and repo groups to be imported into the server through a {@link
RepoSource}.
+ *
+ * @author Jason Dobies
+ */
+public class RepoImportReport {
+
+ private List<RepoDetails> repos = new ArrayList<RepoDetails>();
+ private List<RepoGroupDetails> repoGroups = new
ArrayList<RepoGroupDetails>();
+
+ public RepoImportReport() {
+ }
+
+ public List<RepoDetails> getRepos() {
+ return repos;
+ }
+
+ public void addRepo(RepoDetails repo) {
+ repos.add(repo);
+ }
+
+ public void addRepos(Collection<RepoDetails> repos) {
+ repos.addAll(repos);
+ }
+
+ public List<RepoGroupDetails> getRepoGroups() {
+ return repoGroups;
+ }
+
+ public void addRepoGroup(RepoGroupDetails repoGroup) {
+ repoGroups.add(repoGroup);
+ }
+
+ public void addRepoGroups(Collection<RepoGroupDetails> repoGroups) {
+ repoGroups.addAll(repoGroups);
+ }
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoSource.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoSource.java
new file mode 100644
index 0000000..6cff5e4
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/RepoSource.java
@@ -0,0 +1,44 @@
+/*
+* 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, 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.core.clientapi.server.plugin.content;
+
+/**
+ * Indicates a content provider has the capability to provide repos into the server. Repo
synchronization will be
+ * done through calls defined in this interface. This interface should use the
configuration settings
+ * passed into the plugin through {@link
ContentProvider#initialize(org.rhq.core.domain.configuration.Configuration)}
+ *
+ * @author Jason Dobies
+ */
+public interface RepoSource {
+
+ /**
+ * Requests the content provider return a list of all repos it wants to ensure exist
in the server. This call
+ * should return the current state of the repos as known to the content provider, not
a diff of what has
+ * changed from the previous call to it. The server will resolve the differences.
+ *
+ * @return contains a list of all groups and repos to be imported into the system
+ * @throws Exception if there is an error retrieving the repos that should be
reported to the user
+ */
+ RepoImportReport importRepos() throws Exception;
+
+}
diff --git
a/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/metadata/ContentSourcePluginMetadataManager.java
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/metadata/ContentSourcePluginMetadataManager.java
new file mode 100644
index 0000000..a45f882
--- /dev/null
+++
b/modules/enterprise/server/jar/src/main/java/org/rhq/enterprise/server/plugin/pc/content/metadata/ContentSourcePluginMetadataManager.java
@@ -0,0 +1,201 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content.metadata;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.rhq.core.clientapi.agent.metadata.ConfigurationMetadataParser;
+import
org.rhq.core.clientapi.descriptor.serverplugin.content.ContentSourcePluginDescriptor;
+import
org.rhq.core.clientapi.descriptor.serverplugin.content.ContentSourceTypeDefinition;
+import org.rhq.core.domain.configuration.definition.ConfigurationDefinition;
+import org.rhq.core.domain.content.ContentSourceType;
+import org.rhq.core.domain.content.DownloadMode;
+
+/**
+ * This is meant to provide an interface to the underlying metadata of a server plugin
for content. It will load,
+ * translate and cache the metadata for the rest of the services in the form of the
domain object classes and the jaxb
+ * version of the descriptors.
+ *
+ * @author John Mazzitelli
+ */
+public class ContentSourcePluginMetadataManager {
+ private Log log = LogFactory.getLog(ContentSourcePluginMetadataManager.class);
+
+ // outer map is keyed by plugin name; inner map keyed by content source type name
+ private Map<String, Map<String, ContentSourceType>> loadedPlugins;
+
+ public ContentSourcePluginMetadataManager() {
+ loadedPlugins = new HashMap<String, Map<String,
ContentSourceType>>();
+ }
+
+ /**
+ * This will remove all knowledge of the given plugin - that is, all content source
types deployed by the plugin
+ * will be removed from this manager.
+ *
+ * @param pluginName the plugin whose types are to be removed
+ */
+ public synchronized void unloadPlugin(String pluginName) {
+ loadedPlugins.remove(pluginName);
+ }
+
+ /**
+ * Transforms the pluginDescriptor into domain object form and stores those objects.
+ *
+ * @param pluginDescriptor the descriptor to transform
+ *
+ * @return the new content source types represented by this descriptor (not a copy)
+ */
+ public synchronized Collection<ContentSourceType>
loadPlugin(ContentSourcePluginDescriptor pluginDescriptor) {
+ try {
+ Map<String, ContentSourceType> pluginTypes =
loadedPlugins.get(pluginDescriptor.getName());
+
+ if (pluginTypes != null) {
+ pluginTypes.clear(); // this is a redeploy, delete the original types
+ } else {
+ pluginTypes = new HashMap<String, ContentSourceType>();
+ loadedPlugins.put(pluginDescriptor.getName(), pluginTypes);
+ }
+
+ for (ContentSourceTypeDefinition newType :
pluginDescriptor.getContentSourceType()) {
+ // TODO: right now, content source types cannot have the same name as any
other one
+ // even if defined in another plugin (i.e plugin's content
types are not scoped)
+ // Do we care? This just means one plugin dev cannot name a
content source type
+ // something that another plugin dev used already in another
plugin.
+ if (getContentSourceType(newType.getName()) == null) {
+ // create the new domain object represented by the XML
+ ContentSourceType contentSourceType = new ContentSourceType();
+ contentSourceType.setName(newType.getName());
+ contentSourceType.setDisplayName(newType.getDisplayName());
+ contentSourceType.setDescription(newType.getDescription());
+ contentSourceType.setPluginName(pluginDescriptor.getName());
+ contentSourceType.setDefaultLazyLoad(newType.isLazyLoad());
+
contentSourceType.setDefaultDownloadMode(DownloadMode.valueOf(newType.getDownloadMode()
+ .toUpperCase()));
+ contentSourceType.setDefaultSyncSchedule(newType.getSyncSchedule());
+ contentSourceType.setContentSourceApiClass(newType.getApiClass());
+
+ ConfigurationDefinition configDef =
ConfigurationMetadataParser.parse(newType.getName(), newType
+ .getConfiguration());
+
contentSourceType.setContentSourceConfigurationDefinition(configDef);
+
+ // add the new domain object to the list of domain objects for this
plugin
+ pluginTypes.put(contentSourceType.getName(), contentSourceType);
+ } else {
+ throw new Exception("Cannot redefine an existing content source
type:" + newType.getName());
+ }
+ }
+
+ return pluginTypes.values();
+ } catch (Exception e) {
+ log.error("Error transforming plugin descriptor [" +
pluginDescriptor.getName() + "]", e);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the {@link ContentSourceType} that has the given name. If no plugin
defined a type with that name, <code>
+ * null</code> is returned.
+ *
+ * @param typeName the name of the content source type to return
+ *
+ * @return the content source type with the given name or
<code>null</code> if none exists
+ */
+ public synchronized ContentSourceType getContentSourceType(String typeName) {
+ for (Map<String, ContentSourceType> pluginTypes : loadedPlugins.values())
{
+ ContentSourceType type = pluginTypes.get(typeName);
+ if (type != null) {
+ return type;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns all the {@link ContentSourceType}s that have been defined in all plugins.
+ *
+ * @return all content source types defined; will be empty if there are none
+ */
+ public synchronized Set<ContentSourceType> getAllContentSourceTypes() {
+ Set<ContentSourceType> allTypes = new HashSet<ContentSourceType>();
+
+ for (Map<String, ContentSourceType> pluginTypes : loadedPlugins.values())
{
+ allTypes.addAll(pluginTypes.values());
+ }
+
+ return allTypes;
+ }
+
+ /**
+ * Returns the names of all plugins that defined content source types.
+ *
+ * @return all plugin names
+ */
+ public synchronized Set<String> getPluginNames() {
+ return this.loadedPlugins.keySet();
+ }
+
+ /**
+ * Returns the {@link ContentSourceType}s defined by the given plugin. If there is no
plugin with that name, <code>
+ * null</code> is returned.
+ *
+ * @param pluginName the name of the plugin whose types are to be returned
+ *
+ * @return the content source types defined by the given plugin or
<code>null</code> if no plugin exists with that
+ * name - the returned collection is not a copy, its backed by this manager
+ */
+ public synchronized Collection<ContentSourceType>
getContentSourceTypesByPlugin(String pluginName) {
+ Map<String, ContentSourceType> pluginTypes =
loadedPlugins.get(pluginName);
+
+ if (pluginTypes == null) {
+ return null;
+ }
+
+ return pluginTypes.values();
+ }
+
+ /**
+ * Returns the name of the plugin that deployed the given content source type.
<code>null</code> will be returned if
+ * unknown.
+ *
+ * @param type the name of the plugin that deployed this type is to be returned
+ *
+ * @return name of the plugin
+ */
+ public synchronized String getPluginNameFromContentSourceType(ContentSourceType type)
{
+ Set<String> pluginNames = loadedPlugins.keySet();
+ for (String pluginName : pluginNames) {
+ if (loadedPlugins.get(pluginName).containsValue(type)) {
+ return pluginName;
+ }
+ }
+
+ return null;
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerTest.java
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerTest.java
new file mode 100644
index 0000000..da041b1
--- /dev/null
+++
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentProviderManagerTest.java
@@ -0,0 +1,368 @@
+/*
+* RHQ Management Platform
+* Copyright (C) 2009 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.enterprise.server.plugin.content;
+
+import org.rhq.core.clientapi.server.plugin.content.ContentProvider;
+import org.rhq.core.clientapi.server.plugin.content.ContentProviderPackageDetails;
+import org.rhq.core.clientapi.server.plugin.content.ContentProviderPackageDetailsKey;
+import org.rhq.core.clientapi.server.plugin.content.PackageSource;
+import org.rhq.core.clientapi.server.plugin.content.PackageSyncReport;
+import org.rhq.core.clientapi.server.plugin.content.RepoDetails;
+import org.rhq.core.clientapi.server.plugin.content.RepoGroupDetails;
+import org.rhq.core.clientapi.server.plugin.content.RepoImportReport;
+import org.rhq.core.clientapi.server.plugin.content.RepoSource;
+import org.rhq.core.domain.auth.Subject;
+import org.rhq.core.domain.configuration.Configuration;
+import org.rhq.core.domain.content.ContentSource;
+import org.rhq.core.domain.content.ContentSourceType;
+import org.rhq.core.domain.content.PackageType;
+import org.rhq.core.domain.content.PackageVersion;
+import org.rhq.core.domain.content.PackageVersionContentSource;
+import org.rhq.core.domain.content.Repo;
+import org.rhq.core.domain.content.RepoGroup;
+import org.rhq.core.domain.content.RepoRepoGroup;
+import org.rhq.core.domain.content.RepoRepoRelationship;
+import org.rhq.core.domain.content.RepoRelationship;
+import org.rhq.core.domain.criteria.RepoCriteria;
+import org.rhq.core.domain.resource.ResourceCategory;
+import org.rhq.core.domain.resource.ResourceType;
+import org.rhq.core.domain.util.PageList;
+import org.rhq.enterprise.server.auth.SubjectManagerLocal;
+import org.rhq.enterprise.server.content.ContentSourceManagerLocal;
+import org.rhq.enterprise.server.content.RepoManagerLocal;
+import org.rhq.enterprise.server.test.AbstractEJB3Test;
+import org.rhq.enterprise.server.test.TestContentSourcePluginService;
+import org.rhq.enterprise.server.util.LookupUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.persistence.EntityManager;
+import javax.persistence.Query;
+import javax.transaction.TransactionManager;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author Jason Dobies
+ */
+public class ContentProviderManagerTest extends AbstractEJB3Test {
+
+ private static final String PACKAGE_TYPE_NAME = "testPackageType";
+ private static final String RESOURCE_TYPE_NAME = "testResourceType";
+ private static final String PLUGIN_NAME = "testPlugin";
+ private static final String PACKAGE_NAME = "package1";
+ private static final String PACKAGE_VERSION = "1.0";
+ private static final String PACKAGE_ARCH = "noarch";
+
+ // The following variables need to be cleaned up at the end of the test
+
+ private ContentSourceType testSourceType;
+
+ private ContentSource testSource;
+ private PackageType testPackageType;
+
+ private ResourceType testResourceType;
+ private List<Integer> reposToDelete = new ArrayList<Integer>();
+ private List<Integer> repoGroupsToDelete = new ArrayList<Integer>();
+ private List<Integer> packagesToDelete = new ArrayList<Integer>();
+ private Integer repoId;
+ private Integer relatedRepoId;
+
+ @BeforeMethod
+ public void setupBeforeMethod() throws Exception {
+
+ // Plugin service setup
+ prepareScheduler();
+ TestContentSourcePluginService pluginService =
prepareContentSourcePluginService();
+ pluginService.startPluginContainer();
+
+ // Because of the (current) transaction settings of some of the nested methods
(i.e. REQUIRES_NEW),
+ // this test must commit its data and clean up after itself, as compared to
simply rolling back the
+ // transaction at the end.
+ TransactionManager tx = getTransactionManager();
+ tx.begin();
+ EntityManager entityManager = getEntityManager();
+
+ ContentSourceManagerLocal contentManager = LookupUtil.getContentSourceManager();
+ SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
+ Subject overlord = subjectManager.getOverlord();
+
+ // Create a sample content source type that will be used in this test
+ testSourceType = new ContentSourceType("testType");
+ entityManager.persist(testSourceType);
+
+ // Add a content source to the DB to hang the sync against
+ testSource = new ContentSource("testSource", testSourceType);
+ contentManager.simpleCreateContentSource(overlord, testSource);
+
+ // Create a sample package type that will be used for packages sync'd in the
test
+ testResourceType = new ResourceType(RESOURCE_TYPE_NAME, PLUGIN_NAME,
ResourceCategory.PLATFORM, null);
+ entityManager.persist(testResourceType);
+
+ testPackageType = new PackageType(PACKAGE_TYPE_NAME, testResourceType);
+ entityManager.persist(testPackageType);
+
+ tx.commit();
+ }
+
+ @AfterMethod
+ public void tearDownAfterMethod() throws Exception {
+
+ // Transactional stuff
+ TransactionManager tx = getTransactionManager();
+ tx.begin();
+ EntityManager entityManager = getEntityManager();
+
+ RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
+ SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
+ Subject overlord = subjectManager.getOverlord();
+
+ // Delete the repo relationships
+
entityManager.createNamedQuery(RepoRepoRelationship.DELETE_BY_REPO_ID).setParameter(
+ "repoId", repoId).executeUpdate();
+
+
entityManager.createNamedQuery(RepoRelationship.DELETE_BY_RELATED_REPO_ID).setParameter(
+ "relatedRepoId", relatedRepoId).executeUpdate();
+
+ // Delete any repos that were created in this test
+ for (Integer repoId : reposToDelete) {
+ repoManager.deleteRepo(overlord, repoId);
+ }
+
+ // Delete any repo groups that were created in this test
+ for (Integer repoGroupId : repoGroupsToDelete) {
+ repoManager.deleteRepoGroup(overlord, repoGroupId);
+ }
+
+ // First disassociate packages from the content source
+
entityManager.createNamedQuery(PackageVersionContentSource.DELETE_BY_CONTENT_SOURCE_ID).setParameter(
+ "contentSourceId", testSource.getId()).executeUpdate();
+
+ // Delete any packages created in this test
+ for (Integer packageId : packagesToDelete) {
+ PackageVersion deleteMe = entityManager.find(PackageVersion.class,
packageId);
+ entityManager.remove(deleteMe);
+ }
+
+ // Delete the source that was created
+ testSource = entityManager.find(ContentSource.class, testSource.getId());
+ entityManager.remove(testSource);
+
+ // Delete the fake package type
+ testPackageType = entityManager.find(PackageType.class,
testPackageType.getId());
+ entityManager.remove(testPackageType);
+
+ // Delete the fake resource type
+ testResourceType = entityManager.find(ResourceType.class,
testResourceType.getId());
+ entityManager.remove(testResourceType);
+
+ // Delete the fake source type
+ testSourceType = entityManager.find(ContentSourceType.class,
testSourceType.getId());
+ entityManager.remove(testSourceType);
+
+ tx.commit();
+
+ // Plugin service teardown
+ unprepareContentSourcePluginService();
+ unprepareScheduler();
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void synchronizeContentSource() throws Exception {
+
+ // Setup
+ RepoManagerLocal repoManager = LookupUtil.getRepoManagerLocal();
+ SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager();
+ Subject overlord = subjectManager.getOverlord();
+
+ TestContentProviderManager providerManager = new TestContentProviderManager();
+
+ // Test
+ boolean completed =
providerManager.synchronizeContentSource(testSource.getId());
+ assert completed;
+
+ // Verify RepoGroups
+ RepoGroup repoGroup = repoManager.getRepoGroupByName("testRepoGroup");
+ assert repoGroup != null;
+ repoGroupsToDelete.add(repoGroup.getId());
+
+ // Verify Repos
+ List<Repo> retrievedRepos;
+
+ // -> Simple Repo
+ retrievedRepos = repoManager.getRepoByName("testRepo1");
+ assert retrievedRepos.size() == 1;
+ reposToDelete.add(retrievedRepos.get(0).getId());
+
+ // -> Repo in a group
+ retrievedRepos = repoManager.getRepoByName("testRepo2");
+ assert retrievedRepos.size() == 1;
+ reposToDelete.add(retrievedRepos.get(0).getId());
+
+ Repo repoInGroup = retrievedRepos.get(0);
+
+ RepoCriteria findWithRepoGroup = new RepoCriteria();
+ findWithRepoGroup.fetchRepoRepoGroups(true);
+ findWithRepoGroup.addFilterId(repoInGroup.getId());
+
+ PageList<Repo> repoPageList = repoManager.findReposByCriteria(overlord,
findWithRepoGroup);
+ repoInGroup = repoPageList.get(0);
+
+ Set<RepoRepoGroup> repoGroups = repoInGroup.getRepoRepoGroups();
+ assert repoGroups.size() == 1;
+
+ RepoRepoGroup repoRepoGroup = repoGroups.iterator().next();
+ assert
repoRepoGroup.getRepoRepoGroupPK().getRepoGroup().getName().equals("testRepoGroup");
+ assert
repoRepoGroup.getRepoRepoGroupPK().getRepo().getName().equals("testRepo2");
+
+ // -> Repo with a parent
+ retrievedRepos = repoManager.getRepoByName("testRepo3");
+ assert retrievedRepos.size() == 1;
+ reposToDelete.add(retrievedRepos.get(0).getId());
+ relatedRepoId = retrievedRepos.get(0).getId();
+
+ retrievedRepos = repoManager.getRepoByName("testRepo4");
+ assert retrievedRepos.size() == 1;
+ reposToDelete.add(retrievedRepos.get(0).getId());
+ repoId = retrievedRepos.get(0).getId();
+
+ RepoCriteria findWithRelationships = new RepoCriteria();
+ findWithRelationships.addFilterName("testRepo4");
+ findWithRelationships.fetchRepoRepoRelationships(true);
+ PageList<Repo> childRepoList = repoManager.findReposByCriteria(overlord,
findWithRelationships);
+ assert childRepoList.size() == 1;
+
+ Repo childRepo = childRepoList.get(0);
+ Set<RepoRepoRelationship> childRepoRepoRelationship =
childRepo.getRepoRepoRelationships();
+ assert childRepoRepoRelationship.size() == 1;
+
+ // -> Non-existent repo
+ retrievedRepos = repoManager.getRepoByName("testRepoFoo");
+ assert retrievedRepos.size() == 0;
+
+ // Verify Packages
+ TransactionManager tx = getTransactionManager();
+ tx.begin();
+ EntityManager entityManager = getEntityManager();
+
+ try {
+ Query packageQuery =
entityManager.createNamedQuery(PackageVersion.QUERY_FIND_BY_PACKAGE_DETAILS_KEY);
+ packageQuery.setParameter("packageName", PACKAGE_NAME);
+ packageQuery.setParameter("packageTypeName", PACKAGE_TYPE_NAME);
+ packageQuery.setParameter("resourceTypeId",
testResourceType.getId());
+ packageQuery.setParameter("architectureName", PACKAGE_ARCH);
+ packageQuery.setParameter("version", PACKAGE_VERSION);
+
+ List<PackageVersion> packageList = packageQuery.getResultList();
+ assert packageList.size() == 1;
+ packagesToDelete.add(packageList.get(0).getId());
+ } finally {
+ tx.rollback();
+ }
+
+ }
+
+ /**
+ * Mock implementation of a content provider that will return known data.
+ */
+ private class TestContentProvider implements ContentProvider, PackageSource,
RepoSource {
+
+ public RepoImportReport importRepos() throws Exception {
+ RepoImportReport report = new RepoImportReport();
+
+ // Create a repo group in the system
+ RepoGroupDetails group1 = new RepoGroupDetails("testRepoGroup",
"family");
+ report.addRepoGroup(group1);
+
+ // Simple repo
+ RepoDetails repo1 = new RepoDetails("testRepo1");
+ repo1.setDescription("First test repo");
+ report.addRepo(repo1);
+
+ // Repo belonging to a group that was created in the sync
+ RepoDetails repo2 = new RepoDetails("testRepo2");
+ repo2.setRepoGroup("testRepoGroup");
+ report.addRepo(repo2);
+
+ // Repo with a parent repo created in this sync
+ // Parent explicitly added to this list *after* this child to ensure
that's not a problem
+ RepoDetails repo3 = new RepoDetails("testRepo3");
+ report.addRepo(repo3);
+
+ RepoDetails repo4 = new RepoDetails("testRepo4");
+ repo4.setParentRepoName("testRepo3");
+ report.addRepo(repo4);
+
+ return report;
+ }
+
+ public void synchronizePackages(PackageSyncReport report,
+ Collection<ContentProviderPackageDetails>
existingPackages) throws Exception {
+ ContentProviderPackageDetailsKey key1 =
+ new ContentProviderPackageDetailsKey(PACKAGE_NAME, PACKAGE_VERSION,
PACKAGE_TYPE_NAME,
+ PACKAGE_ARCH, RESOURCE_TYPE_NAME, PLUGIN_NAME);
+ ContentProviderPackageDetails pkg1 = new
ContentProviderPackageDetails(key1);
+ pkg1.setLocation("repo/foo");
+
+ report.addNewPackage(pkg1);
+ }
+
+ public void initialize(Configuration configuration) throws Exception {
+ // No-op
+ }
+
+ public void shutdown() {
+ // No-op
+ }
+
+ public void testConnection() throws Exception {
+ // No-op
+ }
+
+
+ public InputStream getInputStream(String location) throws Exception {
+ // No-op
+ return null;
+ }
+
+ }
+
+ /**
+ * Stubs out the methods in {@link ContentProviderManager} that would go out and
expect a fully packaged plugin.
+ * Instead, use the mock implementation provided above.
+ */
+ private class TestContentProviderManager extends ContentProviderManager {
+
+ private ContentProvider testProvider = new TestContentProvider();
+
+ protected ContentProvider getIsolatedContentProvider(int contentProviderId)
throws RuntimeException {
+ return testProvider;
+ }
+ }
+
+}
diff --git
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentSourcePackageDetailsKeyTest.java
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentSourcePackageDetailsKeyTest.java
new file mode 100644
index 0000000..d889e03
--- /dev/null
+++
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/plugin/pc/content/ContentSourcePackageDetailsKeyTest.java
@@ -0,0 +1,69 @@
+ /*
+ * 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, 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.core.clientapi.server.plugin.content;
+
+import org.testng.annotations.Test;
+
+@Test
+public class ContentSourcePackageDetailsKeyTest {
+ public void testEqualsHashcode() {
+ ContentProviderPackageDetailsKey key1;
+ ContentProviderPackageDetailsKey key2;
+
+ key1 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "rt1", "plugin1");
+ key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "rt1", "plugin1");
+ assert key1.equals(key2);
+ assert key2.equals(key1);
+ assert key1.hashCode() == key2.hashCode();
+
+ key2 = new ContentProviderPackageDetailsKey("BLAH", "ver1",
"pt1", "arch1", "rt1", "plugin1");
+ assert !key1.equals(key2);
+ assert !key2.equals(key1);
+ assert key1.hashCode() != key2.hashCode();
+
+ key2 = new ContentProviderPackageDetailsKey("name1", "BLAH",
"pt1", "arch1", "rt1", "plugin1");
+ assert !key1.equals(key2);
+ assert !key2.equals(key1);
+ assert key1.hashCode() != key2.hashCode();
+
+ key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"BLAH", "arch1", "rt1", "plugin1");
+ assert !key1.equals(key2);
+ assert !key2.equals(key1);
+ assert key1.hashCode() != key2.hashCode();
+
+ key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "BLAH", "rt1", "plugin1");
+ assert !key1.equals(key2);
+ assert !key2.equals(key1);
+ assert key1.hashCode() != key2.hashCode();
+
+ key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "BLAH", "plugin1");
+ assert !key1.equals(key2);
+ assert !key2.equals(key1);
+ assert key1.hashCode() != key2.hashCode();
+
+ key2 = new ContentProviderPackageDetailsKey("name1", "ver1",
"pt1", "arch1", "rt1", "BLAH");
+ assert !key1.equals(key2);
+ assert !key2.equals(key1);
+ assert key1.hashCode() != key2.hashCode();
+ }
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginService.java
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginService.java
index 6a52978..c80b295 100644
---
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginService.java
+++
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginService.java
@@ -35,20 +35,19 @@ import
org.rhq.enterprise.server.plugin.content.ContentProviderManager;
import org.rhq.enterprise.server.plugin.content.ContentProviderPluginContainer;
import
org.rhq.enterprise.server.plugin.content.ContentProviderPluginContainerConfiguration;
import org.rhq.enterprise.server.plugin.content.ContentProviderPluginManager;
-import org.rhq.enterprise.server.plugin.content.ContentProviderPluginService;
+import org.rhq.enterprise.server.plugin.pc.ServerPluginService;
/**
- * Used as a mock service for the content source plugin containr.
+ * Used as a mock service for the content source plugin container.
*/
-public class TestContentSourcePluginService extends ContentProviderPluginService
implements
- TestContentSourcePluginServiceMBean {
+public class TestContentSourcePluginService extends ServerPluginService implements
TestContentSourcePluginServiceMBean {
// public so tests can directly set these
public Map<ContentSource, ContentProvider> testAdapters;
public PackageSyncReport testLastSyncReport;
public Map<ContentSource, Collection<ContentProviderPackageDetails>>
testExistingPackages;
@Override
- protected ContentProviderPluginContainer createPluginContainer() {
+ protected ServerPluginContainer createPluginContainer() {
ContentProviderPluginContainer pc = new TestContentSourcePluginContainer();
ContentProviderPluginContainerConfiguration config = new
ContentProviderPluginContainerConfiguration();
try {
diff --git
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginServiceMBean.java
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginServiceMBean.java
index 1e653da..170d2d7 100644
---
a/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginServiceMBean.java
+++
b/modules/enterprise/server/jar/src/test/java/org/rhq/enterprise/server/test/TestContentSourcePluginServiceMBean.java
@@ -18,7 +18,7 @@
*/
package org.rhq.enterprise.server.test;
-import org.rhq.enterprise.server.plugin.content.ContentProviderPluginServiceManagement;
+import org.rhq.enterprise.server.plugin.pc.ServerPluginServiceManagement;
-public interface TestContentSourcePluginServiceMBean extends
ContentProviderPluginServiceManagement {
+public interface TestContentSourcePluginServiceMBean extends
ServerPluginServiceManagement {
}
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin.xml
b/modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin.xml
new file mode 100644
index 0000000..0740eeb
--- /dev/null
+++
b/modules/enterprise/server/plugins/disk/src/main/resources/META-INF/rhq-serverplugin.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<content-plugin name="DiskContentSourcePlugin"
+ version="1.0"
+ apiVersion="2.0"
+ xmlns="urn:xmlns:rhq-serverplugin.content"
+ xmlns:c="urn:xmlns:server:rhq-configuration">
+
+ <contentSourceType name="DiskSource"
+ displayName="Local Disk Storage Content Source"
+ description="This content source retrieves packages from a
local file system. If deployed in an HA environment, this must be on a distributed file
system that all servers can access."
+ lazyLoad="true"
+ downloadMode="never"
+
apiClass="org.rhq.enterprise.server.plugins.disk.DiskSource">
+
+ <configuration>
+ <c:simple-property name="rootDirectory" type="directory"
required="true" description="The root directory that contains all content
that is to be served by this content source. In an HA environment, this must be on a
distributed file system that all servers can access."/>
+ <!-- would like to be able to define multiple package types, but the UI
doesn't allow editing maps yet
+ <c:list-property name="packageTypes" required="true"
description="Defines the different package types that can be found on this disk
content source">
+ <c:map-property name="packageType">
+ -->
+ <c:simple-property name="filenameFilter"
required="true" summary="true" default=".*"
description="A regular expression that identifies a file of this package type (e.g.
'.*\.jar', '.*/i686/.*\.rpm$')"/>
+ <c:simple-property name="packageTypeName"
required="true" summary="true" description="The name that
identifies the kind of package this type represents (e.g. 'ear',
'rpm')"/>
+ <c:simple-property name="architectureName"
required="true" summary="true" default="noarch"
description="The specific hardware architecture this type of package can be deployed
on. If there is no specific architecture required, use 'noarch'. (e.g.
'i686', 'amd64')"/>
+ <c:simple-property name="resourceTypeName"
required="true" summary="true" description="The name of the
resource type on which this package can be deployed. This is the resource type name as
defined in the agent plugin. (e.g. 'Linux', 'JBossAS Server')"/>
+ <c:simple-property name="resourceTypePluginName"
required="true" summary="true" description="The name of the
plugin that defined the resource type. (e.g. 'Platform',
'JBossAS')"/>
+ <!--
+ </c:map-property>
+ </c:list-property>
+ -->
+ </configuration>
+
+ </contentSourceType>
+
+</content-plugin>
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin.xml
b/modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin.xml
new file mode 100644
index 0000000..7e29279
--- /dev/null
+++
b/modules/enterprise/server/plugins/jboss-software/src/main/resources/META-INF/rhq-serverplugin.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<plugin name="JBossASPatchContentSourcePlugin"
+ xmlns="urn:xmlns:rhq-serverplugin.content"
+ xmlns:c="urn:xmlns:server:rhq-configuration">
+
+ <contentSourceType name="JBossASPatchSource"
+ displayName="JBoss AS Patch Content Source"
+ description="This content source retrieves packages from the
JBoss CSP RSS feed."
+ lazyLoad="true"
+
apiClass="org.rhq.enterprise.server.plugins.jboss.software.JBossSoftwareContentSourceAdapter">
+
+ <configuration>
+ <c:group name="csp" displayName="CSP Feed Settings">
+ <c:simple-property name="url" displayName="Feed URL"
type="string" required="true"
+ description="Destination URL of the feed."/>
+ <c:simple-property name="username"
displayName="Username" type="string" required="false"
+ description="Username used to log into the
feed."/>
+ <c:simple-property name="password"
displayName="Password" type="password" required="false"
+ description="Password used to log into the
feed."/>
+ <c:simple-property name="active" displayName="Active"
type="boolean" required="true" default="true"
+ description="Indicates if this instance should go out
and check the feed for packages."/>
+ </c:group>
+ <c:group name="proxy" displayName="Proxy Settings"
hiddenByDefault="true">
+ <c:simple-property name="proxyUrl" displayName="Proxy
URL" type="string" required="false"
+ description="Optional. URL of the proxy server to use
for this connection."/>
+ <c:simple-property name="proxyPort" displayName="Proxy
Port" type="string" required="false"
+ description="Optional. Port of the proxy server to
use for this connection."/>
+ <c:simple-property name="proxyUsername" displayName="Proxy
Username" type="string" required="false"
+ description="Optional. If the proxy requires
authentication, this is the user to log in as."/>
+ <c:simple-property name="proxyPassword" displayName="Proxy
Password" type="password" required="false"
+ description="Optional. If the proxy requires
authentitcation, this is the password for the user."/>
+ </c:group>
+ </configuration>
+
+ </contentSourceType>
+
+</plugin>
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin.xml
b/modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin.xml
new file mode 100644
index 0000000..457305d
--- /dev/null
+++
b/modules/enterprise/server/plugins/rhnhosted/src/main/resources/META-INF/rhq-serverplugin.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<plugin name="RHNHostedPlugin"
+ xmlns="urn:xmlns:rhq-serverplugin.content"
+ xmlns:c="urn:xmlns:server:rhq-configuration">
+
+ <contentSourceType name="RHNSource"
+ displayName="RHN Hosted Source"
+ description="This plugin facilitates communication with Red
Hat Network."
+ lazyLoad="false"
+ downloadMode="filesystem"
+
apiClass="org.rhq.enterprise.server.plugins.rhnhosted.RHNProvider">
+
+ <configuration>
+ <c:simple-property
+ name="location"
+ type="string"
+ required="true"
+
default="http://satellite.rhn.redhat.com/"
+ description="RHN Hosted server url for connection."/>
+
+ <c:simple-property
+ name="certificate"
+ type="longString"
+ required="true"
+ description="RHQ subscription Certificate for activation
."/>
+
+ <!--<c:group name="repos" displayName="repo list">
+ <c:simple-property name="repos" type="string"
default="rhn-tools-rhel-i386-server-5"/>
+ </c:group>-->
+
+ <c:simple-property name="SyncableChannels"
required="true" default="rhel-i386-server-vt-5"
+ description="list of syncable channels.">
+ <c:property-options>
+ <c:option name="rhel-i386-server-5"
value="rhel-i386-server-5"/>
+ <c:option name="rhn-tools-rhel-i386-server-5"
value="rhn-tools-rhel-i386-server-5"/>
+ <c:option name="rhel-i386-server-vt-5"
value="rhel-i386-server-vt-5"/>
+ <c:option name="rhel-x86_64-server-5"
value="rhel-x86_64-server-5"/>
+ <c:option name="rhn-tools-rhel-x86_64-server-5"
value="rhn-tools-rhel-x86_64-server-5"/>
+ <c:option name="rhel-x86_64-server-vt-5"
value="rhel-x86_64-server-vt-5"/>
+ </c:property-options>
+ </c:simple-property>
+
+
+ </configuration>
+
+ </contentSourceType>
+
+</plugin>
diff --git
a/modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin.xml
b/modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin.xml
new file mode 100644
index 0000000..97aaf7c
--- /dev/null
+++
b/modules/enterprise/server/plugins/url/src/main/resources/META-INF/rhq-serverplugin.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<content-plugin name="UrlContentSourcePlugin"
+ version="1.0"
+ apiVersion="2.0"
+ xmlns="urn:xmlns:rhq-serverplugin.content"
+ xmlns:c="urn:xmlns:server:rhq-configuration">
+
+ <contentSourceType name="UrlSource"
+ displayName="Remote URL Content Source"
+ description="This content source retrieves packages from a
remote system identified by a URL."
+ lazyLoad="true"
+ downloadMode="database"
+
apiClass="org.rhq.enterprise.server.plugins.url.UrlProvider">
+
+ <configuration>
+ <c:simple-property name="rootUrl" type="string"
required="true" description="The URL that contains all content that is to
be served by this content source."/>
+ <c:simple-property name="indexFile" type="string"
required="true" default="content-index.txt" description="The
index file that defines all the content that can be found on the remote server. If this is
not a full URL, it is assumed to be relative to the root URL."/>
+
+ <c:list-property name="packageTypes" required="true"
min="0"
+ description="Defines the different package types
associated with specific filename filters. These are used only if the index file does not
provide the package type information.">
+ <c:map-property name="packageType">
+ <c:simple-property name="filenameFilter"
required="true" summary="true" default=".*"
description="A regular expression that identifies a file of this package type (e.g.
'.*\.jar', '.*/i686/.*\.rpm$')"/>
+ <c:simple-property name="packageTypeName"
required="true" summary="true" description="The name that
identifies the kind of package this type represents (e.g. 'ear',
'rpm')"/>
+ <c:simple-property name="architectureName"
required="true" summary="true" default="noarch"
description="The specific hardware architecture this type of package can be deployed
on. If there is no specific architecture required, use 'noarch'. (e.g.
'i686', 'amd64')"/>
+ <c:simple-property name="resourceTypeName"
required="true" summary="true" description="The name of the
resource type on which this package can be deployed. This is the resource type name as
defined in the agent plugin. (e.g. 'Linux', 'JBossAS Server')"/>
+ <c:simple-property name="resourceTypePluginName"
required="true" summary="true" description="The name of the
plugin that defined the resource type. (e.g. 'Platform',
'JBossAS')"/>
+ </c:map-property>
+ </c:list-property>
+ </configuration>
+
+ </contentSourceType>
+
+ <contentSourceType name="HttpSource"
+ displayName="HTTP Content Source"
+ description="This content source retrieves packages from a
remote HTTP server, possibly via a proxy."
+ lazyLoad="true"
+ downloadMode="database"
+
apiClass="org.rhq.enterprise.server.plugins.url.HttpProvider">
+
+ <configuration>
+ <c:simple-property name="rootUrl" type="string"
required="true" description="The HTTP URL that contains all content that is
to be served by this content source."/>
+ <c:simple-property name="indexFile" type="string"
required="true" default="content-index.txt" description="The
index file that defines all the content that can be found on the remote server. If this is
not a full URL, it is assumed to be relative to the root URL."/>
+
+ <c:list-property name="packageTypes" required="true"
min="0"
+ description="Defines the different package types
associated with specific filename filters. These are used only if the index file does not
provide the package type information.">
+ <c:map-property name="packageType">
+ <c:simple-property name="filenameFilter"
required="true" summary="true" default=".*"
description="A regular expression that identifies a file of this package type (e.g.
'.*\.jar', '.*/i686/.*\.rpm$')"/>
+ <c:simple-property name="packageTypeName"
required="true" summary="true" description="The name that
identifies the kind of package this type represents (e.g. 'ear',
'rpm')"/>
+ <c:simple-property name="architectureName"
required="true" summary="true" default="noarch"
description="The specific hardware architecture this type of package can be deployed
on. If there is no specific architecture required, use 'noarch'. (e.g.
'i686', 'amd64')"/>
+ <c:simple-property name="resourceTypeName"
required="true" summary="true" description="The name of the
resource type on which this package can be deployed. This is the resource type name as
defined in the agent plugin. (e.g. 'Linux', 'JBossAS Server')"/>
+ <c:simple-property name="resourceTypePluginName"
required="true" summary="true" description="The name of the
plugin that defined the resource type. (e.g. 'Platform',
'JBossAS')"/>
+ </c:map-property>
+ </c:list-property>
+
+ <c:group name="security" displayName="Security
Settings">
+ <c:simple-property name="username"
displayName="Username" type="string" required="false"
+ description="Username used to log into the HTTP
server"/>
+ <c:simple-property name="password"
displayName="Password" type="password" required="false"
+ description="Password used to log into the HTTP
server"/>
+ </c:group>
+ <c:group name="proxy" displayName="Proxy Settings"
hiddenByDefault="true">
+ <c:simple-property name="proxyUrl" displayName="Proxy
URL" type="string" required="false"
+ description="Optional. URL of the proxy server to use
for this connection."/>
+ <c:simple-property name="proxyPort" displayName="Proxy
Port" type="string" required="false"
+ description="Optional. Port of the proxy server to
use for this connection."/>
+ <c:simple-property name="proxyUsername" displayName="Proxy
Username" type="string" required="false"
+ description="Optional. If the proxy requires
authentication, this is the user to log in as."/>
+ <c:simple-property name="proxyPassword" displayName="Proxy
Password" type="password" required="false"
+ description="Optional. If the proxy requires
authentitcation, this is the password for the user."/>
+ </c:group>
+ </configuration>
+
+ </contentSourceType>
+
+</content-plugin>
\ No newline at end of file
diff --git
a/modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin.xml
b/modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin.xml
new file mode 100644
index 0000000..2031a13
--- /dev/null
+++
b/modules/enterprise/server/plugins/yum/src/main/resources/META-INF/rhq-serverplugin.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<content-plugin name="YumContentSourcePlugin"
+ version="1.0"
+ apiVersion="2.0"
+ xmlns="urn:xmlns:rhq-serverplugin.content"
+ xmlns:c="urn:xmlns:server:rhq-configuration">
+
+ <contentSourceType name="YumSource"
+ displayName="Yum Repository Content Source"
+ description="This content source retrieves packages from a
local or remote Yum repository."
+ lazyLoad="true"
+ downloadMode="filesystem"
+
apiClass="org.rhq.enterprise.server.plugins.yum.RepoProvider">
+
+ <configuration>
+ <c:simple-property
+ name="location"
+ type="string"
+ required="true"
+ description="The URL or path to the Yum repository" />
+ </configuration>
+ </contentSourceType>
+
+</content-plugin>
\ No newline at end of file
diff --git a/modules/enterprise/server/pom.xml b/modules/enterprise/server/pom.xml
index 60f27c8..de38720 100644
--- a/modules/enterprise/server/pom.xml
+++ b/modules/enterprise/server/pom.xml
@@ -32,6 +32,7 @@
<activeByDefault>true</activeByDefault>
</activation>
<modules>
+ <module>xml-schemas</module>
<module>jar</module>
<module>sars</module>
<module>plugins</module>
diff --git a/modules/enterprise/server/xml-schemas/pom.xml
b/modules/enterprise/server/xml-schemas/pom.xml
new file mode 100644
index 0000000..e4e2df4
--- /dev/null
+++ b/modules/enterprise/server/xml-schemas/pom.xml
@@ -0,0 +1,161 @@
+<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-parent</artifactId>
+ <version>1.4.0-SNAPSHOT</version>
+ </parent>
+
+ <groupId>org.rhq</groupId>
+ <artifactId>rhq-enterprise-server-xml-schemas</artifactId>
+ <packaging>jar</packaging>
+
+ <name>RHQ Server XML Schemas</name>
+ <description>Server side XML schemas and JAXB APIs used mailing to support the
RHQ Server plugin container</description>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>${rhq.groupId}</groupId>
+ <artifactId>rhq-core-domain</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>${rhq.groupId}</groupId>
+ <artifactId>rhq-core-client-api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.xml.bind</groupId>
+ <artifactId>jaxb-api</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
section. -->
+ </dependency>
+
+ <dependency>
+ <groupId>com.sun.xml.bind</groupId>
+ <artifactId>jaxb-impl</artifactId>
+ <!-- NOTE: The version is defined in the root POM's dependencyManagement
section. -->
+ <!--<scope>test</scope> not sure about this -->
+ </dependency>
+
+ <!-- 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>jboss.jboss-embeddable-ejb3</groupId>
+ <artifactId>hibernate-all</artifactId>
+ <version>1.0.0.Alpha9</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.sun.tools.xjc.maven2</groupId>
+ <artifactId>maven-jaxb-plugin</artifactId>
+ <version>1.1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+
<generateDirectory>${basedir}/target/generated-sources/xjc</generateDirectory>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>java.net</id>
+ <
name>java.net Maven Repository</name>
+ <
url>http://download.java.net/maven/1/</url>
+ <layout>legacy</layout>
+ </pluginRepository>
+ </pluginRepositories>
+
+ <repositories>
+ <repository>
+ <id>java.net</id>
+ <
name>java.net Maven Repository</name>
+ <
url>http://download.java.net/maven/1/</url>
+ <layout>legacy</layout>
+ </repository>
+ </repositories>
+
+ <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}/lib</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>
+
+ </executions>
+ </plugin>
+
+ </plugins>
+ </build>
+ </profile>
+
+ </profiles>
+
+</project>
diff --git
a/modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtil.java
b/modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtil.java
new file mode 100644
index 0000000..ede3f42
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtil.java
@@ -0,0 +1,266 @@
+/*
+ * 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, 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.enterprise.server.xmlschema;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.ValidationEvent;
+import javax.xml.bind.util.ValidationEventCollector;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.maven.artifact.versioning.ComparableVersion;
+
+import org.rhq.core.domain.plugin.Plugin;
+import
org.rhq.enterprise.server.xmlschema.generated.serverplugin.ServerPluginDescriptor;
+
+/**
+ * Utilities for server-side plugin descriptors.
+ *
+ * @author John Mazzitelli
+ */
+public abstract class ServerPluginDescriptorUtil {
+ private static final Log LOG = LogFactory.getLog(ServerPluginDescriptorUtil.class);
+
+ private static final String PLUGIN_DESCRIPTOR_PATH =
"META-INF/rhq-serverplugin.xml";
+ private static final String PLUGIN_SCHEMA_PATH = "rhq-serverplugin.xsd";
+
+ /**
+ * Determines which of the two plugins is obsolete - in other words, this determines
which
+ * plugin is older. Each plugin must have the same logical name, but
+ * one of which will be determined to be obsolete and should not be deployed.
+ * If they have the same MD5, they are identical, so <code>null</code>
will be returned.
+ * Otherwise, the versions are compared and the one with the oldest version is
obsolete.
+ * If they have the same versions, the one with the oldest timestamp is obsolete.
+ * If they have the same timestamp too, we have no other way to determine
obsolescence so plugin1
+ * will be picked arbitrarily and a message will be logged when this occurs.
+ *
+ * @param plugin1
+ * @param plugin2
+ * @return a reference to the obsolete plugin (plugin1 or plugin2 reference will be
returned)
+ * <code>null</code> is returned if they are the same (i.e. they
have the same MD5)
+ * @throws IllegalArgumentException if the two plugins have different logical names
+ */
+ public static Plugin determineObsoletePlugin(Plugin plugin1, Plugin plugin2) {
+ if (!plugin1.getName().equals(plugin2.getName())) {
+ throw new IllegalArgumentException("The two plugins don't have the
same name:" + plugin1 + ":" + plugin2);
+ }
+
+ if (plugin1.getMd5().equals(plugin2.getMd5())) {
+ return null;
+ } else {
+ String version1Str = plugin1.getVersion();
+ String version2Str = plugin2.getVersion();
+ ComparableVersion plugin1Version = new ComparableVersion((version1Str !=
null) ? version1Str : "0");
+ ComparableVersion plugin2Version = new ComparableVersion((version2Str !=
null) ? version2Str : "0");
+ if (plugin1Version.equals(plugin2Version)) {
+ if (plugin1.getMtime() == plugin2.getMtime()) {
+ LOG.info("Plugins [" + plugin1 + ", " + plugin2
+ + "] are the same logical plugin but have different content.
The plugin [" + plugin1
+ + "] will be considered obsolete.");
+ return plugin1;
+ } else if (plugin1.getMtime() < plugin2.getMtime()) {
+ return plugin1;
+ } else {
+ return plugin2;
+ }
+ } else if (plugin1Version.compareTo(plugin2Version) < 0) {
+ return plugin1;
+ } else {
+ return plugin2;
+ }
+ }
+ }
+
+ /**
+ * Returns the version for the plugin represented by the given descriptor/file.
+ * If the descriptor defines a version, that is considered the version of the
plugin.
+ * However, if the plugin descriptor does not define a version, the plugin jar's
manifest
+ * is searched for an implementation version string and if one is found that is the
version
+ * of the plugin. If the manifest entry is also not found, the plugin does not have a
version
+ * associated with it, which causes this method to throw an exception.
+ *
+ * @param pluginFile the plugin jar
+ * @param descriptor the plugin descriptor as found in the plugin jar (if
<code>null</code>,
+ * the plugin file will be read and the descriptor parsed from it)
+ * @return the version of the plugin
+ * @throws Exception if the plugin is invalid, there is no version for the plugin or
the version string is invalid
+ */
+ public static ComparableVersion getPluginVersion(File pluginFile,
ServerPluginDescriptor descriptor)
+ throws Exception {
+
+ if (descriptor == null) {
+ descriptor = loadPluginDescriptorFromUrl(pluginFile.toURI().toURL());
+ }
+
+ String version = descriptor.getValue().getVersion();
+ if (version == null) {
+ Manifest manifest = getManifest(pluginFile);
+ if (manifest != null) {
+ version =
manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
+ }
+ }
+
+ if (version == null) {
+ throw new Exception("No version is defined for plugin jar [" +
pluginFile
+ + "]. A version must be defined either via the MANIFEST.MF [" +
Attributes.Name.IMPLEMENTATION_VERSION
+ + "] attribute or via the plugin descriptor 'version'
attribute.");
+ }
+
+ try {
+ return new ComparableVersion(version);
+ } catch (RuntimeException e) {
+ throw new Exception("Version [" + version + "] for [" +
pluginFile + "] did not parse", e);
+ }
+ }
+
+ /**
+ * Obtains the manifest of the plugin file represented by the given deployment info.
+ * Use this method rather than calling deploymentInfo.getManifest()
+ * (workaround for
https://jira.jboss.org/jira/browse/JBAS-6266).
+ *
+ * @param pluginFile the plugin file
+ * @return the deployed plugin's manifest
+ */
+ private static Manifest getManifest(File pluginFile) {
+ try {
+ JarFile jarFile = new JarFile(pluginFile);
+ try {
+ Manifest manifest = jarFile.getManifest();
+ return manifest;
+ } finally {
+ jarFile.close();
+ }
+ } catch (Exception ignored) {
+ return null; // this is OK, it just means we do not have a manifest
+ }
+ }
+
+ /**
+ * Loads a plugin descriptor from the given plugin jar and returns it.
+ *
+ * This is a static method to provide a convienence method for others to be able to
use.
+ *
+ * @param pluginJarFileUrl URL to a plugin jar file
+ * @return the plugin descriptor found in the given plugin jar file
+ * @throws Exception if failed to find or parse a descriptor file in the plugin jar
+ */
+ public static ServerPluginDescriptor loadPluginDescriptorFromUrl(URL
pluginJarFileUrl) throws Exception {
+
+ final Log logger = LogFactory.getLog(ServerPluginDescriptorUtil.class);
+
+ if (pluginJarFileUrl == null) {
+ throw new Exception("A valid plugin JAR URL must be supplied.");
+ }
+ logger.debug("Loading plugin descriptor from plugin jar at [" +
pluginJarFileUrl + "]...");
+
+ testPluginJarIsReadable(pluginJarFileUrl);
+
+ JAXBContext jaxbContext;
+ try {
+ jaxbContext = JAXBContext.newInstance(XmlSchemaPackages.SERVERPLUGIN);
+ } catch (Exception e) {
+ throw new Exception("Failed to create JAXB Context.", e);
+ }
+
+ JarInputStream jis = null;
+ JarEntry descriptorEntry = null;
+
+ try {
+ jis = new JarInputStream(pluginJarFileUrl.openStream());
+ JarEntry nextEntry = jis.getNextJarEntry();
+ while (nextEntry != null && descriptorEntry == null) {
+ if (PLUGIN_DESCRIPTOR_PATH.equals(nextEntry.getName())) {
+ descriptorEntry = nextEntry;
+ } else {
+ jis.closeEntry();
+ nextEntry = jis.getNextJarEntry();
+ }
+ }
+
+ if (descriptorEntry == null) {
+ throw new Exception("The plugin descriptor does not exist");
+ }
+
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+
+ // Enable schema validation
+ URL schemaURL =
ServerPluginDescriptorUtil.class.getClassLoader().getResource(PLUGIN_SCHEMA_PATH);
+ Schema pluginSchema =
SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaURL);
+ unmarshaller.setSchema(pluginSchema);
+
+ ValidationEventCollector vec = new ValidationEventCollector();
+ unmarshaller.setEventHandler(vec);
+
+ ServerPluginDescriptor pluginDescriptor = (ServerPluginDescriptor)
unmarshaller.unmarshal(jis);
+
+ for (ValidationEvent event : vec.getEvents()) {
+ logger.debug("Plugin [" + pluginDescriptor.getName() + "]
descriptor messages {Severity: "
+ + event.getSeverity() + ", Message: " + event.getMessage()
+ ", Exception: "
+ + event.getLinkedException() + "}");
+ }
+
+ return pluginDescriptor;
+ } catch (Exception e) {
+ throw new Exception("Could not successfully parse the plugin descriptor
[" + PLUGIN_DESCRIPTOR_PATH
+ + "] found in plugin jar at [" + pluginJarFileUrl +
"]", e);
+ } finally {
+ if (jis != null) {
+ try {
+ jis.close();
+ } catch (Exception e) {
+ logger.warn("Cannot close jar stream [" + pluginJarFileUrl
+ "]. Cause: " + e);
+ }
+ }
+ }
+ }
+
+ private static void testPluginJarIsReadable(URL pluginJarFileUrl) throws Exception {
+ InputStream inputStream = null;
+ try {
+ inputStream = pluginJarFileUrl.openStream();
+ } catch (IOException e) {
+ throw new Exception("Unable to open plugin jar at [" +
pluginJarFileUrl + "] for reading.");
+ } finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+ }
+}
diff --git
a/modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/XmlSchemaPackages.java
b/modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/XmlSchemaPackages.java
new file mode 100644
index 0000000..e4911d8
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/java/org/rhq/enterprise/server/xmlschema/XmlSchemaPackages.java
@@ -0,0 +1,37 @@
+/*
+ * 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, 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.enterprise.server.xmlschema;
+
+/**
+ * Defines the JAXB generated package names for the different server-side XML schemas.
+ *
+ * @author John Mazzitelli
+ */
+public interface XmlSchemaPackages {
+ String SERVERPLUGIN =
"org.rhq.enterprise.server.xmlschema.generated.serverplugin";
+ String SERVERPLUGIN_GENERIC =
"org.rhq.enterprise.server.xmlschema.generated.serverplugin.generic";
+ String SERVERPLUGIN_CONTENT =
"org.rhq.enterprise.server.xmlschema.generated.serverplugin.content";
+ String SERVERPLUGIN_PERSPECTIVE =
"org.rhq.enterprise.server.xmlschema.generated.serverplugin.perspective";
+ String CONFIGURATION =
"org.rhq.enterprise.server.xmlschema.generated.configuration";
+ String CONTENTSOURCE_PACKAGEDETAILS =
"org.rhq.enterprise.server.xmlschema.generated.contentsource.packagedetails";
+}
\ No newline at end of file
diff --git
a/modules/enterprise/server/xml-schemas/src/main/resources/rhq-contentsource-packagedetails.xsd
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-contentsource-packagedetails.xsd
new file mode 100644
index 0000000..c944020
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-contentsource-packagedetails.xsd
@@ -0,0 +1,381 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
+<xs:schema
+
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:rhq="urn:xmlns:rhq-contentsource-packagedetails"
+ targetNamespace="urn:xmlns:rhq-contentsource-packagedetails"
+ elementFormDefault="qualified"
+ jaxb:version="2.0"
+
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ blockDefault="">
+
+ <xs:annotation>
+ <xs:documentation>
+ Schema for content source package details metadata. This schema will provide the
structure
+ that XML content sources (e.g. HttpSource) will use for their XML index files.
This is
+ how such content sources can advertise what content they have available.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:schemaBindings>
+ <jaxb:package
name="org.rhq.enterprise.server.xmlschema.generated.contentsource.packagedetails"
/>
+ </jaxb:schemaBindings>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:complexType name="packageDetailsKeyType">
+ <xs:annotation>
+ <xs:documentation>
+ The key to details of a package that a content source
+ provides. This key is used when referring to a package
+ version found in the remote content source repository.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="name">
+ <xs:annotation>
+ <xs:documentation>
+ The name of the package.This name, combined with the
+ version, identifies an individual package within its
+ package type family.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="version">
+ <xs:annotation>
+ <xs:documentation>
+ The version of the package. The format of this
+ attribute will vary based on the package and the
+ package type.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="package-type-name">
+ <xs:annotation>
+ <xs:documentation>
+ Fully qualified name of the package type which defines
+ the family of packages that this package belongs to
+ (e.g. "rpm"). This is defined in the product plugin where
+ the package type is defined.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="architecture-name">
+ <xs:annotation>
+ <xs:documentation>
+ The architecture on which this package can be
+ deployed. If there is no specific architecture that is
+ associated with this package, then "noarch" should be
+ used.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="resource-type-name">
+ <xs:annotation>
+ <xs:documentation>
+ The name of the resource type for which this package
+ is applicable. In other words, this is the resource
+ type on which this package can be deployed. Because a
+ resource type name itself is not unique, this type
+ name must be paired with the product plugin name that defines
+ the resource type.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="resource-type-plugin">
+ <xs:annotation>
+ <xs:documentation>
+ The name of the product plugin that defined the resource type
+ for which this package is applicable.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="packageDetailsType">
+ <xs:sequence>
+ <xs:element name="package-details-key"
type="rhq:packageDetailsKeyType">
+ </xs:element>
+ <xs:element name="resource-versions"
type="rhq:resourceVersionsType" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The versions of the resource type which this package
+ is applicable. In other words, this package is
+ deployable only on resources that match these version
+ strings.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="display-name" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The human-readable name of the package suitable to be
+ displayed on a user interface.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="display-version" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The human-readable version of the package suitable to
+ be displayed on a user interface.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="short-description" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ Just a few words that briefly describe this package.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="long-description" type="xs:string"
minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The details that describe this package.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="classification" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ Provides additional classification metadata to
+ describe the package. The possible values for this
+ attribute will vary based on package type. For
+ instance, two packages of the same package type may be
+ differentiated as a "bug fix" or a "security
update".
+ Another way to use this would be to group packages
+ together, such as "System Patches" or
"Applications".
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="file-name" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The name of the file that this package should be
+ stored as. This typically is a combination of the
+ package name and version, but it is not required to be
+ so.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="file-size" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The size, in bytes, of the package content.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:long">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="file-created-date" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The date and time when the original content was
+ created. This value is specified in epoch milliseconds.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:long">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="md5" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The package content's md5 hashcode.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="sha256" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The package content's sha256 hashcode.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="license-name" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The name of the license that governs the usage of the
+ package.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="license-version" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ The version of the license that governs the usage of
+ the package.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element name="metadata" type="xs:string"
minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ Generic metadata that is used to extend the metadata
+ for a particular package. This metadata is custom for
+ a particular package type and can include things such
+ as install instructions or errata information.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="extra-properties"
type="rhq:configurationType" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ If the package type defines an extra set of custom
+ properties, these are this package's property values.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element name="location" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ Defines the location where this package's content can
+ be found on the content source remote repository.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="resourceVersionsType">
+ <xs:sequence>
+ <xs:element name="resource-version" minOccurs="1"
maxOccurs="unbounded">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"></xs:whiteSpace>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="packageType">
+ <xs:sequence>
+ <xs:element name="package" type="rhq:packageDetailsType"
minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:element name="packages"
type="rhq:packageType"></xs:element>
+
+ <!-- configuration property values schema -->
+
+ <xs:complexType name="configurationType">
+ <xs:annotation>
+ <xs:documentation>Describes all configurable
elements.</xs:documentation>
+ </xs:annotation>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="simple-property"
type="rhq:simplePropertyType" />
+ <xs:element name="list-property"
type="rhq:listPropertyType" />
+ <xs:element name="map-property"
type="rhq:mapPropertyType" />
+ </xs:choice>
+ </xs:complexType>
+
+ <xs:complexType name="simplePropertyType">
+ <xs:simpleContent>
+ <xs:extension base="xs:string">
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:extension>
+ </xs:simpleContent>
+ </xs:complexType>
+
+ <xs:complexType name="listPropertyType">
+ <xs:complexContent>
+ <xs:extension base="rhq:configurationType">
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:complexType name="mapPropertyType">
+ <xs:complexContent>
+ <xs:extension base="rhq:configurationType">
+ <xs:attribute name="name" type="xs:string"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+</xs:schema>
diff --git
a/modules/enterprise/server/xml-schemas/src/main/resources/rhq-server-configuration.xsd
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-server-configuration.xsd
new file mode 100644
index 0000000..4301d7c
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-server-configuration.xsd
@@ -0,0 +1,517 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
+
+<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:config="urn:xmlns:server:rhq-configuration"
+ targetNamespace="urn:xmlns:server:rhq-configuration"
+ elementFormDefault="qualified"
+ jaxb:version="2.0"
+
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
blockDefault="">
+
+ <xs:annotation>
+ <xs:documentation>Schema for the definition of generic configuration data.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:schemaBindings>
+ <jaxb:package
name="org.rhq.enterprise.server.xmlschema.generated.configuration"/>
+ </jaxb:schemaBindings>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:complexType name="configuration">
+ <xs:annotation>
+ <xs:appinfo>
+ <jaxb:class name="ConfigurationDescriptor"/>
+ </xs:appinfo>
+ <xs:documentation>Describes all configurable elements of a
resource.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="notes" type="xs:string"
minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>General notes on the overall
configuration.</xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="config:configuration-property"
minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="group" type="config:propertyGroup"
minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="template"
type="config:configurationTemplate" minOccurs="0"
maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+
+ <xs:complexType name="configurationTemplate">
+ <xs:annotation>
+ <xs:appinfo>
+ <jaxb:class name="ConfigurationTemplateDescriptor"/>
+ </xs:appinfo>
+ <xs:documentation>Describes a template of configuration
values.</xs:documentation>
+ </xs:annotation>
+
+ <xs:complexContent>
+ <xs:extension base="config:configuration">
+ <xs:attribute name="name" type="xs:string"
use="required"/>
+ <xs:attribute name="description" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"
fixed="true"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+
+ <xs:complexType name="propertyGroup">
+ <xs:sequence>
+ <xs:element name="description" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>Description of types of properties contained in
this group.</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="250"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+ <xs:element ref="config:configuration-property"
maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" use="required">
+ <xs:annotation>
+ <xs:documentation>Name of the group as it is internally known to the
plugin</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="displayName" use="optional">
+ <xs:annotation>
+ <xs:documentation>Descriptive name of the
group.</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="hiddenByDefault" type="xs:boolean"
default="false">
+ <xs:annotation>
+ <xs:documentation>If true, this group would not be shown to the user by
default, but require an extra click
+ to see (e.g. to expand a collapsible panel).
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:element name="configuration-property" abstract="true"
type="config:configurationProperty"/>
+ <xs:complexType name="configurationProperty">
+ <xs:annotation>
+ <xs:documentation>Base class for all configuration
properties.</xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+
+ <xs:element name="description" minOccurs="0"
maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>a more detailed description of the property's
purpose</xs:documentation>
+ <xs:appinfo>
+ <jaxb:property name="longDescription"/>
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="4000"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+
+ </xs:sequence>
+
+ <xs:attribute name="name" use="required">
+ <xs:annotation>
+ <xs:documentation>the name of the property as it is internally known to
the plugin</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="displayName" use="optional">
+ <xs:annotation>
+ <xs:documentation>Descriptive name of the property. If not provided, a
camel case property will be English
+ translated. (e.g myName -> My Name)
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="100"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="description" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="1000"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="required" type="xs:boolean"
use="optional" default="true">
+ <xs:annotation>
+ <xs:documentation>If true, the property must be set for the
configuration to be considered valid.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="readOnly" type="xs:boolean"
use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>If true, the property can only be read via JON, but
not set.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="summary" type="xs:boolean"
use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>If true, this property is marked as part of the
summary information for the parent
+ object.</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ </xs:complexType>
+
+ <xs:element name="simple-property" type="config:simpleProperty"
substitutionGroup="config:configuration-property"/>
+ <xs:complexType name="simpleProperty">
+ <xs:complexContent>
+ <xs:extension base="config:configurationProperty">
+
+ <xs:sequence>
+
+ <xs:element name="property-options"
type="config:propertyOptions" minOccurs="0"
maxOccurs="1"/>
+
+ <xs:element name="constraint"
type="config:constraintType" minOccurs="0"
maxOccurs="unbounded"/>
+
+ <xs:element name="defaultValueDescription"
minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>a description of the property's default
value (if it has one)</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse"/>
+ <xs:minLength value="1"/>
+ <xs:maxLength value="1000"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:element>
+
+ </xs:sequence>
+
+ <xs:attribute name="type" type="config:propertyType"
default="string" use="optional">
+ <xs:annotation>
+ <xs:documentation>data type of the property's value (default
type is "string")</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="defaultValue" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ DEPRECATED - THIS ATTRIBUTE WILL GO AWAY IN A LATER VERSION OF RHQ!
+ The property's default value; this element should be defined for
properties whose
+ required attribute is "false" (i.e. for optional
properties); conversely, this element should not
+ be defined for properties whose required attribute is
"true" (i.e. for required properties); not
+ to be confused with the 'default' attribute, which specifies
the initial value for a property
+ when a new configuration is created</xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- NOTE: No collapse restriction is defined, since the
property's default value could be a string containing significant whitespace. -->
+ <!-- NOTE: No minLength restriction is defined, since the
property's default value could be an empty string. -->
+ <xs:maxLength value="2000"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <!-- TODO: Rename this attribute to "initialValue", so it will
not be confused with the "defaultValue"
+ attribute. (ips, 07/20/07) -->
+ <xs:attribute name="default" use="optional">
+ <xs:annotation>
+ <xs:documentation>the initial value for this property when a new
configuration is created; not to be
+ confused with the 'defaultValue' attribute, which specifies
the default value for an optional
+ property that is not defined in a
configuration</xs:documentation>
+ <xs:appinfo>
+ <jaxb:property name="initialValue"/>
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <!-- NOTE: No collapse restriction is defined, since the
property's default initial value could be a string containing significant whitespace.
-->
+ <!-- NOTE: No minLength restriction is defined, since the
property's default initial value could be an empty string. -->
+ <xs:maxLength value="2000"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+
+ <xs:attribute name="units"
type="config:measurementUnitsDescriptor" use="optional">
+ <xs:annotation>
+ <xs:documentation>units the property value is measured in (if
applicable) - typically should only be
+ set for properties with type="integer" or
type="float"</xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ <xs:attribute name="activationPolicy"
default="immediate" type="config:activationPolicy"
use="optional">
+ <xs:annotation>
+ <xs:documentation>conditions under which a change to this
property will become effective
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:element name="map-property" type="config:mapProperty"
substitutionGroup="config:configuration-property"/>
+ <xs:complexType name="mapProperty">
+ <xs:annotation>
+ <xs:documentation>The definition of a child map of
properties.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="config:configurationProperty">
+ <xs:sequence>
+ <xs:element ref="config:configuration-property"
minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>The map of child property definitions. If
not supplied, the map can contain
+ artitrary child properties.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:simpleType name="maxCount">
+ <xs:annotation>
+ <xs:documentation>
+ for max counts of lists
+ </xs:documentation>
+ </xs:annotation>
+ <xs:union memberTypes="xs:nonNegativeInteger">
+ <xs:simpleType>
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="unbounded"/>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:union>
+ </xs:simpleType>
+
+ <xs:element name="list-property" type="config:listProperty"
substitutionGroup="config:configuration-property"/>
+ <xs:complexType name="listProperty">
+ <xs:annotation>
+ <xs:documentation>The definition of a child list of
properties.</xs:documentation>
+ </xs:annotation>
+ <xs:complexContent>
+ <xs:extension base="config:configurationProperty">
+ <xs:sequence>
+ <xs:element ref="config:configuration-property"
minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>The type of child property. If not supplied
properties can be arbitrary.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="min" type="xs:nonNegativeInteger"
default="0"/>
+ <xs:attribute name="max" type="config:maxCount"
default="unbounded"/>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+
+ <xs:simpleType name="activationPolicy">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="immediate"/>
+ <xs:enumeration value="restart"/>
+ <xs:enumeration value="shutdown"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <!-- == Property Details ======================= -->
+
+ <xs:simpleType name="propertyType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="string"/>
+ <xs:enumeration value="longString"/>
+ <xs:enumeration value="password"/>
+ <xs:enumeration value="boolean"/>
+ <xs:enumeration value="integer"/>
+ <xs:enumeration value="long"/>
+ <xs:enumeration value="float"/>
+ <xs:enumeration value="double"/>
+ <xs:enumeration value="file"/>
+ <xs:enumeration value="directory"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="propertyOptions">
+ <xs:annotation>
+ <xs:documentation>
+ Contains the elements of an enumerated property.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="option" type="config:option"
minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="allowCustomValue" type="xs:boolean"
use="optional" default="false">
+ <xs:annotation>
+ <xs:documentation>
+ If false, indicates that the value of the property must
+ be one of the enumerated option values. If true, the user
+ is free to enter any value, which does not necessarily
+ have to be one of the enumerated option values.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="option">
+ <xs:annotation>
+ <xs:documentation>Used to describe items available in a property with a
list type.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="name" use="optional">
+ <xs:annotation>
+ <xs:documentation>Display name to be used for the item. Defaults to the
value if not supplied.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string"/>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="value" use="required">
+ <xs:annotation>
+ <xs:documentation>Value to use as the property value if this item is
selected.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string"/>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="default" default="false"
use="optional">
+ <xs:annotation>
+ <xs:documentation>Indicates this item is the default item in the list.
Default value is false.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:boolean"/>
+ </xs:simpleType>
+ </xs:attribute>
+ </xs:complexType>
+
+ <!-- == Property Constraints ================= -->
+
+ <xs:complexType name="constraintType">
+ <xs:annotation>
+ <xs:documentation>
+ A constraint on a property value. Allows you to define what a value's
+ type should be as well as additional constraints such as matching
+ a regular expression or a number falling within a range.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:choice maxOccurs="unbounded" minOccurs="1">
+ <xs:element name="integer-constraint"
type="config:integerConstraintType"/>
+ <xs:element name="float-constraint"
type="config:floatConstraintType"/>
+ <xs:element name="regex-constraint"
type="config:regexConstraintType"/>
+ </xs:choice>
+ </xs:complexType>
+
+ <xs:complexType name="integerConstraintType">
+ <xs:annotation>
+ <xs:documentation>
+ Constraint to indicate a value must be an integer. If specified, the
+ minimum and maximum values will indicate the range in which the value must
fall.
+ This range is inclusive, so a value that is equal to either the minimum or
the
+ maximum will be considered valid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="minimum" type="xs:integer">
+ <xs:annotation><xs:documentation>Minimum integer value (inclusive)
for the property value.</xs:documentation></xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximum" type="xs:integer">
+ <xs:annotation><xs:documentation>Maximum integer value (inclusive)
for the property value.</xs:documentation></xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="floatConstraintType">
+ <xs:annotation>
+ <xs:documentation>
+ Constraint to indicate a value must be an decimal. If specified, the
+ minimum and maximum values will indicate the range in which the value must
fall.
+ This range is inclusive, so a value that is equal to either the minimum or
the
+ maximum will be considered valid.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="minimum" type="xs:float">
+ <xs:annotation><xs:documentation>Minimum decimal value (inclusive)
for the property value.</xs:documentation></xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="maximum" type="xs:float">
+ <xs:annotation><xs:documentation>Maximum decimal value (inclusive)
for the property value.</xs:documentation></xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:complexType name="regexConstraintType">
+ <xs:annotation>
+ <xs:documentation>
+ Constraint to indicate a value must match the specified
+ regular expression.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:attribute name="expression" type="xs:string"
use="required">
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:simpleType name="measurementUnitsDescriptor">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="none"/>
+ <xs:enumeration value="percentage">
+ <xs:annotation>
+ <xs:documentation>
+ Values expected in decimal [0.00,1.00]
+ </xs:documentation>
+ </xs:annotation>
+ </xs:enumeration>
+ <xs:enumeration value="bits"/>
+ <xs:enumeration value="kilobits" />
+ <xs:enumeration value="megabits" />
+ <xs:enumeration value="gigabits" />
+ <xs:enumeration value="terabits" />
+ <xs:enumeration value="petabits" />
+ <xs:enumeration value="bytes"/>
+ <xs:enumeration value="kilobytes"/>
+ <xs:enumeration value="megabytes"/>
+ <xs:enumeration value="gigabytes"/>
+ <xs:enumeration value="terabytes"/>
+ <xs:enumeration value="epoch_milliseconds"/>
+ <xs:enumeration value="nanoseconds"/>
+ <xs:enumeration value="milliseconds"/>
+ <xs:enumeration value="seconds"/>
+ <xs:enumeration value="minutes"/>
+ <xs:enumeration value="hours"/>
+ <xs:enumeration value="days"/>
+ <xs:enumeration value="kelvin"/>
+ <xs:enumeration value="celsius"/>
+ <xs:enumeration value="fahrenheit"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+</xs:schema>
diff --git
a/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-content.xsd
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-content.xsd
new file mode 100644
index 0000000..0f3de91
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-content.xsd
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
+
+<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:config="urn:xmlns:server:rhq-configuration"
+ xmlns:serverplugin="urn:xmlns:rhq-serverplugin"
+ xmlns:content="urn:xmlns:rhq-serverplugin.content"
+ targetNamespace="urn:xmlns:rhq-serverplugin.content"
+ elementFormDefault="qualified"
+ jaxb:version="2.0"
+
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ blockDefault="">
+
+ <xs:import namespace="urn:xmlns:server:rhq-configuration"
schemaLocation="rhq-server-configuration.xsd" />
+ <xs:import namespace="urn:xmlns:rhq-serverplugin"
schemaLocation="rhq-serverplugin.xsd" />
+
+ <xs:annotation>
+ <xs:documentation>
+ Schema for server-side content source plugins. These plugins will provide
+ implementations that allow remote repositories to feed content into
+ the server's content subsystem.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:schemaBindings>
+ <jaxb:package
name="org.rhq.enterprise.server.xmlschema.generated.serverplugin.content" />
+ </jaxb:schemaBindings>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:element name="content-plugin"
substitutionGroup="serverplugin:server-plugin">
+ <xs:annotation>
+ <xs:documentation>
+ A plugin representing a set of defined server content provider
implementations.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:class name="ContentServerPluginDescriptor" />
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:complexContent>
+ <xs:extension
base="serverplugin:ServerPluginComplexType">
+ <xs:sequence>
+ <xs:element ref="content:contentSourceType"
minOccurs="1" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+ Defines a supported content source type that is able
to feed content into the server.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ </xs:extension>
+ </xs:complexContent>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="contentSourceType">
+ <xs:annotation>
+ <xs:appinfo>
+ <jaxb:class name="ContentSourceTypeDefinition" />
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="configuration"
type="config:configuration" minOccurs="0" maxOccurs="1">
+ <xs:annotation>
+ <xs:documentation>
+ Defines the configuration properties that must be set when
creating a
+ content source of this type. Typically, this will define the
properties
+ necessary for specifying how to connect to the underlying
source.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" use="required">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1" />
+ <xs:maxLength value="200" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="displayName" use="optional">
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1" />
+ <xs:maxLength value="200" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="description" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Describes this type of content source. This usually
+ provides information such as what type of remote endpoint
+ the content source uses (http or some kind of file
+ transport protocol) and the types of packages the content
+ source can serve up, if known.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1" />
+ <xs:maxLength value="500" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="lazyLoad" use="required"
type="xs:boolean">
+ <xs:annotation>
+ <xs:documentation>
+ If set to true, the content bits for all packages coming from
+ content sources of this type will, by default, only be loaded on
demand.
+ This means the package contents will only be loaded when they
are
+ asked for the very first time. If false, the default for all
content
+ sources of this type will be that they should attempt to download
all
+ packages as soon as possible. Note that this is only the
default,
+ suggested value. When creating a content source, the user will
be
+ given the chance to override this default.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="downloadMode" use="optional"
default="database">
+ <xs:annotation>
+ <xs:documentation>
+ Indicates where (and even if) package bits are
+ downloaded, when they are downloaded. If 'never', then
+ package bits are never downloaded from the content
+ source, effectively creating a pass-through directly
+ to the remote repository for every request for package
+ bits. If 'database', when package bits are downloaded,
+ they are stored in the database. If 'filesystem',
+ package bits will be stored somewhere on the
+ filesystem.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:enumeration
value="never"></xs:enumeration>
+ <xs:enumeration
value="database"></xs:enumeration>
+ <xs:enumeration
value="filesystem"></xs:enumeration>
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="syncSchedule" use="optional"
type="xs:string" default="0 0 3 * * ?">
+ <xs:annotation>
+ <xs:documentation>
+ Periodically, the content source plugin adapter will be asked to
+ synchronize with the remote content source repository. This
gives
+ the adapter a chance to see if any content has been added,
updated
+ or removed from the remote repository.
+ This attribute defines the schedule, as a cron string. The
default
+ will be set for everyday at 3:00am local time. If you never want
+ the content source to be automatically synced, set this value to
+ an empty string.
+ For documentation on the syntax of this cron string, please see:
+
http://www.opensymphony.com/quartz/wikidocs/CronTriggers%20Tutorial.html
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="apiClass"
type="serverplugin:classNameType" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ This specifies the fully qualified class name of the
+ implementation class that provides a way for the server
+ to interface with the remote content store. This API
+ class must implement the ContentProviderManager interface.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+ </xs:element>
+</xs:schema>
diff --git
a/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-generic.xsd
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-generic.xsd
new file mode 100644
index 0000000..4501263
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-generic.xsd
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
+
+<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:serverplugin="urn:xmlns:rhq-serverplugin"
+ xmlns:generic="urn:xmlns:rhq-serverplugin.generic"
+ targetNamespace="urn:xmlns:rhq-serverplugin.generic"
+ elementFormDefault="qualified"
+ jaxb:version="2.0"
+
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ blockDefault="">
+
+ <xs:import namespace="urn:xmlns:rhq-serverplugin"
schemaLocation="rhq-serverplugin.xsd" />
+
+ <xs:annotation>
+ <xs:documentation>
+ Schema for a generic server-side plugins. This type of plugin does not
+ need any additional support from the server plugin container other than
+ simple lifecycle management (for example, be told when to start and stop).
+ The plugin is otherwise standalone and can do everything it needs to do
+ without additional help from the server plugin container.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:schemaBindings>
+ <jaxb:package
name="org.rhq.enterprise.server.xmlschema.generated.serverplugin.generic" />
+ </jaxb:schemaBindings>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:element name="generic-plugin"
substitutionGroup="serverplugin:server-plugin">
+ <xs:annotation>
+ <xs:documentation>
+ Defines a generic plugin.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:class name="GenericServerPluginDescriptor" />
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+
+</xs:schema>
diff --git
a/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-perspective.xsd
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-perspective.xsd
new file mode 100644
index 0000000..b99c530
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin-perspective.xsd
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
+
+<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:perspective="urn:xmlns:rhq-serverplugin.perspective"
+ targetNamespace="urn:xmlns:rhq-serverplugin.perspective"
+ elementFormDefault="qualified"
+ jaxb:version="2.0"
+
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
blockDefault="">
+
+ <xs:import namespace="urn:xmlns:rhq-serverplugin"
schemaLocation="rhq-serverplugin.xsd" />
+
+ <xs:annotation>
+ <xs:documentation>Schema for the definition Perspective service objects
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:schemaBindings>
+ <jaxb:package
name="org.rhq.enterprise.server.xmlschema.generated.serverplugin.perspective"/>
+ </jaxb:schemaBindings>
+ </xs:appinfo>
+ </xs:annotation>
+
+
+ <xs:element name="perspective">
+ <xs:annotation>
+ <xs:documentation>
+Perspective is a collection of user interface screens and defined URL access points to
+get to high level functionality within the Perspective.
+
+ Fields:
+
+ name: Name of the Perspective.
+
+ url: Root URL of the Perspective.
+
+ description: Description of Perspective
+
+ tasks: The set of Tasks this Perspective 'owns' and shares as available for
users to
+ navigate to.
+
+ navigation: The List of NavigationItem objects associated with this Perspective.
+ NavigationItems are name/path pairs that represent high level navigation links this
+ Perspective desires to show. Examples would for an Administration Perspective:
+
+ Name , Path
+ Users , /admin/users
+ Systems , /admin/systems
+ Configuration, /admin/configuration
+
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:class name="Perspective"/>
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element ref="perspective:task" minOccurs="0"
maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+ Defines child server types that can be embedded in this server
type.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:property name="tasks" />
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+ <xs:element ref="perspective:navigationitem"
minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+ Defines child server types that can be embedded in this server
type.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:property name="navigationItems" />
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+ <xs:attribute name="name" use="required"
type="xs:string"/>
+ <xs:attribute name="path" type="xs:string"/>
+ <xs:attribute name="description"
type="xs:string"/>
+
+ </xs:complexType>
+ </xs:element>
+
+
+ <xs:element name="task">
+ <xs:annotation>
+ <xs:documentation>
+Tasks are high level UI concepts that a Perspectives are responsible for. The Task will
+provide a URL that allows the user to access the starting point for that Task.
+
+For example, common tasks in most web applications involve creation and management of
+Users of the system. A common task in managing users is the step of actually creating a
+User. In order to designate the starting point for creating a user you would create a
+Task object:
+
+Task.name = "user create"
+Task.url = "/users/create"
+Task.display = "Create a new User in the system"
+Task.urlmatches = "/users/*"
+
+Fields:
+
+The name field is a progmatically referenceable name that isn't intended to change.
Code
+will reference Tasks by name.
+
+The url field will allow UIs to build a link to the Task's starting point.
+
+The display can be used when linking to the Task to show a display value describing what
+the Task does
+
+The urlmatches is used to indicate a list of URLs that this Task should be visible to.
+This can allow GUI developers a way to specify the relationship of this Task to specific
+pages or a tree of URLs. The above example indicates that urlmatches is
"/users/*" which
+is an indication that the task is relative to all the pages in the /users tree of URLs.
+This can be used by a page rendering to show a link to the 'user create' Task if
the user
+was looking at a page with a path starting with /users/
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:class name="Task"/>
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="pathmatches" type="xs:string"
minOccurs="0" maxOccurs="unbounded">
+ <xs:annotation>
+ <xs:documentation>
+ The pathMatches is used to indicate a list of rooted paths that this
Task should be visible to.
+ This can allow GUI developers a way to specify the relationship of
this Task to specific
+ pages or a tree of URLs. The above example indicates that urlmatches
is "/users/*" which
+ is an indication that the task is relative to all the pages in the
/users tree of URLs.
+ This can be used by a page rendering to show a link to the 'user
create' Task if the user
+ was looking at a page with a path starting with /users/
+ </xs:documentation>
+ </xs:annotation>
+ </xs:element>
+ </xs:sequence>
+
+ <xs:attribute name="name" use="required"
type="xs:string"/>
+ <xs:attribute name="path" use="required"
type="xs:string"/>
+ <xs:attribute name="description" type="xs:string"/>
+ <xs:attribute name="context" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="navigationitem">
+ <xs:annotation>
+ <xs:documentation>
+NavigationItem is a class that represents named paths that a Perspective can show in a
+GUI to get to high-level areas of a Perspective's pages. An example would be:
Typical web
+applications include a Top Level navigation bar. You could represent a Perspective's
top
+nav with a set of NavigationItems
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:class name="NavigationItem"/>
+ </xs:appinfo>
+ </xs:annotation>
+ <xs:complexType>
+ <xs:attribute name="name" use="required"
type="xs:string"/>
+ <xs:attribute name="path" type="xs:string"/>
+ </xs:complexType>
+ </xs:element>
+
+</xs:schema>
diff --git a/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin.xsd
b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin.xsd
new file mode 100644
index 0000000..4f79fad
--- /dev/null
+++ b/modules/enterprise/server/xml-schemas/src/main/resources/rhq-serverplugin.xsd
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"
?>
+
+<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
+ xmlns:config="urn:xmlns:server:rhq-configuration"
+ xmlns:serverplugin="urn:xmlns:rhq-serverplugin"
+ targetNamespace="urn:xmlns:rhq-serverplugin"
+ elementFormDefault="qualified"
+ jaxb:version="2.0"
+
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
+ blockDefault="">
+
+ <xs:import namespace="urn:xmlns:server:rhq-configuration"
schemaLocation="rhq-server-configuration.xsd" />
+
+ <xs:annotation>
+ <xs:documentation>
+ Schema for all server-side plugins. All server side plugin types
+ will define their own schema that get embedded in this schema.
+ Since there are only a strictly defined number of plugin types,
+ each plugin type's schema will be explicitly included in this
+ schema, under the plugin element's choice definition.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:schemaBindings>
+ <jaxb:package
name="org.rhq.enterprise.server.xmlschema.generated.serverplugin" />
+ </jaxb:schemaBindings>
+ </xs:appinfo>
+ </xs:annotation>
+
+ <xs:element name="server-plugin"
type="serverplugin:ServerPluginComplexType" abstract="true">
+ <xs:annotation>
+ <xs:documentation>
+ Root of a server-side plugin descriptor. All server side plugins
+ will have this as their root element; however, child elements of this
+ root element will be plugin-type-specific.
+ </xs:documentation>
+ <xs:appinfo>
+ <jaxb:class name="ServerPluginDescriptor" />
+ </xs:appinfo>
+ </xs:annotation>
+ </xs:element>
+
+ <xs:complexType name="ServerPluginComplexType">
+ <xs:attribute name="name" use="required">
+ <xs:annotation>
+ <xs:documentation>
+ Name of the plugin. This should be unique across all plugins deployed
in the system.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:simpleType>
+ <xs:restriction base="xs:string">
+ <xs:minLength value="1" />
+ <xs:maxLength value="200" />
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:attribute>
+ <xs:attribute name="displayName" type="xs:string"
use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Formatted name displayed to the user. If this is omitted, the
"name" attribute will be used.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="description" type="xs:string"
use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Summary of what the plugin provides to be displayed to the user.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="package"
type="serverplugin:classNameType" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ Package in which all component classes in this plugin reside. These
component
+ classes may use classes in other packages, however non-qualified
classnames
+ are assumed to be in this package.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="pluginLifecycleListener"
type="serverplugin:classNameType" use="optional">
+ <xs:annotation>
+ <xs:documentation>
+ A class that performs global initialization and shutdown of the
plugin. If specified,
+ this class will be notified when the plugin is loaded and unloaded.
This provides a place
+ for plugin developers to allocate global resources needed by all
plugin components and
+ a place to clean up those resources.
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="version" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The version of this plugin in an OSGI compatible format. (e.g. 2.0.4
or 3.1.beta2)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ <xs:attribute name="apiVersion" type="xs:string">
+ <xs:annotation>
+ <xs:documentation>
+ The version of the server-side API this plugin requires in OSGI
compatible format. (e.g. 2.0)
+ </xs:documentation>
+ </xs:annotation>
+ </xs:attribute>
+ </xs:complexType>
+
+ <xs:simpleType name="classNameType">
+ <xs:restriction base="xs:string">
+ <xs:whiteSpace value="collapse" />
+ <xs:minLength value="1" />
+ <xs:maxLength value="500" />
+ <xs:pattern
value="[a-zA-Z_][a-zA-Z_0-9]*(.[a-zA-Z_][a-zA-Z_0-9]*)*" />
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git
a/modules/enterprise/server/xml-schemas/src/test/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtilTest.java
b/modules/enterprise/server/xml-schemas/src/test/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtilTest.java
new file mode 100644
index 0000000..69980e3
--- /dev/null
+++
b/modules/enterprise/server/xml-schemas/src/test/java/org/rhq/enterprise/server/xmlschema/ServerPluginDescriptorUtilTest.java
@@ -0,0 +1,45 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2009 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.enterprise.server.xmlschema;
+
+import java.net.URL;
+
+import org.testng.annotations.Test;
+
+import
org.rhq.enterprise.server.xmlschema.generated.serverplugin.ServerPluginDescriptor;
+
+/**
+ * Tests that we can parse server-side plugin descriptors.
+ *
+ * @author John Mazzitelli
+ */
+@Test
+public class ServerPluginDescriptorUtilTest {
+
+ public void testGenericPluginDescriptor() throws Exception {
+ URL url =
this.getClass().getClassLoader().getResource("test-serverplugin-generic.jar");
+ ServerPluginDescriptor descriptor =
ServerPluginDescriptorUtil.loadPluginDescriptorFromUrl(url);
+ assert descriptor != null;
+ return;
+ }
+}
diff --git a/modules/enterprise/server/xml-schemas/src/test/resources/log4j.xml
b/modules/enterprise/server/xml-schemas/src/test/resources/log4j.xml
new file mode 100644
index 0000000..cce501d
--- /dev/null
+++ b/modules/enterprise/server/xml-schemas/src/test/resources/log4j.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<!-- ===================================================================== -->
+<!-- -->
+<!-- Log4j Configuration -->
+<!-- -->
+<!-- ===================================================================== -->
+
+<!-- $Id: log4j.xml 8776 2008-01-23 05:13:06Z ispringer $ -->
+
+<!--
+ | For more configuration infromation and examples see the Jakarta Log4j
+ | owebsite:
http://jakarta.apache.org/log4j
+ -->
+
+<log4j:configuration
xmlns:log4j="http://jakarta.apache.org/log4j/"
debug="true">
+
+ <appender name="CONSOLE"
class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <param name="Threshold" value="WARN"/>
+
+ <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>
+
+ <appender name="FILE"
class="org.apache.log4j.RollingFileAppender">
+ <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>
+
+ <root>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="FILE"/>
+ <!--
+ -->
+ </root>
+
+</log4j:configuration>
diff --git
a/modules/enterprise/server/xml-schemas/src/test/resources/test-serverplugin-generic.jar
b/modules/enterprise/server/xml-schemas/src/test/resources/test-serverplugin-generic.jar
new file mode 100644
index 0000000..e68c9d6
Binary files /dev/null and
b/modules/enterprise/server/xml-schemas/src/test/resources/test-serverplugin-generic.jar
differ
diff --git a/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml
b/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml
index 2d457c5..58b4c6a 100644
--- a/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml
+++ b/modules/plugins/rhq-server/src/main/resources/META-INF/rhq-plugin.xml
@@ -298,31 +298,31 @@
</service>
- <service name="RHQ Server Content Source Server Plugin Subsystem"
+ <service name="RHQ Server Plugin Subsystem"
discovery="org.rhq.plugins.jmx.MBeanResourceDiscoveryComponent"
class="org.rhq.plugins.jmx.MBeanResourceComponent"
- description="Details on the content source server plugin
subsystem">
+ description="Details on the server-side plugin container
subsystem">
<runs-inside>
<parent-resource-type name="JBossAS Server"
plugin="JBossAS"/>
</runs-inside>
<plugin-configuration>
- <c:simple-property name="objectName" readOnly="true"
default="rhq.serverplugin:service=ContentSourcePluginService"/>
- <c:simple-property name="nameTemplate" default="RHQ Server
Content Source Server Plugin Subsystem"/>
- <c:simple-property name="descriptionTemplate" default="Details
on the content source server plugin subsystem"/>
+ <c:simple-property name="objectName" readOnly="true"
default="rhq.serverplugin:service=ServerPluginService"/>
+ <c:simple-property name="nameTemplate" default="RHQ Server
Plugin Subsystem"/>
+ <c:simple-property name="descriptionTemplate" default="Details
on the server-side plugin container subsystem"/>
</plugin-configuration>
<operation name="startPluginContainer" displayName="Start Plugin
Container"
- description="Starts the plugin container which will load and
initialize all content source plugins. Once started, content source feed data will be able
to start to flow">
+ description="Starts the plugin container which will load and
initialize all server-side plugins.">
</operation>
<operation name="stopPluginContainer" displayName="Stop Plugin
Container"
- description="Stops the plugin container which will shutdown all
content source plugins. Once stopped, content source feed data will not be able to
flow">
+ description="Stops the plugin container which will shutdown all
server-side plugins.">
</operation>
<operation name="restartPluginContainer" displayName="Restart
Plugin Container"
- description="Convienence operation that first stops and then
immediately restarts the plugin container.">
+ description="Convienence operation that first stops and then
immediately restarts the server plugin container.">
</operation>
<metric property="{pluginContainer.configuration.pluginDirectory}"