/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.muse.tools.generator.analyzer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.muse.tools.generator.util.Capability;
import org.apache.muse.tools.generator.util.ConfigurationData;
import org.apache.muse.tools.generator.util.ConfigurationDataDescriptor;
import org.apache.muse.tools.generator.util.DeploymentDescriptorHelper;
import org.apache.muse.tools.inspector.JavaMethod;
import org.apache.muse.tools.inspector.JavaProperty;
import org.apache.muse.tools.inspector.ResourceInspector;
import org.apache.muse.ws.dm.muws.MuwsConstants;
import org.apache.muse.ws.dm.muws.adv.impl.SimpleAdvertisement;
import org.apache.muse.ws.dm.muws.impl.SimpleConfiguration;
import org.apache.muse.ws.dm.muws.impl.SimpleCorrelatableProperties;
import org.apache.muse.ws.dm.muws.impl.SimpleDescription;
import org.apache.muse.ws.dm.muws.impl.SimpleIdentity;
import org.apache.muse.ws.dm.muws.impl.SimpleManageabilityCharacteristics;
import org.apache.muse.ws.dm.muws.impl.SimpleMetrics;
import org.apache.muse.ws.dm.muws.impl.SimpleOperationalStatus;
import org.apache.muse.ws.dm.muws.impl.SimpleRelationshipResource;
import org.apache.muse.ws.dm.muws.impl.SimpleRelationships;
import org.apache.muse.ws.dm.muws.impl.SimpleState;
import org.apache.muse.ws.metadata.WsxConstants;
import org.apache.muse.ws.notification.NotificationProducer;
import org.apache.muse.ws.notification.SubscriptionManager;
import org.apache.muse.ws.notification.WsnConstants;
import org.apache.muse.ws.notification.impl.SimpleNotificationConsumer;
import org.apache.muse.ws.notification.impl.SimpleNotificationProducer;
import org.apache.muse.ws.notification.impl.SimpleSubscriptionManager;
import org.apache.muse.ws.resource.lifetime.WsrlConstants;
import org.apache.muse.ws.resource.lifetime.impl.SimpleScheduledTermination;
import org.apache.muse.ws.resource.metadata.MetadataDescriptor;
import org.apache.muse.ws.resource.metadata.OpenMetadataDescriptor;
import org.apache.muse.ws.resource.properties.WsrpConstants;
import org.apache.muse.ws.resource.properties.get.impl.SimpleGetCapability;
import org.apache.muse.ws.resource.sg.Entry;
import org.apache.muse.ws.resource.sg.WssgConstants;
import org.apache.muse.ws.resource.sg.impl.SimpleEntry;
import org.apache.muse.ws.resource.sg.impl.SimpleServiceGroup;
import org.apache.muse.ws.resource.sg.impl.SimpleServiceGroupRegistration;
import org.w3c.dom.Document;
/**
* SimpleAnalyzer is a canonical implementation of an <code>Analyzer</code>. This
* class will take in a description of a resource (using WSDL and/or a Muse descriptor).
* Using these documents it will create a map of <code>Capability</code> objects which
* describe the resource as a set of capabilities. The class takes into account
* built-in capabilities and their related operations/properties. For user-defined
* capabilities, there are special steps taken to group operations and properties into
* capabilities. See the project tools documentation for more information.
*
* @author Andrew Eberbach (aeberbac)
*
* @see org.apache.muse.tools.generator.analyzer.Analyzer
*/
public class SimpleAnalyzer implements Analyzer {
/**
* QName to Capability URIs for properties, operations. This
* is where we keep the mapping that determines which properties
* and which operations belong to which capability URIs.
*/
static Map _qnameCapabilityMap = new HashMap();
/**
* Capability URIs to classes that implement them provided by Muse.
*/
static Map _internalImplMap = new HashMap();
/**
* QName to Action URI for operation parameters.
*/
static Map _internalActionMap = new HashMap();
static {
//WS-X
_qnameCapabilityMap.put(WsxConstants.GET_METADATA_QNAME,
WsxConstants.GET_METADATA_CAPABILITY);
_internalImplMap.put(WsxConstants.GET_METADATA_CAPABILITY,
org.apache.muse.ws.metadata.impl.SimpleMetadataExchange.class);
_internalActionMap.put(WsxConstants.GET_METADATA_QNAME,
WsxConstants.GET_METADATA_URI);
//WS-RP GET
_qnameCapabilityMap.put(WsrpConstants.GET_QNAME,
WsrpConstants.GET_CAPABILITY);
_qnameCapabilityMap.put(WsrpConstants.GET_DOCUMENT_QNAME,
WsrpConstants.GET_CAPABILITY);
_qnameCapabilityMap.put(WsrpConstants.GET_MULTIPLE_QNAME,
WsrpConstants.GET_CAPABILITY);
_qnameCapabilityMap.put(WsrpConstants.QUERY_DIALECT_QNAME,
WsrpConstants.GET_CAPABILITY);
_internalImplMap.put(WsrpConstants.GET_CAPABILITY,
SimpleGetCapability.class);
_internalActionMap.put(WsrpConstants.GET_QNAME,
WsrpConstants.GET_RESOURCE_PROPERTY_URI);
_internalActionMap.put(WsrpConstants.GET_DOCUMENT_QNAME,
WsrpConstants.GET_RP_DOCUMENT_URI);
_internalActionMap.put(WsrpConstants.GET_MULTIPLE_QNAME,
WsrpConstants.GET_MULTIPLE_PROPERTIES_URI);
//WS-RP QUERY
_qnameCapabilityMap.put(WsrpConstants.QUERY_QNAME,
WsrpConstants.QUERY_CAPABILITY);
_internalImplMap.put(WsrpConstants.QUERY_CAPABILITY,
org.apache.muse.ws.resource.properties.query.impl.SimpleQueryCapability.class);
_internalActionMap.put(WsrpConstants.QUERY_QNAME,
WsrpConstants.QUERY_RESOURCE_PROPERTIES_URI);
//WS-RP SET
_qnameCapabilityMap.put(WsrpConstants.SET_QNAME,
WsrpConstants.SET_CAPABILITY);
_internalImplMap.put(WsrpConstants.SET_CAPABILITY,
org.apache.muse.ws.resource.properties.set.impl.SimpleSetCapability.class);
_internalActionMap.put(WsrpConstants.SET_QNAME,
WsrpConstants.SET_RESOURCE_PROPERTIES_URI);
//WS-RL Immediate
_qnameCapabilityMap.put(WsrlConstants.DESTROY_QNAME,
WsrlConstants.IMMEDIATE_TERMINATION_URI);
_internalImplMap.put(WsrlConstants.IMMEDIATE_TERMINATION_URI,
org.apache.muse.ws.resource.lifetime.impl.SimpleImmediateTermination.class);
_internalActionMap.put(WsrlConstants.DESTROY_QNAME,
WsrlConstants.DESTROY_URI);
//WS-RL Scheduled
addProperties(SimpleScheduledTermination.PROPERTIES,
WsrlConstants.SCHEDULED_TERMINATION_URI);
_qnameCapabilityMap.put(WsrlConstants.SET_TERMINATION_QNAME,
WsrlConstants.SCHEDULED_TERMINATION_URI);
_internalImplMap.put(WsrlConstants.SCHEDULED_TERMINATION_URI,
org.apache.muse.ws.resource.lifetime.impl.SimpleScheduledTermination.class);
_internalActionMap.put(WsrlConstants.SET_TERMINATION_QNAME,
WsrlConstants.SET_TERMINATION_URI);
//WS-DM Identity
addProperties(SimpleIdentity.PROPERTIES,
MuwsConstants.IDENTITY_URI);
_internalImplMap.put(MuwsConstants.IDENTITY_URI,
SimpleIdentity.class);
//WS-DM Manageability Characteristics
addProperties(SimpleManageabilityCharacteristics.PROPERTIES,
MuwsConstants.CHARACTERISTICS_URI);
_internalImplMap.put(MuwsConstants.CHARACTERISTICS_URI,
SimpleManageabilityCharacteristics.class);
//WS-DM Correlatable Properties
addProperties(SimpleCorrelatableProperties.PROPERTIES,
MuwsConstants.CORRELATABLE_URI);
_internalImplMap.put(MuwsConstants.CORRELATABLE_URI,
SimpleCorrelatableProperties.class);
//WS-DM Description
addProperties(SimpleDescription.PROPERTIES,
MuwsConstants.DESCRIPTION_URI);
_internalImplMap.put(MuwsConstants.DESCRIPTION_URI,
SimpleDescription.class);
//WS-DM Operational Status
addProperties(SimpleOperationalStatus.PROPERTIES,
MuwsConstants.OP_STATUS_URI);
_internalImplMap.put(MuwsConstants.OP_STATUS_URI,
SimpleOperationalStatus.class);
//WS-DM Metrics
addProperties(SimpleMetrics.PROPERTIES,
MuwsConstants.METRICS_URI);
_internalImplMap.put(MuwsConstants.METRICS_URI,
SimpleMetrics.class);
//WS-DM Configuration
_internalImplMap.put(MuwsConstants.CONFIGURATION_URI,
SimpleConfiguration.class);
//WS-DM State
addProperties(SimpleState.PROPERTIES,
MuwsConstants.STATE_URI);
_internalImplMap.put(MuwsConstants.STATE_URI,
SimpleState.class);
//WS-DM Relationships
addProperties(SimpleRelationships.PROPERTIES,
MuwsConstants.RELATIONSHIPS_URI);
_qnameCapabilityMap.put(MuwsConstants.QUERY_RELATIONSHIPS_QNAME,
MuwsConstants.RELATIONSHIPS_URI);
_internalImplMap.put(MuwsConstants.RELATIONSHIPS_URI,
SimpleRelationships.class);
_internalActionMap.put(MuwsConstants.QUERY_RELATIONSHIPS_QNAME,
MuwsConstants.QUERY_RELATIONSHIPS_URI);
//WS-DM Relationship Resource
addProperties(SimpleRelationshipResource.PROPERTIES,
MuwsConstants.RELATIONSHIP_RESOURCE_URI);
_internalImplMap.put(MuwsConstants.RELATIONSHIP_RESOURCE_URI,
SimpleRelationshipResource.class);
//WS-DM Advertisement
_internalImplMap.put(MuwsConstants.ADVERTISEMENT_URI,
SimpleAdvertisement.class);
//WS-SG ServiceGroup
addProperties(SimpleServiceGroup.PROPERTIES,
WssgConstants.SERVICE_GROUP_URI);
_internalImplMap.put(WssgConstants.SERVICE_GROUP_URI,
SimpleServiceGroup.class);
//WS-SG Entry
addProperties(Entry.PROPERTIES,
WssgConstants.ENTRY_URI);
_internalImplMap.put(WssgConstants.ENTRY_URI,
SimpleEntry.class);
//WS-SG Registration
_internalActionMap.put(WssgConstants.ADD_URI,
WssgConstants.SERVICE_GROUP_REG_URI);
_internalImplMap.put(WssgConstants.SERVICE_GROUP_REG_URI,
SimpleServiceGroupRegistration.class);
//WS-N Consumer
_qnameCapabilityMap.put(WsnConstants.NOTIFY_QNAME,
WsnConstants.CONSUMER_URI);
_internalImplMap.put(WsnConstants.CONSUMER_URI,
SimpleNotificationConsumer.class);
_internalActionMap.put(WsnConstants.NOTIFY_QNAME,
WsnConstants.NOTIFY_URI);
//WS-N Producer
addProperties(NotificationProducer.PROPERTIES,
WsnConstants.PRODUCER_URI);
_qnameCapabilityMap.put(WsnConstants.SUBSCRIBE_QNAME,
WsnConstants.PRODUCER_URI);
_qnameCapabilityMap.put(WsnConstants.GET_CURRENT_QNAME,
WsnConstants.PRODUCER_URI);
_internalImplMap.put(WsnConstants.PRODUCER_URI,
SimpleNotificationProducer.class);
_internalActionMap.put(WsnConstants.SUBSCRIBE_QNAME,
WsnConstants.SUBSCRIBE_URI);
_internalActionMap.put(WsnConstants.GET_CURRENT_QNAME,
WsnConstants.GET_CURRENT_URI);
//SubscriptionManager
addProperties(SubscriptionManager.PROPERTIES,
WsnConstants.SUBSCRIPTION_MGR_URI);
_qnameCapabilityMap.put(WsnConstants.PAUSE_QNAME,
WsnConstants.SUBSCRIPTION_MGR_URI);
_qnameCapabilityMap.put(WsnConstants.RESUME_QNAME,
WsnConstants.SUBSCRIPTION_MGR_URI);
_internalImplMap.put(WsnConstants.SUBSCRIPTION_MGR_URI,
SimpleSubscriptionManager.class);
_internalActionMap.put(WsnConstants.PAUSE_QNAME,
WsnConstants.PAUSE_URI);
_internalActionMap.put(WsnConstants.RESUME_QNAME,
WsnConstants.RESUME_URI);
}
static ConfigurationDataDescriptor[] REQUIRED_PARAMETERS =
new ConfigurationDataDescriptor[] {
ConfigurationData.DESCRIPTOR_DOCUMENT_CONFIGURATION
};
private Map[] _capabilityMaps = null;
private Document[] _wsdlDocuments = null;
private MetadataDescriptor[] _metadataDescriptors;
/**
* Uses the <code>ResourceInspector</code> to analyze a given WSDL file and
* extract the capabilities it contains. Capabilities are grouped by namespace URI
* but special exception is made to "built-in" capabilities and standard capabilities
* defined by the standards bodies.
*
* @param configuration
* Contains the parameters for the analyzer
*/
public ConfigurationData analyze(ConfigurationData configuration) throws Exception {
ConfigurationData.checkConfiguration(this, configuration);
loadParameters(configuration);
for(int i=0; i < _wsdlDocuments.length; i++) {
ResourceInspector inspector = inspect(_wsdlDocuments[i], _metadataDescriptors[i]);
_capabilityMaps[i] = new HashMap();
extractOperations(inspector, _capabilityMaps[i]);
extractProperties(inspector, _capabilityMaps[i]);
}
for(int i=0; i < _wsdlDocuments.length; i++) {
updateFromDescriptor(configuration, i);
}
return createResultData(configuration);
}
/**
* Add the given properties to the QName -> capability URI map.
*
* @param properties
* Properties to add
* @param uri
* URI to which they map
*/
private static void addProperties(QName[] properties, String uri) {
for(int i=0; i < properties.length; i++) {
_qnameCapabilityMap.put(properties[i], uri);
}
}
/**
* Load the parameters from the <code>ConfigurationData</code>. The only
* parameter we really care about is the WSDL file from
* <code>ConfigurationData.WSDL_DOCUMENT</code>.
*
* @param configuration
* The configuration to read
*/
private void loadParameters(ConfigurationData configuration) {
_wsdlDocuments =
(Document[])configuration.getParameter(ConfigurationData.WSDL_DOCUMENT_LIST);
_capabilityMaps = new HashMap[_wsdlDocuments.length];
_metadataDescriptors =
(MetadataDescriptor[])configuration.getParameter(ConfigurationData.METADATA_DESCRIPTOR_LIST);
}
/**
* Create a <code>ResourceInspector</code> and run it against the
* given WSDL file.
*
* @param wsdlDocument
* The document to inspect
* @param descriptor
* @return
* The <code>ResourceInspector</code> that analyzed the
* given document.
*/
private ResourceInspector inspect(Document wsdlDocument, MetadataDescriptor descriptor) {
ResourceInspector inspector = new ResourceInspector();
inspector.setMetadata(descriptor);
inspector.run(wsdlDocument.getDocumentElement(), null);
return inspector;
}
/**
* Create the <code>ConfigurationData</code> that we wil pass back to the
* caller of <code>analyze</code> so that they can pass it on to the next
* phase. The current configuration is <code>clone</code>d.
*
* This class inserts a <code>Map[]</code> containing the capabilities for
* each resource found.
*
* @param configuration
* The current configuration.
* @return
* A cloned configuration with our result added.
*/
private ConfigurationData createResultData(ConfigurationData configuration) {
ConfigurationData resultData = (ConfigurationData) configuration.clone();
resultData.addParameter(ConfigurationData.CAPABILITIES_MAP_LIST, _capabilityMaps);
return resultData;
}
/**
* Find all of the properties that the inspector saw and split them up by
* capability URI.
*
* @param inspector
* The inspector that ran against the current WSDL
* @param capabilities
* A Map of capability objects (URI->Capability)
*/
private void extractProperties(ResourceInspector inspector, Map capabilities) {
Capability capability = null;
Collection properties = inspector.getProperties();
if (properties != null) {
for (Iterator i = properties.iterator(); i.hasNext();) {
QName property = (QName) i.next();
capability = getCapability(property,capabilities);
capability.addProperty(makeJavaProperty(property, inspector));
}
}
}
/**
* Find all of the operations that the inspector saw and split them up by
* capability URI.
* @param inspector
* The inspector that ran against the current WSDL
* @param capabilities
* A Map of capability objects (URI->Capability)
*/
private void extractOperations(ResourceInspector inspector, Map capabilities) {
Capability capability = null;
Map methods = inspector.getJavaMethods();
for (Iterator i = methods.values().iterator(); i.hasNext();) {
JavaMethod method = (JavaMethod) i.next();
capability = getCapability(method.getName(), capabilities);
String actionURI = (String) _internalActionMap.get(method.getName());
if(actionURI != null) {
method.setActionURI(actionURI);
}
capability.addOperation(method);
}
}
/**
* Check the descriptor to see if there are already mappings defined from Capability URIs to
* java classes. This is optional.
*
* If there are such mappings then they will overwrite the generated class names. This
* also works for creating custom implementations of built-in mappings.
*
* @param configuration
* The configuration that might contain the Descriptor (ConfigurationData.DESCRIPTOR_DOCUMENT).
*
* @param resourceIndex
* The index of resource-type element that we are currently dealing with, since
* a descriptor can contain more than one resource-type.
*
* @throws Exception
* If something goes wrong with reading the descriptor. See the DeploymentDescriptorHelper.
*/
private void updateFromDescriptor(ConfigurationData configuration, int resourceIndex) throws Exception {
Document descriptorDocument =
(Document)configuration.getParameter(ConfigurationData.DESCRIPTOR_DOCUMENT);
if(descriptorDocument == null) {
return;
}
DeploymentDescriptorHelper helper =
new DeploymentDescriptorHelper(descriptorDocument, _wsdlDocuments[resourceIndex], resourceIndex);
Capability[] capsFromDescriptor = helper.getCapabilities();
Map currentCapabilityMap = _capabilityMaps[resourceIndex];
for(int i=0; i < capsFromDescriptor.length; i++) {
Capability capability = capsFromDescriptor[i];
//
// If the capability is in the capability map then
// it means that we found some wsdl operations or properties. If
// it isn't in this map then it's something that has no wsdl properties
// or operations which means it's one of those empty capabilities. We
// want to generate code for this, just in case.
//
String uri = capability.getURI();
Capability existingCapability = (Capability) currentCapabilityMap.get(uri);
if(existingCapability != null) {
String implClass = capability.getImplementingClass();
if(implClass != null) {
String existingClass = existingCapability.getImplementingClass();
if(existingClass == null) {
existingCapability.setImplementingClass(implClass);
existingCapability.setBuiltIn(false);
} else {
if(!existingClass.equals(implClass)) {
existingCapability.setImplementingClass(implClass);
existingCapability.setBuiltIn(false);
}
}
}
} else {
//
// Make sure this isn't a built-in empty capability
//
Class implementingClass = (Class)_internalImplMap.get(uri);
if(implementingClass == null) {
currentCapabilityMap.put(uri, capability);
capability.setBuiltIn(false);
}
}
}
}
/**
* Create a <code>JavaProperty</code> from a QName and a java type that
* we get from the <code>ResourInspector</code>.
*
* @param property
* The name of the property
* @param inspector
* The inspector run on the WSDL containing the property.
*
* @return
* A wrapped version of the property containing its QName and
* corresponding java class.
*/
private JavaProperty makeJavaProperty(QName property, ResourceInspector inspector) {
JavaProperty javaProperty = new JavaProperty();
javaProperty.setQName(property);
javaProperty.setJavaType(inspector.getPropertyType(property));
MetadataDescriptor metadata = inspector.getMetadata();
//
// Need to check to see if the metadata document
// has the given property. This isn't always true since metadata
// is optional
//
if(!metadata.hasProperty(property)) {
metadata = OpenMetadataDescriptor.getInstance();
}
javaProperty.setMetadata(metadata);
return javaProperty;
}
/**
* Given a QName get its capability. If the capability is
* not in the given capabilities map then create a new <code>Capability</code>.
*
* The QName can be a property or an input element on an operation.
*
* We also check to see if the capability URI is a built-in
* capability. If so then we mark the capability as "built-in" using
* <code>setBuiltIn(true)</code>;
*
* The reason why this class isn't just a lookup into the capabilities
* map is that we don't know if the namespace uri of the given
* qname matches its capability URI.
*
* @param qname
* The name of the property or input element which
* we want to associate with a capability.
* @param capabilities
* The capabilities map (URI->Capability)
*
* @return
* A new wrapped capability or an existing capability.
*/
private Capability getCapability(QName qname, Map capabilities) {
String capabilityURI = getCapabilityURI(qname);
Capability capability = (Capability) capabilities.get(capabilityURI);
if (capability == null) {
capability = new Capability(capabilityURI);
capabilities.put(capabilityURI, capability);
}
Class implementingClass = (Class)_internalImplMap.get(capabilityURI);
if(implementingClass != null) {
capability.setImplementingClass(implementingClass.getName());
capability.setBuiltIn(true);
}
return capability;
}
/**
* Given a QName get the capability URI. This is
* the point at which we look into the giant map of
* QNames->URIs to find if the given QName has a capability URI
* that differs from its namespace URI.
*
* @param qname
* The name of a property or operation.
*
* @return The URI of the capability that defines the property or operation.
*/
private String getCapabilityURI(QName qname) {
String result = (String) _qnameCapabilityMap.get(qname);
// If it isn't built-in, then just assume that
// the namespace URI for the QName is the capability URI
return result == null ? qname.getNamespaceURI() : result;
}
/**
* Returns <code>REQUIRED_PARAMETERS</code> which is a descriptor of
* the parameters we need at a bare minimum.
*
* @return
* A list of descriptors for the parameters we need to run.
*
* @see org.apache.muse.tools.generator.util.Configurable#getConfigurationDataDescriptions()
*/
public ConfigurationDataDescriptor[] getConfigurationDataDescriptions() {
return REQUIRED_PARAMETERS;
}
}