blob: c16c156b733f6715d7a82f67f406170ac6a9524b [file] [log] [blame]
/*
*
* 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.qpid.management.wsdm.muse.resources;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.namespace.QName;
import org.apache.muse.core.Capability;
import org.apache.muse.core.Environment;
import org.apache.muse.core.ResourceManager;
import org.apache.muse.core.routing.MessageHandler;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.muse.ws.addressing.EndpointReference;
import org.apache.muse.ws.addressing.WsaConstants;
import org.apache.muse.ws.addressing.soap.SoapConstants;
import org.apache.muse.ws.addressing.soap.SoapFault;
import org.apache.muse.ws.addressing.soap.SoapUtils;
import org.apache.muse.ws.resource.WsResource;
import org.apache.muse.ws.resource.metadata.MetadataDescriptor;
import org.apache.muse.ws.resource.metadata.WsrmdConstants;
import org.apache.muse.ws.resource.metadata.impl.SimpleMetadataDescriptor;
import org.apache.muse.ws.resource.metadata.impl.WsrmdUtils;
import org.apache.muse.ws.resource.properties.ResourcePropertyCollection;
import org.apache.muse.ws.resource.properties.impl.SimpleResourcePropertyCollection;
import org.apache.muse.ws.resource.properties.impl.WsrpUtils;
import org.apache.muse.ws.resource.properties.schema.ResourcePropertiesSchema;
import org.apache.muse.ws.resource.properties.schema.impl.SimpleResourcePropertiesSchema;
import org.apache.muse.ws.wsdl.WsdlUtils;
import org.apache.qpid.management.Messages;
import org.apache.qpid.management.wsdm.common.ThreadSessionManager;
import org.apache.qpid.transport.util.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* QMan WS resource.
* We could say that this is a QMan manageable entity under the
* WS-DM perspective.
*
* @author Andrea Gazzarini
*/
@SuppressWarnings("unchecked")
public class QManWsResource implements WsResource
{
private final static Logger LOGGER = Logger.get(QManWsResource.class);
/**
* Internal state of this resource.
*
* @author Andrea Gazzarini
*/
interface State
{
/**
* Provides initialization of this resource.
*
* @throws SoapFault when the initialization fails.
*/
void initialize() throws SoapFault;
/**
* Returns true if this resource has been initialized.
*
* @return true if this resource has been initialized.
*/
boolean hasBeenInitialized();
/**
* Returns true if this resource has been shutdown.
*
* @return true if this resource has been shutdown.
*/
boolean hasBeenShutdown();
/**
* Shuts down this resource.
*
* @throws SoapFault when the shutdown procedure fails.
*/
void shutdown() throws SoapFault;
}
private final State _hasBeenShutdown = new State()
{
/**
* Return false because this resource has been shutdown so therefore
* initialization occurred.
*
* @return true;
*/
public boolean hasBeenInitialized()
{
return true;
}
/**
* Returns true because this state indicates that resource has been shutdown.
*
* @return true.
*/
public boolean hasBeenShutdown()
{
return true;
}
/**
* Since this resource has been shutdown the initialization
* cannot be performed again.
* As conseguence of that this method throws an exception.
*
* @throws SoapFault each time this method is called.
*/
public void initialize() throws SoapFault
{
LOGGER.error(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
throw new SoapFault(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
}
public void shutdown() throws SoapFault
{
LOGGER.error(Messages.QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN);
throw new SoapFault(Messages.QMAN_100033_WS_RESOURCE_ALREADY_SHUTDOWN);
}
};
private final State _hasBeenInitialized = new State()
{
/**
* Returns true because this is the state where a resource is when it
* has been initialized.
*
* @return true.
*/
public boolean hasBeenInitialized()
{
return true;
}
/**
* Returns false because this resource has been initialized but no shutdown request
* has been received.
*
* @return false.
*/
public boolean hasBeenShutdown()
{
return false;
}
/**
* A resource in this state cannot be initialized again so if this method is called an
* exception is thrown.
*
* @throws SoapFault each time this method is called.
*/
public void initialize() throws SoapFault
{
LOGGER.error(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
throw new SoapFault(Messages.QMAN_100031_WS_RESOURCE_ALREADY_INITIALIZED);
}
/**
* Shuts down this resource.
*
* @throws SoapFault when the shutdown procedure fails.
*/
public void shutdown() throws SoapFault
{
shutdownCapabilities();
ResourceManager manager = getResourceManager();
if (manager.getResource(_enpointReference) != null)
{
manager.removeResource(_enpointReference);
}
_currentState = _hasBeenShutdown;
}
};
/**
* The initial state of this resource.
* As the name suggests, it is not yet initialized.
*/
private final State _notYetInitialized = new State()
{
/**
* Provides initialization of this resource.
*
* @throws SoapFault when the initialization fails.
*/
public void initialize() throws SoapFault
{
_properties = new SimpleResourcePropertyCollection();
_wsdl = ThreadSessionManager.getInstance().getSession().getWsdlDocument();
ResourcePropertiesSchema schema = createPropertiesSchema(_wsdl);
_properties.setSchema(schema);
MetadataDescriptor metadata = createMetadataDescriptor(_wsdl);
_properties.setMetadata(metadata);
initializeCapabilities();
_properties.applyMetadata();
// Resource intialization completed : Let's make a state change.
_currentState = _hasBeenInitialized;
}
/**
* Shuts down this resource.
*
* @throws SoapFault when the shutdown procedure fails. */
public void shutdown() throws SoapFault
{
LOGGER.error(Messages.QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED);
throw new SoapFault(Messages.QMAN_100032_WS_RESOURCE_NOT_YET_INITIALIZED);
}
/**
* Returns false because this state indicates that
* the resource has not yet been initialized.
*
* @return false;
*/
public boolean hasBeenInitialized()
{
return false;
}
/**
* Returns false because the resource, when is in this state
* hasn't been initialized and as conseguence of that hasn't
* been shutdonm.
*
* @return false;
*/
public boolean hasBeenShutdown()
{
return false;
}
};
private Map<String,Capability> _capabilitiesByAction = new HashMap<String, Capability>();
private Map<String, Capability> _capabilitiesByURI = new LinkedHashMap<String, Capability>();
private String _contextPath;
private Environment _environment;
private EndpointReference _enpointReference;
private State _currentState = _notYetInitialized;
private ResourceManager _resourceManager;
private ResourcePropertyCollection _properties;
private Map<String,String> _initParameters = Collections.EMPTY_MAP;
// Workaround : muse is using and hardcoded java.util.logging.Logger but we should use
// SLF4j so this is the original implementatation that won't never be used (on QMan classes)
private java.util.logging.Logger _logger;
private Document _wsdl;
private String _wsdlPath;
private QName _wsdlPortType;
/**
* Adds the given capability to this resource.
*
* @param capability the capability to be added.
*/
public void addCapability(Capability capability)
{
capability.setResource(this);
capability.setLog(getLog());
capability.setEnvironment(getEnvironment());
String uri = capability.getCapabilityURI();
_capabilitiesByURI.put(uri, capability);
LOGGER.debug(
Messages.QMAN_200033_CAPABILITY_CLASS_HAS_BEEN_ADDED,
capability.getClass(),
uri);
}
/**
* Returns the capability associated with the given URI.
*
* @return the capability associated with the given URI.
*/
public Capability getCapability(String capabilityURI)
{
return _capabilitiesByURI.get(capabilityURI);
}
/**
* Returns a collection with all registered capability URIs.
*
* @return a collection with all registered capability URIs.
*/
public final Collection getCapabilityURIs()
{
return Collections.unmodifiableSet(_capabilitiesByURI.keySet());
}
/**
* Returns the context path of this resource.
*
* @return the context path of this resource.
*/
public final String getContextPath()
{
return _contextPath;
}
/**
* Returns the endpoint reference of this resource.
*
* @return the endpoint reference of this resource.
*/
public EndpointReference getEndpointReference()
{
return _enpointReference;
}
/**
* Returns the enviroment associated with this resource.
*
* @return the enviroment associated with this resource.
*/
public final Environment getEnvironment()
{
return _environment;
}
/**
* Returns the initialization parameter of this resource associated with
* the given name.
*
* @param name the init parameter name.
* @return the initialization parameter associated with the given name.
*/
public final String getInitializationParameter(String name)
{
return (String)getInitializationParameters().get(name);
}
/**
* Returns the map containing all init parameters of this resource.
*
* @return the map containing all init parameters of this resource.
*/
public final Map<String,String> getInitializationParameters()
{
return _initParameters;
}
/**
* N.A. This resource uses QMan logging instead of plain java.util.logger
* implementation.
*/
public final java.util.logging.Logger getLog()
{
return _logger;
}
/**
* Returns the resource manager associated with this resource.
*
* @return the resource manager associated with this resource.
*/
public ResourceManager getResourceManager()
{
return _resourceManager;
}
/**
* Returns the wsdl (relative) path of this resource.
*
* @return the wsdl (relative) path of this resource.
*/
public String getWsdlPath()
{
return _wsdlPath;
}
/**
* Returns the port type of this resource.
*
* @return the port type of this resource.
*/
public final QName getWsdlPortType()
{
return _wsdlPortType;
}
/**
* Returns true if this resource has been initialized, false otherwise.
*
* @return true if this resource has been initialized, false otherwise.
*/
public final boolean hasBeenInitialized()
{
return _currentState.hasBeenInitialized();
}
/**
* Returns true if this resource has been shutdown, false otherwise.
*
* @return true if this resource has been shutdown, false otherwise.
*/
public final boolean hasBeenShutdown()
{
return _currentState.hasBeenShutdown();
}
/**
* Checks if a capability with the given URI is available for this resource.
*
* @return true if a capability with the given URI is available for this resource, false otherwise.
*/
public final boolean hasCapability(String capabilityURI)
{
return getCapability(capabilityURI) != null;
}
/**
* Returns the collection containing all properties of this resource.
*
* @return the collection containing all properties of this resource.
*/
public final ResourcePropertyCollection getPropertyCollection()
{
return _properties;
}
/**
* Return the WSDL document of this resource.
*
* @return the WSDL document of this resource.
*/
public Document getWsdl()
{
return _wsdl;
}
/**
* Initializes this resources.
* Note that the what needs to be done depends on the current state of this
* resource.
*
* @throws SoapFault when the initialization fails.
*/
public void initialize() throws SoapFault
{
_currentState.initialize();
}
/**
* Invokes the action specified in the given soap request on this resource.
*
* @param requestBody the SOAP body.
* @return the result of the invocation as org.w3c.dom.Element
*/
public Element invoke(Element requestBody)
{
String action = _environment.getAddressingContext().getAction();
Capability capability = getCapabilityForAction(action);
// Sanity check : is there a capability for the given action?
if (capability == null)
{
SoapFault wsaFault = new SoapFault(
String.format(
Messages.ACTION_NOT_SUPPORTED,
action,getContextPath()));
wsaFault.setCode(SoapConstants.SENDER_QNAME);
wsaFault.setSubCode(WsaConstants.ACTION_NOT_SUPPORTED_FAULT_QNAME);
Element detail = XmlUtils.createElement(WsaConstants.PROBLEM_ACTION_QNAME);
XmlUtils.setElement(detail, WsaConstants.ACTION_QNAME, action);
wsaFault.setDetail(detail);
LOGGER.error(
Messages.QMAN_100020_ACTION_NOT_SUPPORTED,
action,
getContextPath());
return wsaFault.toXML();
}
MessageHandler handler = capability.getMessageHandler(action);
Method method = handler.getMethod();
try
{
Object[]parameters = handler.fromXML(requestBody);
Object result = method.invoke(capability, parameters);
return handler.toXML(result);
}
catch (Throwable throwable)
{
LOGGER.error(
throwable,
Messages.QMAN_100037_INVOKE_OPERATION_FAILURE);
SoapFault response = SoapUtils.convertToFault(
(throwable.getCause()!= null)
? throwable.getCause()
: throwable);
return response.toXML();
}
}
/**
* Sets the context path of this resource.
*
* @param contextPath the context path of this resource.
*/
public final void setContextPath(String contextPath)
{
_contextPath = contextPath;
}
/**
* Sets the endpoint reference of this resource.
*
* @param endpointReference the endpoint reference of this resource.
*/
public final void setEndpointReference(EndpointReference endpointReference)
{
if (_enpointReference != null && hasBeenInitialized())
throw new RuntimeException(("ExistingResourceEPR"));
_enpointReference = endpointReference;
}
/**
* Sets the context environment of this resource.
*
* @param environment the context environment of this resource.
*/
public final void setEnvironment(Environment environment)
{
_environment = environment;
}
/**
* Sets the initialization parameters of this resource.
*
* @param parameters the init parameters of this resource.
*/
public final void setInitializationParameters(Map parameters)
{
_initParameters = (parameters != null)
? parameters
: Collections.EMPTY_MAP;
}
/**
* N.A. for this resource. QMan logging mechanism is used for that.
*/
public final void setLog(java.util.logging.Logger log)
{
_logger = log;
}
/**
* Sets the resource manager owner of this resource.
*
* @param manager the resource manager of this resource.
*/
public void setResourceManager(ResourceManager manager)
{
_resourceManager = manager;
}
/**
* Sets the WSDL (relative) path of this resource.
*
* @param wsdlPath the WSDL (relative) path of this resource.
*/
public final void setWsdlPath(String wsdlPath)
{
this._wsdlPath = wsdlPath;
}
/**
* Sets the port type of this resource.
*
* @param wsdlPortType the port type of this resource.
*/
public final void setWsdlPortType(QName wsdlPortType)
{
_wsdlPortType = wsdlPortType;
}
/**
* Shutdown procedure for this resource.
*
* @throws SoapFault when the shutdown procedure fails.
*/
public synchronized void shutdown() throws SoapFault
{
_currentState.shutdown();
}
/**
* Returns a string representation of this resource.
* Basically the resource endpoint reference (as a string) is returned.
*
* @return the resource endpoint reference (as a string) is returned.
*/
public String toString()
{
return getEndpointReference().toString();
}
/**
* Initializes capabilities of this resource.
*
* @throws SoapFault when at least one capability fails to initialize.
*/
private void initializeCapabilities() throws SoapFault
{
for (Entry<String, Capability> entry : _capabilitiesByURI.entrySet())
{
Capability capability = entry.getValue();
capability.initialize();
for (Object action : capability.getActions())
{
_capabilitiesByAction.put((String)action, capability);
}
capability.initializeCompleted();
}
}
/**
* Shutdown procedure for all registered capabilities of this resource.
*
* @throws SoapFault when at least one capability shutdown fails.
*/
private void shutdownCapabilities() throws SoapFault
{
for (Entry<String,Capability> entry : _capabilitiesByURI.entrySet())
{
Capability capabilty = entry.getValue();
capabilty.prepareShutdown();
capabilty.shutdown();
}
}
/**
* Creates a metadata descriptor for this resource.
*
* @param wsdl the WSDL document.
* @return a metadata descriptor for this resource.
* @throws SoapFault when it's not possible build the descriptor.
*/
private MetadataDescriptor createMetadataDescriptor(Document wsdl) throws SoapFault
{
try
{
Element portTypeXML = WsdlUtils.getPortType(wsdl, getWsdlPortType());
String rmdName = XmlUtils.getAttribute(
portTypeXML,
WsrmdConstants.DESCRIPTOR_ATTR_QNAME);
String rmdPath = XmlUtils.getAttribute(
portTypeXML,
WsrmdConstants.DESCRIPTOR_LOCATION_ATTR_QNAME);
LOGGER.debug(Messages.QMAN_200034_RMD_NAME, rmdName);
LOGGER.debug(Messages.QMAN_200035_RMD_PATH, rmdPath);
Environment env = getEnvironment();
String path = env.createRelativePath(getWsdlPath(), rmdPath);
Document rmdDoc = env.getDocument(path);
Element[] additionalProperties =
ThreadSessionManager
.getInstance()
.getSession()
.getResourceMetadataDescriptor();
Element metadataDescriptor = WsrmdUtils.getMetadataDescriptor(rmdDoc, rmdName);
for (Element element : additionalProperties)
{
// rmdDoc.importNode(element, true);
Element adopted = (Element) rmdDoc.importNode(element,false);
metadataDescriptor.appendChild(adopted);
}
return new SimpleMetadataDescriptor(metadataDescriptor);
}
catch(Exception exception)
{
LOGGER.error(
exception,
Messages.QMAN_100021_RMD_BUID_FAILURE,
getContextPath());
throw new SoapFault(exception);
}
}
/**
* Returns the capability associated with the given action.
*
* @param action the wsa:action of the requested capability.
* @return the capability associated with the given action.
*/
private Capability getCapabilityForAction(String action)
{
return (Capability)_capabilitiesByAction.get(action);
}
/**
* Creates a WSRP document representing schema properties for this resource.
*
* @param wsdl the DOM document holding the resource's WSDL.
* @return the WSRP document schema.
*/
private ResourcePropertiesSchema createPropertiesSchema(Document wsdl)
{
QName wsrpName = WsrpUtils.getPropertiesName(wsdl, getWsdlPortType());
Element wsrpDoc = WsdlUtils.getElementDeclaration(wsdl, wsrpName);
return new SimpleResourcePropertiesSchema(wsrpName, wsrpDoc);
}
}