/*
* 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.agent.metadata;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.JAXBElement;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.clientapi.descriptor.plugin.Bundle;
import org.rhq.core.clientapi.descriptor.plugin.BundleConfigFullCopy;
import org.rhq.core.clientapi.descriptor.plugin.BundleConfigPropertyReference;
import org.rhq.core.clientapi.descriptor.plugin.BundleDestination;
import org.rhq.core.clientapi.descriptor.plugin.BundleDestinationBaseDir;
import org.rhq.core.clientapi.descriptor.plugin.BundleDestinationDefinition;
import org.rhq.core.clientapi.descriptor.plugin.BundleTargetDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.BundleTraitReference;
import org.rhq.core.clientapi.descriptor.plugin.ContentDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.DiscoveryCallbacksType;
import org.rhq.core.clientapi.descriptor.plugin.DiscoveryTypeCallbackType;
import org.rhq.core.clientapi.descriptor.plugin.DriftDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.EventDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.MetricDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.OperationDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.ParentResourceType;
import org.rhq.core.clientapi.descriptor.plugin.PlatformDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.PluginDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.ProcessScanDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.ResourceCreateDeletePolicy;
import org.rhq.core.clientapi.descriptor.plugin.ResourceCreationData;
import org.rhq.core.clientapi.descriptor.plugin.ResourceDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.ResourceUpgradeCallbackType;
import org.rhq.core.clientapi.descriptor.plugin.RunsInsideType;
import org.rhq.core.clientapi.descriptor.plugin.ServerDescriptor;
import org.rhq.core.clientapi.descriptor.plugin.ServiceDescriptor;
import org.rhq.core.domain.bundle.BundleType;
import org.rhq.core.domain.bundle.ResourceTypeBundleConfiguration;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.event.EventDefinition;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.resource.ClassLoaderType;
import org.rhq.core.domain.resource.CreateDeletePolicy;
import org.rhq.core.domain.resource.ProcessScan;
import org.rhq.core.domain.resource.ResourceCategory;
import org.rhq.core.domain.resource.ResourceCreationDataType;
import org.rhq.core.domain.resource.ResourceType;
/**
* This is a stateful class intended to hold the related metadata for a single plugin descriptor. It is designed to be
* used by the PluginMetadataManager that will load multiple plugin descriptors and coordinate their metadata.
*
* @author Jason Dobies
* @author Greg Hinkle
*/
public class PluginMetadataParser {
private static final Log LOG = LogFactory.getLog(PluginMetadataParser.class);
private PluginDescriptor pluginDescriptor;
private List<ResourceType> resourceTypes = new ArrayList<ResourceType>();
private Set<ResourceType> rootResourceTypes = new LinkedHashSet<ResourceType>();
private Map<ResourceType, String> discoveryClasses = new HashMap<ResourceType, String>();
private Map<ResourceType, String> componentClasses = new HashMap<ResourceType, String>();
private Map<ResourceType, List<String>> discoveryCallbackClasses = null;
private Map<ResourceType, List<String>> resourceUpgradeCallbackClasses = null;
// a map keyed on plugin name that contains the parsers for all other known plugin descriptors
// this map is managed by this parser's PluginMetadataManager and is how the manager shares information
// from other plugins to this parser instance
private final Map<String, PluginMetadataParser> parsersByPlugin;
public PluginMetadataParser(PluginDescriptor descriptor, Map<String, PluginMetadataParser> parsersByPlugin)
throws InvalidPluginDescriptorException {
this.pluginDescriptor = descriptor;
this.parsersByPlugin = parsersByPlugin;
parseDescriptor();
}
public PluginDescriptor getDescriptor() {
return this.pluginDescriptor;
}
public String getPluginLifecycleListenerClass() {
String pkg = this.pluginDescriptor.getPackage();
String clazz = this.pluginDescriptor.getPluginLifecycleListener();
return getFullyQualifiedComponentClassName(pkg, clazz);
}
public List<ResourceType> getAllTypes() {
return new ArrayList<ResourceType>(resourceTypes);
}
/**
* @return the root types for this plugin (not necessarily root for the whole system)
*/
public Set<ResourceType> getRootResourceTypes() {
return this.rootResourceTypes;
}
/**
* This returns all resource types that this plugin defines discovery callbacks for.
* When the resource types' discovery is run, the details will be funneled through the discovery
* callbacks to give this plugin a chance to alter the discovered details.
* Note that it is very possible that the resource type keys are types that are NOT defined
* by the plugin associated with this parser. The resource types will be defined either in
* this plugin or one of its dependencies.
*
* @return map of all types that have one or more discovery callbacks defined. May be null.
*/
public Map<ResourceType, List<String>> getDiscoveryCallbackClasses() {
return discoveryCallbackClasses;
}
public Map<ResourceType, List<String>> getResourceUpgradeCallbackClasses() {
return resourceUpgradeCallbackClasses;
}
public void parseDescriptor() throws InvalidPluginDescriptorException {
ResourceType type;
// the plugin's root platforms
for (PlatformDescriptor descriptor : pluginDescriptor.getPlatforms()) {
type = parsePlatformDescriptor(descriptor);
if (type != null) {
rootResourceTypes.add(type);
}
}
// the plugin's root servers
for (ServerDescriptor descriptor : pluginDescriptor.getServers()) {
type = parseServerDescriptor(descriptor, null);
if (type != null) {
rootResourceTypes.add(type);
}
}
// the plugin's root services
for (ServiceDescriptor descriptor : pluginDescriptor.getServices()) {
type = parseServiceDescriptor(descriptor, null, null);
if (type != null) {
rootResourceTypes.add(type);
}
}
// find any declared discovery callbacks now - do this at the end in
// case we are defining callbacks on types in our own plugin
parseDiscoveryCallbacks();
parseBundleTypeTargets();
}
private void parseBundleTypeTargets() {
parseBundleTypeTarget(pluginDescriptor.getPlatforms());
parseBundleTypeTarget(pluginDescriptor.getServers());
parseBundleTypeTarget(pluginDescriptor.getServices());
}
private void parseBundleTypeTarget(List<? extends ResourceDescriptor> resourceTypes) {
for (ResourceDescriptor d : resourceTypes) {
if (d.getBundle() != null) {
ResourceType rt = getResourceTypeFromPlugin(d.getName(), pluginDescriptor.getName());
BundleType bt = rt.getBundleType();
parseBundleTypeTarget(bt, d.getBundle().getTargets());
}
}
}
private void parseBundleTypeTarget(BundleType bundleType, Bundle.Targets target) {
if (target == null) {
return;
}
for (Bundle.Targets.ResourceType ref : target.getResourceType()) {
ResourceType rt = getResourceTypeFromPlugin(ref.getName(), ref.getPlugin());
bundleType.addTargetedResourceType(rt);
}
}
private void parseDiscoveryCallbacks() throws InvalidPluginDescriptorException {
DiscoveryCallbacksType jaxbCallbacks = pluginDescriptor.getDiscoveryCallbacks();
if (jaxbCallbacks == null) {
return;
}
List<Object> jaxbCallbacksList = jaxbCallbacks.getTypeCallbackOrUpgradeCallback();
if (jaxbCallbacksList == null || jaxbCallbacksList.isEmpty()) {
return;
}
for (Object jaxbCallback : jaxbCallbacksList) {
if (jaxbCallback instanceof DiscoveryTypeCallbackType) {
parseDiscoveryCallback((DiscoveryTypeCallbackType) jaxbCallback);
} else {
parseResourceUpgradeCallback((ResourceUpgradeCallbackType) jaxbCallback);
}
}
}
private void parseDiscoveryCallback(DiscoveryTypeCallbackType jaxbCallback) throws InvalidPluginDescriptorException {
String plugin = jaxbCallback.getPlugin();
String type = jaxbCallback.getType();
String callbackClass = jaxbCallback.getCallbackClass();
LOG.debug("Plugin [" + pluginDescriptor.getName() + "] defined a discovery class [" + callbackClass
+ "] to listen for discovery details for type [{" + plugin + "}" + type + "].");
if (callbackClass == null || callbackClass.length() == 0) {
// this should never happen - the XML parser should have failed to even get this far
throw new InvalidPluginDescriptorException("Missing discovery class in plugin ["
+ pluginDescriptor.getName() + "] -> {" + plugin + "}" + type);
}
if (plugin == null || plugin.length() == 0 || type == null || type.length() == 0) {
// this should never happen - the XML parser should have failed to even get this far
throw new InvalidPluginDescriptorException("Both plugin and type must be defined for discovery callbacks in plugin ["
+ pluginDescriptor.getName() + "] -> {" + plugin + "}" + type + ":" + callbackClass);
}
ResourceType resourceType = getResourceTypeFromPlugin(type, plugin);
if (resourceType == null) {
LOG.warn("There is no type named [" + type + "] from a plugin named [" + plugin
+ "]. This is probably because that plugin is missing. The discovery callback will be ignored");
return;
}
if (discoveryCallbackClasses == null) {
discoveryCallbackClasses = new HashMap<ResourceType, List<String>>();
}
List<String> callbacksList = discoveryCallbackClasses.get(resourceType);
if (callbacksList == null) {
callbacksList = new ArrayList<String>(1);
discoveryCallbackClasses.put(resourceType, callbacksList);
}
String fqcn = getFullyQualifiedComponentClassName(pluginDescriptor.getPackage(), callbackClass);
callbacksList.add(fqcn);
}
private void parseResourceUpgradeCallback(ResourceUpgradeCallbackType jaxbCallback) throws InvalidPluginDescriptorException {
String plugin = jaxbCallback.getPlugin();
String type = jaxbCallback.getType();
String callbackClass = jaxbCallback.getCallbackClass();
LOG.debug("Plugin [" + pluginDescriptor.getName() + "] defined a resource upgrade callback class [" + callbackClass
+ "] to listen for resource upgrade results for type [{" + plugin + "}" + type + "].");
if (callbackClass == null || callbackClass.length() == 0) {
// this should never happen - the XML parser should have failed to even get this far
throw new InvalidPluginDescriptorException("Missing resource upgrade class in plugin ["
+ pluginDescriptor.getName() + "] -> {" + plugin + "}" + type);
}
if (plugin == null || plugin.length() == 0 || type == null || type.length() == 0) {
// this should never happen - the XML parser should have failed to even get this far
throw new InvalidPluginDescriptorException("Both plugin and type must be defined for resource upgrade callbacks in plugin ["
+ pluginDescriptor.getName() + "] -> {" + plugin + "}" + type + ":" + callbackClass);
}
ResourceType resourceType = getResourceTypeFromPlugin(type, plugin);
if (resourceType == null) {
LOG.warn("There is no type named [" + type + "] from a plugin named [" + plugin
+ "]. This is probably because that plugin is missing. The resource upgrade callback will be ignored");
return;
}
if (resourceUpgradeCallbackClasses == null) {
resourceUpgradeCallbackClasses = new HashMap<ResourceType, List<String>>();
}
List<String> callbacksList = resourceUpgradeCallbackClasses.get(resourceType);
if (callbacksList == null) {
callbacksList = new ArrayList<String>(1);
resourceUpgradeCallbackClasses.put(resourceType, callbacksList);
}
String fqcn = getFullyQualifiedComponentClassName(pluginDescriptor.getPackage(), callbackClass);
callbacksList.add(fqcn);
}
private ResourceType parsePlatformDescriptor(PlatformDescriptor platformDescriptor)
throws InvalidPluginDescriptorException {
ResourceType platformResourceType = new ResourceType(platformDescriptor.getName(), pluginDescriptor.getName(),
ResourceCategory.PLATFORM, null);
platformResourceType.setDescription(platformDescriptor.getDescription());
platformResourceType.setDisplayName(platformDescriptor.getDisplayName());
LOG.debug("Parsed platform resource type: " + platformResourceType);
parseResourceDescriptor(platformDescriptor, platformResourceType, null, null, null);
if ((platformResourceType.getProcessScans() != null) && (platformResourceType.getProcessScans().size() > 0)) {
LOG.warn("Platforms are not auto-discovered via process scans. "
+ "The <process-scan> elements will be ignored in resource type: " + platformResourceType);
}
RunsInsideType runsInside = platformDescriptor.getRunsInside();
if (runsInside != null) {
LOG.warn("Platforms do not currently support running inside other resources. "
+ "The <runs-inside> information will be ignored in resource type: " + platformResourceType);
}
platformResourceType.setCreateDeletePolicy(CreateDeletePolicy.NEITHER);
return platformResourceType;
}
private ResourceType parseServerDescriptor(ServerDescriptor serverDescriptor, ResourceType parentServerType)
throws InvalidPluginDescriptorException {
ResourceType serverResourceType;
String sourcePlugin = serverDescriptor.getSourcePlugin();
String sourceServer = serverDescriptor.getSourceType();
sourcePlugin = (sourcePlugin == null) ? "" : sourcePlugin.trim();
sourceServer = (sourceServer == null) ? "" : sourceServer.trim();
if ((sourcePlugin.length() == 0) && (sourceServer.length() == 0)) {
// not using Embedded extension model
serverResourceType = new ResourceType(serverDescriptor.getName(), pluginDescriptor.getName(),
ResourceCategory.SERVER, parentServerType);
serverResourceType.setDescription(serverDescriptor.getDescription());
serverResourceType.setDisplayName(serverDescriptor.getDisplayName());
serverResourceType.setSubCategory(serverDescriptor.getSubCategory());
serverResourceType.setCreationDataType(convertCreationDataType(serverDescriptor.getCreationDataType()));
serverResourceType
.setCreateDeletePolicy(convertCreateDeletePolicy(serverDescriptor.getCreateDeletePolicy()));
serverResourceType.setSingleton(serverDescriptor.isSingleton());
parseResourceDescriptor(serverDescriptor, serverResourceType, null, null, null);
LOG.debug("Parsed server Resource type: " + serverResourceType);
} else if ((sourcePlugin.length() > 0) && (sourceServer.length() > 0)) {
// using Embedded extension model - the defined type is actually a copy of another plugin's server type
LOG.debug("Parsing embedded server type {" + pluginDescriptor.getName() + "}"
+ serverDescriptor.getName() + ", which extends server type {" + sourcePlugin + "}" + sourceServer + "...");
Map<String, ServerDescriptor> pluginServerDescriptors = getPluginServerDescriptors(sourcePlugin);
ServerDescriptor sourceServerDescriptor = pluginServerDescriptors.get(sourceServer);
if (sourceServerDescriptor == null) {
LOG.warn("There is no server type named [" + sourceServer + "] from a plugin named [" + sourcePlugin
+ "]. This is probably because that plugin is missing. Resource Type [{"
+ pluginDescriptor.getName() + "}" + serverDescriptor.getName() + "] will be ignored.");
return null;
}
serverResourceType = new ResourceType(serverDescriptor.getName(), pluginDescriptor.getName(),
ResourceCategory.SERVER, parentServerType);
// Let the plugin writer override these, or if not, parseResourceDescriptor() will pick up the source type's
// values.
serverResourceType.setDescription(serverDescriptor.getDescription());
serverResourceType.setSubCategory(serverDescriptor.getSubCategory());
serverResourceType.setCreationDataType(convertCreationDataType(serverDescriptor.getCreationDataType()));
serverResourceType
.setCreateDeletePolicy(convertCreateDeletePolicy(serverDescriptor.getCreateDeletePolicy()));
serverResourceType.setSingleton(serverDescriptor.isSingleton());
String discoveryClass;
String componentClass;
if (serverDescriptor.getDiscovery() != null) {
discoveryClass = getFullyQualifiedComponentClassName(pluginDescriptor.getPackage(), serverDescriptor
.getDiscovery());
} else {
discoveryClass = getFullyQualifiedComponentClassName(getPluginPackage(sourcePlugin),
sourceServerDescriptor.getDiscovery());
}
if (serverDescriptor.getClazz() != null) {
componentClass = getFullyQualifiedComponentClassName(pluginDescriptor.getPackage(), serverDescriptor
.getClazz());
} else {
componentClass = getFullyQualifiedComponentClassName(getPluginPackage(sourcePlugin),
sourceServerDescriptor.getClazz());
}
parseResourceDescriptor(sourceServerDescriptor, serverResourceType, discoveryClass, componentClass,
sourcePlugin);
// The above incorporates children from the source descriptor. The following incorporates
// children from this descriptor
// Look for child server types
for (ServerDescriptor childServerDescriptor : serverDescriptor.getServers()) {
parseServerDescriptor(childServerDescriptor, serverResourceType);
}
// Look for child service types
for (ServiceDescriptor childServiceDescriptor : serverDescriptor.getServices()) {
parseServiceDescriptor(childServiceDescriptor, serverResourceType, null);
}
} else {
// this should never happen - the XML parser should have failed to even get this far
throw new InvalidPluginDescriptorException("Both sourcePlugin and sourceType must be defined: "
+ serverDescriptor.getName());
}
serverResourceType.setSupportsManualAdd(serverDescriptor.isSupportsManualAdd());
serverResourceType.setSupportsMissingAvailabilityType(serverDescriptor.isSupportsMissingAvailabilityType());
// now see if we are using the Injection extension model
// if so, we need to inject the new resource type as a child to the parent plugin's types
RunsInsideType runsInside = serverDescriptor.getRunsInside();
if (runsInside != null) {
List<ParentResourceType> parentTypesDescriptor = runsInside.getParentResourceType();
for (ParentResourceType parentTypeDescriptor : parentTypesDescriptor) {
String parentTypeName = parentTypeDescriptor.getName();
String parentTypePlugin = parentTypeDescriptor.getPlugin();
ResourceType parentTypeToInjectInto = getResourceTypeFromPlugin(parentTypeName, parentTypePlugin);
if (parentTypeToInjectInto != null) {
// inject our new server resource type as a child type to the parent plugin's type
parentTypeToInjectInto.addChildResourceType(serverResourceType);
} else {
// The parent plugin owning the resource that this resource can run inside of does not exist.
// We will ignore this runs-inside declaration, thus allowing optional plugins to be missing.
LOG.warn("There is no resource type named [" + parentTypeName + "] from a plugin named ["
+ parentTypePlugin + "]. This is probably because that plugin is missing. Resource Type [{"
+ pluginDescriptor.getName() + "}" + serverDescriptor.getName()
+ "] will not have that missing type as a possible parent.");
}
}
}
return serverResourceType;
}
private ResourceType parseServiceDescriptor(ServiceDescriptor serviceDescriptor, ResourceType parentType,
String parentSourcePlugin) throws InvalidPluginDescriptorException {
ResourceType serviceResourceType;
String sourcePlugin = serviceDescriptor.getSourcePlugin();
// Fallback to using the source plugin of your parent if you don't override.
if (sourcePlugin == null) {
sourcePlugin = parentSourcePlugin;
}
sourcePlugin = (sourcePlugin != null) ? sourcePlugin.trim() : "";
String sourceType = serviceDescriptor.getSourceType();
sourceType = (sourceType != null) ? sourceType.trim() : "";
if (sourcePlugin.isEmpty() && sourceType.isEmpty()) {
// not using Embedded extension model
serviceResourceType = new ResourceType(serviceDescriptor.getName(), pluginDescriptor.getName(),
ResourceCategory.SERVICE, parentType);
serviceResourceType.setDescription(serviceDescriptor.getDescription());
serviceResourceType.setDisplayName(serviceDescriptor.getDisplayName());
serviceResourceType.setSubCategory(serviceDescriptor.getSubCategory());
serviceResourceType.setCreationDataType(convertCreationDataType(serviceDescriptor.getCreationDataType()));
serviceResourceType.setCreateDeletePolicy(convertCreateDeletePolicy(serviceDescriptor
.getCreateDeletePolicy()));
serviceResourceType.setSingleton(serviceDescriptor.isSingleton());
parseResourceDescriptor(serviceDescriptor, serviceResourceType, null, null, null);
LOG.debug("Parsed service Resource type: " + serviceResourceType);
if ((serviceResourceType.getProcessScans() != null) && (serviceResourceType.getProcessScans().size() > 0)) {
LOG.warn("Child services are not auto-discovered via process scans. "
+ "The <process-scan> elements will be ignored in resource type: " + serviceResourceType);
}
} else {
// Using Embedded extension model - the defined type is actually a copy of another plugin's service or server type.
LOG.debug("Parsing embedded service type {" + pluginDescriptor.getName() + "}"
+ serviceDescriptor.getName() + ", which extends type {" + sourcePlugin + "}" + sourceType + "...");
ResourceDescriptor sourceTypeDescriptor;
if (sourceType.isEmpty()) {
sourceTypeDescriptor = serviceDescriptor;
} else {
Map<String, ServiceDescriptor> pluginServiceDescriptors = getPluginServiceDescriptors(sourcePlugin);
sourceTypeDescriptor = pluginServiceDescriptors.get(sourceType);
if (sourceTypeDescriptor == null) {
Map<String, ServerDescriptor> pluginServerDescriptors = getPluginServerDescriptors(sourcePlugin);
sourceTypeDescriptor = pluginServerDescriptors.get(sourceType);
}
}
if (sourceTypeDescriptor == null) {
LOG.warn("There is no service or server type named [" + sourceType + "] from a plugin named ["
+ sourcePlugin + "]. This is probably because that plugin is missing. Resource Type [{"
+ pluginDescriptor.getName() + "}" + serviceDescriptor.getName() + "] will be ignored.");
return null;
}
serviceResourceType = new ResourceType(serviceDescriptor.getName(), pluginDescriptor.getName(),
ResourceCategory.SERVICE, parentType);
// Let the plugin writer override these, or if not, parseResourceDescriptor() will pick up the source type's
// values.
serviceResourceType.setDescription(serviceDescriptor.getDescription());
serviceResourceType.setSubCategory(serviceDescriptor.getSubCategory());
serviceResourceType.setDisplayName(serviceDescriptor.getDisplayName());
serviceResourceType.setCreationDataType(convertCreationDataType(serviceDescriptor.getCreationDataType()));
serviceResourceType.setCreateDeletePolicy(convertCreateDeletePolicy(serviceDescriptor
.getCreateDeletePolicy()));
serviceResourceType.setSingleton(serviceDescriptor.isSingleton());
serviceResourceType.setSupportsMissingAvailabilityType(serviceDescriptor
.isSupportsMissingAvailabilityType());
String discoveryClass;
if (serviceDescriptor.getDiscovery() != null) {
discoveryClass = getFullyQualifiedComponentClassName(getPluginPackage(sourcePlugin), serviceDescriptor
.getDiscovery());
} else {
discoveryClass = getFullyQualifiedComponentClassName(getPluginPackage(sourcePlugin),
sourceTypeDescriptor.getDiscovery());
}
String componentClass;
if (serviceDescriptor.getClazz() != null) {
componentClass = getFullyQualifiedComponentClassName(getPluginPackage(sourcePlugin), serviceDescriptor
.getClazz());
} else {
componentClass = getFullyQualifiedComponentClassName(getPluginPackage(sourcePlugin),
sourceTypeDescriptor.getClazz());
}
parseResourceDescriptor(sourceTypeDescriptor, serviceResourceType, discoveryClass, componentClass,
sourcePlugin);
}
serviceResourceType.setSupportsManualAdd(serviceDescriptor.isSupportsManualAdd());
serviceResourceType.setSupportsMissingAvailabilityType(serviceDescriptor.isSupportsMissingAvailabilityType());
// now see if we are using the Injection extension model
// if so, we need to inject the new resource type as a child to the parent plugin's types
// note that the Injection model only allows for root-level services to be injected
if (parentType == null) {
RunsInsideType runsInside = serviceDescriptor.getRunsInside();
if (runsInside != null) {
List<ParentResourceType> parentTypesDescriptor = runsInside.getParentResourceType();
for (ParentResourceType parentTypeDescriptor : parentTypesDescriptor) {
String parentTypeName = parentTypeDescriptor.getName();
String parentTypePlugin = parentTypeDescriptor.getPlugin();
ResourceType parentTypeToInjectInto = getResourceTypeFromPlugin(parentTypeName, parentTypePlugin);
if (parentTypeToInjectInto != null) {
// inject our new server resource type as a child type to the parent plugin's type
parentTypeToInjectInto.addChildResourceType(serviceResourceType);
} else {
// The parent plugin owning the resource that this resource can run inside of does not exist.
// We will ignore this runs-inside declaration, thus allowing optional plugins to be missing.
LOG.warn("There is no resource type named [" + parentTypeName + "] from a plugin named ["
+ parentTypePlugin
+ "]. This is probably because that plugin is missing. Resource Type [{"
+ pluginDescriptor.getName() + "}" + serviceDescriptor.getName()
+ "] will not have that missing type as a possible parent.");
}
}
}
}
return serviceResourceType;
}
/**
* Parses the resource descriptor and registers the type and its component classes.
*
* @param resourceDescriptor
* @param resourceType the new resource type that will get the new data found in the descriptor added to it
* @param discoveryClass if <code>null</code>, will get the classname from the resourceDescriptor; otherwise,
* is used as-is
* @param componentClass if <code>null</code>, will get the classname from the resourceDescriptor; otherwise,
* is used as-is
*
* @throws InvalidPluginDescriptorException
*/
private void parseResourceDescriptor(ResourceDescriptor resourceDescriptor, ResourceType resourceType,
String discoveryClass, String componentClass, String sourcePlugin) throws InvalidPluginDescriptorException {
// 1) Subcategory
// 2) Classes
// 3) Plugin config
// 4) Resource config
// 5) Drift definition
// 6) Metrics
// 7) Control operations
// 8) Process matches (for process scan auto-discovery)
// 9) Artifacts
// 10) Child subcategories
// 11) Bundle Type
// 12) Bundle Configuration (for types that are targets for bundle deployments)
String classLoaderTypeString = resourceDescriptor.getClassLoader();
if (classLoaderTypeString == null) {
resourceType.setClassLoaderType(ClassLoaderType.SHARED);
} else {
resourceType.setClassLoaderType(ClassLoaderType.valueOf(classLoaderTypeString.toUpperCase()));
}
// Only set the description, subCategory, etc. if they have not already been set. This is in
if (resourceType.getDescription() == null) {
resourceType.setDescription(resourceDescriptor.getDescription());
}
if (resourceType.getDisplayName() == null) {
resourceType.setDisplayName(resourceDescriptor.getDisplayName());
}
if (resourceType.getSubCategory() == null) {
resourceType.setSubCategory(resourceDescriptor.getSubCategory());
}
if (discoveryClass == null) {
discoveryClass = getFullyQualifiedComponentClassName(pluginDescriptor.getPackage(), resourceDescriptor
.getDiscovery());
}
if (componentClass == null) {
componentClass = getFullyQualifiedComponentClassName(pluginDescriptor.getPackage(), resourceDescriptor
.getClazz());
}
try {
resourceType.setPlugin(pluginDescriptor.getName().intern());
if (resourceDescriptor.getPluginConfiguration() != null) {
resourceType.setPluginConfigurationDefinition(ConfigurationMetadataParser.parse(resourceType.getName(),
resourceDescriptor.getPluginConfiguration()));
}
if (resourceDescriptor.getResourceConfiguration() != null) {
resourceType.setResourceConfigurationDefinition(ConfigurationMetadataParser.parse(resourceType
.getName(), resourceDescriptor.getResourceConfiguration()));
}
Set<String> driftDefNames = new HashSet<String>();
DriftMetadataParser driftMetadataParser = new DriftMetadataParser();
for (DriftDescriptor descriptor : resourceDescriptor.getDriftDefinition()) {
if (driftDefNames.contains(descriptor.getName())) {
throw new InvalidPluginDescriptorException("Duplicate drift definition name detected ["
+ descriptor.getName() + "]");
}
driftDefNames.add(descriptor.getName());
resourceType.addDriftDefinitionTemplate(driftMetadataParser.parseDriftMetadata(descriptor));
}
driftDefNames = null; // don't need this anymore
int displayPosition = 1;
for (MetricDescriptor metricDescriptor : resourceDescriptor.getMetric()) {
List<MeasurementDefinition> measurementDefinition = MetricsMetadataParser.parseMetricsMetadata(
metricDescriptor, resourceType);
for (MeasurementDefinition def : measurementDefinition) {
def.setDisplayOrder(displayPosition++);
resourceType.addMetricDefinition(def);
}
}
for (EventDescriptor eventDescriptor : resourceDescriptor.getEvent()) {
EventDefinition eventDefinition = EventsMetadataParser.parseEventsMetadata(eventDescriptor,
resourceType);
resourceType.addEventDefinition(eventDefinition);
}
for (OperationDescriptor operationDescriptor : resourceDescriptor.getOperation()) {
resourceType.addOperationDefinition(OperationsMetadataParser
.parseOperationDescriptor(operationDescriptor));
}
for (ProcessScanDescriptor processMatch : resourceDescriptor.getProcessScan()) {
resourceType.addProcessScan(new ProcessScan(processMatch.getQuery(), processMatch.getName()));
}
for (ContentDescriptor contentDescriptor : resourceDescriptor.getContent()) {
resourceType.addPackageType(ContentMetadataParser.parseContentDescriptor(contentDescriptor));
}
Bundle bundle = resourceDescriptor.getBundle();
if (bundle != null) {
String typeName = bundle.getType();
resourceType.setBundleType(new BundleType(typeName, resourceType));
// do NOT parse the target types of bundle type right now so that we don't
// require the plugin writer to order the types herself
}
BundleTargetDescriptor bundleTarget = resourceDescriptor.getBundleTarget();
if (bundleTarget != null) {
List<BundleDestination> destDefs = bundleTarget.getDestinationBaseDirOrDestinationDefinition();
if (destDefs != null && destDefs.size() > 0) {
Configuration c = new Configuration();
ResourceTypeBundleConfiguration bundleConfiguration = new ResourceTypeBundleConfiguration(c);
for (BundleDestination destDef : destDefs) {
if (destDef instanceof BundleDestinationBaseDir) {
BundleDestinationBaseDir destBaseDir = (BundleDestinationBaseDir) destDef;
String name = destBaseDir.getName();
String valueContext = destBaseDir.getValueContext();
String valueName = destBaseDir.getValueName();
String description = destBaseDir.getDescription();
List<String> accepts = new ArrayList<String>();
for(BundleDestination.Accepts accept : destBaseDir.getAccepts()) {
accepts.add(accept.getBundleType());
}
bundleConfiguration.addBundleDestinationBaseDirectory(name, valueContext, valueName,
description, accepts);
} else if (destDef instanceof BundleDestinationDefinition) {
BundleDestinationDefinition def = (BundleDestinationDefinition) destDef;
ResourceTypeBundleConfiguration.BundleDestinationDefinition.Builder bld = bundleConfiguration
.createDestinationDefinitionBuilder(def.getName());
bld.withDescription(def.getDescription()).withConnectionString(def.getConnection());
for (BundleDestination.Accepts accept : def.getAccepts()) {
bld.addAcceptedBundleType(accept.getBundleType());
}
for (JAXBElement<?> ref : def.getReferencedConfiguration()
.getMapPropertyRefOrListPropertyRefOrSimplePropertyRef()) {
String tagName = ref.getName().getLocalPart();
if ("simple-property-ref".equals(tagName)) {
BundleConfigPropertyReference r = (BundleConfigPropertyReference) ref.getValue();
if ("pluginConfiguration".equals(r.getContext())) {
bld.addPluginConfigurationSimplePropertyReference(r.getName(),
r.getTargetName());
} else if ("resourceConfiguration".equals(r.getContext())) {
bld.addResourceConfigurationSimplePropertyReference(r.getName(),
r.getTargetName());
}
} else if ("list-property-ref".equals(tagName)) {
BundleConfigPropertyReference r = (BundleConfigPropertyReference) ref.getValue();
if ("pluginConfiguration".equals(r.getContext())) {
bld.addPluginConfigurationListPropertyReference(r.getName(),
r.getTargetName());
} else if ("resourceConfiguration".equals(r.getContext())) {
bld.addResourceConfigurationListPropertyReference(r.getName(),
r.getTargetName());
}
} else if ("map-property-ref".equals(tagName)) {
BundleConfigPropertyReference r = (BundleConfigPropertyReference) ref.getValue();
if ("pluginConfiguration".equals(r.getContext())) {
bld.addPluginConfigurationMapPropertyReference(r.getName(),
r.getTargetName());
} else if ("resourceConfiguration".equals(r.getContext())) {
bld.addResourceConfigurationMapPropertyReference(r.getName(),
r.getTargetName());
}
} else if ("trait-ref".equals(tagName)) {
BundleTraitReference r = (BundleTraitReference) ref.getValue();
bld.addMeasurementTraitReference(r.getName(), r.getTargetName());
} else if ("all".equals(tagName)) {
BundleConfigFullCopy r = (BundleConfigFullCopy) ref.getValue();
if ("pluginConfiguration".equals(r.getOf())) {
bld.addFullPluginConfigurationReference(r.getPrefix());
} else if ("resourceConfiguration".equals(r.getOf())) {
bld.addFullResourceConfigurationReference(r.getPrefix());
} else if ("traits".equals(r.getOf())) {
bld.addFullMeasurementTraitsReference(r.getPrefix());
}
}
}
bld.build();
}
}
resourceType.setResourceTypeBundleConfiguration(bundleConfiguration);
}
}
} catch (InvalidPluginDescriptorException e) {
// TODO: Should we be storing these for viewing in server? Breaking deployment? What?
throw e;
}
// The type is built, register it
registerResourceTypeAndComponentClasses(resourceType, discoveryClass, componentClass);
// Look for child types
if (resourceDescriptor instanceof PlatformDescriptor) {
for (ServerDescriptor serverDescriptor : ((PlatformDescriptor) resourceDescriptor).getServers()) {
parseServerDescriptor(serverDescriptor, resourceType);
}
for (ServiceDescriptor serviceDescriptor : ((PlatformDescriptor) resourceDescriptor).getServices()) {
parseServiceDescriptor(serviceDescriptor, resourceType, sourcePlugin);
}
}
if (resourceDescriptor instanceof ServerDescriptor) {
for (ServerDescriptor serverDescriptor : ((ServerDescriptor) resourceDescriptor).getServers()) {
parseServerDescriptor(serverDescriptor, resourceType);
}
for (ServiceDescriptor serviceDescriptor : ((ServerDescriptor) resourceDescriptor).getServices()) {
parseServiceDescriptor(serviceDescriptor, resourceType, sourcePlugin);
}
}
if (resourceDescriptor instanceof ServiceDescriptor) {
for (ServiceDescriptor serviceDescriptor : ((ServiceDescriptor) resourceDescriptor).getServices()) {
parseServiceDescriptor(serviceDescriptor, resourceType, sourcePlugin);
}
}
}
private String getFullyQualifiedComponentClassName(String packageName, String baseClassName) {
if (baseClassName == null) {
return null;
}
if ((baseClassName.indexOf('.') > -1) || (packageName == null)) {
return baseClassName; // looks like must already be fully qualified
}
return packageName + '.' + baseClassName;
}
/**
* Returns the fully qualified name of the resource discovery component class for the given ResourceType.
* This method is only called by the Plugin Container.
*
* @param resourceType the ResourceType
* @return the resource discovery component class name
*/
public String getDiscoveryComponentClass(ResourceType resourceType) {
String s = this.discoveryClasses.get(resourceType);
if (s!=null) {
s = s.intern();
}
return s;
}
/**
* Returns the fully qualified name of the resource component class for the given ResourceType.
* This method is only called by the Plugin Container.
*
* @param resourceType the ResourceType
* @return the resource component class name
*/
public String getComponentClass(ResourceType resourceType) {
String s = this.componentClasses.get(resourceType);
if (s!=null) {
s=s.intern();
}
return s;
}
private void registerResourceTypeAndComponentClasses(ResourceType resourceType, String discoveryClass,
String componentClass) {
this.resourceTypes.add(resourceType);
if (componentClass!=null) {
this.componentClasses.put(resourceType, componentClass.intern());
} else {
this.componentClasses.put(resourceType, null);
}
if (discoveryClass != null) {
this.discoveryClasses.put(resourceType, discoveryClass.intern());
}
}
private Map<String, ServerDescriptor> getPluginServerDescriptors(String pluginName) {
Map<String, ServerDescriptor> pluginServerDescriptors = new HashMap<String, ServerDescriptor>();
PluginMetadataParser pluginParser;
// get the plugin parser that corresponds to the plugin (which could be this plugin parser)
if (pluginName.equals(this.pluginDescriptor.getName())) {
pluginParser = this;
} else {
pluginParser = parsersByPlugin.get(pluginName);
}
if (pluginParser != null) {
for (ServerDescriptor server : pluginParser.pluginDescriptor.getServers()) {
pluginServerDescriptors.put(server.getName(), server);
}
}
return pluginServerDescriptors;
}
private Map<String, ServiceDescriptor> getPluginServiceDescriptors(String pluginName) {
Map<String, ServiceDescriptor> pluginServiceDescriptors = new HashMap<String, ServiceDescriptor>();
PluginMetadataParser pluginParser;
// get the plugin parser that corresponds to the plugin (which could be this plugin parser)
if (pluginName.equals(this.pluginDescriptor.getName())) {
pluginParser = this;
} else {
pluginParser = parsersByPlugin.get(pluginName);
}
if (pluginParser != null) {
addPluginServiceDescriptors(pluginParser.pluginDescriptor.getServices(), pluginServiceDescriptors);
addPluginServiceDescriptors(pluginParser.pluginDescriptor.getServers(), pluginServiceDescriptors);
}
return pluginServiceDescriptors;
}
private String getPluginPackage(String pluginName) {
String packageName = null;
PluginMetadataParser pluginParser;
// get the plugin parser that corresponds to the plugin (which could be this plugin parser)
if (pluginName.equals(this.pluginDescriptor.getName())) {
pluginParser = this;
} else {
pluginParser = parsersByPlugin.get(pluginName);
}
if (pluginParser != null) {
packageName = pluginParser.pluginDescriptor.getPackage();
}
return packageName;
}
private void addPluginServiceDescriptors(Collection<? extends ResourceDescriptor> parents,
Map<String, ServiceDescriptor> descriptors) {
if (parents != null) {
for (ResourceDescriptor parent : parents) {
List<ServiceDescriptor> services;
if (parent instanceof ServerDescriptor) {
services = ((ServerDescriptor) parent).getServices();
} else if (parent instanceof ServiceDescriptor) {
services = ((ServiceDescriptor) parent).getServices();
} else {
throw new IllegalStateException("Unsupported parent descriptor type: "
+ parent.getClass().getName());
}
for (ServiceDescriptor service : services) {
descriptors.put(service.getName(), service);
addPluginServiceDescriptors(service.getServices(), descriptors); // recurse down the hierarchy
}
}
}
}
private ResourceType getResourceTypeFromPlugin(String resourceTypeName, String pluginName) {
if ((resourceTypeName != null) && (pluginName != null)) {
PluginMetadataParser pluginParser;
// get the plugin parser that corresponds to the plugin that has the type (which could be this plugin parser)
if (pluginName.equals(this.pluginDescriptor.getName())) {
pluginParser = this;
} else {
pluginParser = parsersByPlugin.get(pluginName);
}
// go through the plugin's entire list of resource types to find the one we are looking for
if (pluginParser != null) {
for (ResourceType type : pluginParser.resourceTypes) {
if (resourceTypeName.equals(type.getName())) {
return type;
}
}
}
}
return null;
}
/**
* Converts the creation data descriptor (JAXB) object into the domain enumeration.
*
* @param creationType descriptor read creation data object
*
* @return domain enumeration value; <code>null</code> if the JAXB representation is <code>null</code> or does not
* correspond to any domain enumerated value
*/
private ResourceCreationDataType convertCreationDataType(ResourceCreationData creationType) {
switch (creationType) {
case CONTENT: {
return ResourceCreationDataType.CONTENT;
}
case CONFIGURATION: {
return ResourceCreationDataType.CONFIGURATION;
}
}
return null;
}
/**
* Converts the create and delete policy descriptor (JAXB) object into the domain enumeration.
*
* @param policy descriptor read policy
*
* @return domain enumeration value; <code>null</code> if the JAXB representation is <code>null</code> or does not
* correspond to any domain enumerated value
*/
private CreateDeletePolicy convertCreateDeletePolicy(ResourceCreateDeletePolicy policy) {
switch (policy) {
case BOTH: {
return CreateDeletePolicy.BOTH;
}
case CREATE_ONLY: {
return CreateDeletePolicy.CREATE_ONLY;
}
case DELETE_ONLY: {
return CreateDeletePolicy.DELETE_ONLY;
}
case NEITHER: {
return CreateDeletePolicy.NEITHER;
}
}
return null;
}
public void cleanDescriptor() {
pluginDescriptor=null;
}
}