blob: cabeb3ae29993f44dacdfcc76c8c883171ec7db3 [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.axis2.jaxws.description.impl;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.description.Parameter;
import org.apache.axis2.java.security.AccessController;
import org.apache.axis2.jaxws.ClientConfigurationFactory;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.catalog.JAXWSCatalogManager;
import org.apache.axis2.jaxws.catalog.impl.OASISCatalogManager;
import org.apache.axis2.jaxws.description.DescriptionFactory;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.description.EndpointInterfaceDescription;
import org.apache.axis2.jaxws.description.ResolvedHandlersDescription;
import org.apache.axis2.jaxws.description.ServiceDescription;
import org.apache.axis2.jaxws.description.ServiceDescriptionJava;
import org.apache.axis2.jaxws.description.ServiceDescriptionWSDL;
import org.apache.axis2.jaxws.description.ServiceRuntimeDescription;
import org.apache.axis2.jaxws.description.builder.DescriptionBuilderComposite;
import org.apache.axis2.jaxws.description.builder.MDQConstants;
import org.apache.axis2.jaxws.description.builder.PortComposite;
import static org.apache.axis2.jaxws.description.builder.MDQConstants.RETURN_TYPE_FUTURE;
import static org.apache.axis2.jaxws.description.builder.MDQConstants.RETURN_TYPE_RESPONSE;
import org.apache.axis2.jaxws.description.builder.MethodDescriptionComposite;
import org.apache.axis2.jaxws.description.builder.ParameterDescriptionComposite;
import org.apache.axis2.jaxws.description.xml.handler.HandlerChainsType;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.util.WSDL4JWrapper;
import org.apache.axis2.jaxws.util.WSDLWrapper;
import org.apache.axis2.AxisFault;
import org.apache.axis2.engine.AxisConfiguration;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xml.resolver.Catalog;
import javax.jws.HandlerChain;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.wsdl.WSDLException;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.xml.namespace.QName;
import javax.xml.ws.WebServiceClient;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.handler.PortInfo;
import javax.xml.ws.soap.SOAPBinding;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.net.ConnectException;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
/** @see ../ServiceDescription */
class ServiceDescriptionImpl
implements ServiceDescription, ServiceDescriptionWSDL, ServiceDescriptionJava {
private ClientConfigurationFactory clientConfigFactory;
private ConfigurationContext configContext;
// Number of times this instance is being used. For service-providers, this is not decremented
// since the serice isn't un-used once it is created. For service-requesters, the service
// is used by ServiceDelegates, and becomes un-used when the ServiceDelegate is released.
private int useCount = 0;
private String wsdlURL;
private QName serviceQName;
private WSDLWrapper wsdlWrapper;
private WSDLWrapper generatedWsdlWrapper;
//ANNOTATION: @HandlerChain
private HandlerChain handlerChainAnnotation;
private HandlerChainsType handlerChainsType;
// EndpointDescriptions from annotations and wsdl
private Map<QName, EndpointDescription> definedEndpointDescriptions =
new HashMap<QName, EndpointDescription>();
// Endpoints for dynamic ports
// This needs to be a strong reference (not Weak or Soft) so that the resource release logic
// in the finalizer still has a reference to the EndpointDescriptions so they can be
// released. Otherwise, this collection will be null when the finalizer is called.
private Map<Object, Map<QName, EndpointDescriptionImpl>> dynamicEndpointDescriptions =
new HashMap<Object, Map<QName, EndpointDescriptionImpl>>();
// Cache classes for the info for resolved handlers
private SoftReference<Map<PortInfo, ResolvedHandlersDescription>> resolvedHandlersDescription =
new SoftReference<Map<PortInfo, ResolvedHandlersDescription>>
(new ConcurrentHashMap<PortInfo, ResolvedHandlersDescription>());
private static final Log log = LogFactory.getLog(ServiceDescriptionImpl.class);
private HashMap<String, DescriptionBuilderComposite> dbcMap = null;
private DescriptionBuilderComposite composite = null;
private boolean isServerSide = false;
// Allow a unique XML CatalogManager per service description.
private JAXWSCatalogManager catalogManager = null;
// RUNTIME INFORMATION
Map<String, ServiceRuntimeDescription> runtimeDescMap =
new ConcurrentHashMap<String, ServiceRuntimeDescription>();
private static final String JAXWS_DYNAMIC_ENDPOINTS = "jaxws.dynamic.endpoints";
/**
* Create a service-requester side (aka client-side) service description.
* Construct a service description hierachy
* based on WSDL (may be null), the Service class, and a service QName.
*
* @param wsdlURL The WSDL file (this may be null).
* @param serviceQName The name of the service in the WSDL. This can not be null since a
* javax.xml.ws.Service can not be created with a null service QName.
* @param serviceClass The JAX-WS service class. This could be an instance of
* javax.xml.ws.Service or a generated service subclass thereof. This will
* not be null.
*/
ServiceDescriptionImpl(URL wsdlURL, QName serviceQName, Class serviceClass) {
this(wsdlURL, serviceQName, serviceClass, null, null);
}
/**
* Create a service-requester side service description. Same as constructor above with an
* additonal composite paramater. Note that the composite is "sparse" in that any values it
* contains overrides any values on the corresponding class annotation HOWEVER if the composite
* doesn't specify a value, it is gotten from the class annotation.
* @param wsdlURL
* @param serviceQName
* @param serviceClass
* @param sparseComposite a composite with any annotation overrides such as from a client deployment
* descriptor. CAN NOT BE NULL, but it can be an object created with a default constructor
*/
ServiceDescriptionImpl(URL wsdlURL, QName serviceQName, Class serviceClass,
DescriptionBuilderComposite sparseComposite,
Object sparseCompositeKey) {
if (log.isDebugEnabled()) {
log.debug("ServiceDescriptionImpl(URL,QName,Class,DescriptionBuilderComposite,Object)");
}
if (sparseComposite != null) {
catalogManager = sparseComposite.getCatalogManager();
}
if (catalogManager == null) {
catalogManager = new OASISCatalogManager();
}
if (serviceQName == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("serviceDescErr0"));
}
if (serviceClass == null) {
throw ExceptionFactory
.makeWebServiceException(Messages.getMessage("serviceDescErr1", "null"));
}
if (!javax.xml.ws.Service.class.isAssignableFrom(serviceClass)) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("serviceDescErr1", serviceClass.getName()));
}
composite = new DescriptionBuilderComposite();
composite.setIsServiceProvider(false);
composite.setCorrespondingClass(serviceClass);
// The classloader was originally gotten off this class, but it seems more logical to
// get it off the application service class.
// composite.setClassLoader(this.getClass().getClassLoader());
composite.setClassLoader(getClassLoader(serviceClass));
composite.setSparseComposite(sparseCompositeKey, sparseComposite);
// If there's a WSDL URL specified in the sparse composite, that is a override, for example
// from a JSR-109 deployment descriptor, and that's the one to use.
URL sparseCompositeWsdlURL = getSparseCompositeWsdlURL(sparseComposite);
if (sparseCompositeWsdlURL != null) {
if (log.isDebugEnabled()) {
log.debug("Wsdl location overriden by sparse composite; overriden value: " + this.wsdlURL);
}
this.wsdlURL = sparseCompositeWsdlURL.toString();
} else {
this.wsdlURL = wsdlURL == null ? null : wsdlURL.toString();
}
if (log.isDebugEnabled()) {
log.debug("Wsdl Location value used: " + this.wsdlURL);
}
// TODO: On the client side, we should not support partial WSDL; i.e. if the WSDL is specified it must be
// complete and must contain the ServiceQName. This is how the Sun RI behaves on the client.
// When this is fixed, the check in ServiceDelegate(URL, QName, Class) should be removed
// TODO: The serviceQName needs to be verified between the argument/WSDL/Annotation
this.serviceQName = serviceQName;
setupWsdlDefinition();
}
URL getSparseCompositeWsdlURL(DescriptionBuilderComposite sparseComposite) {
// Use the WSDL file if it is specified in the composite
URL url = null;
if (sparseComposite != null) {
WebServiceClient wsc = (WebServiceClient) sparseComposite.getWebServiceClientAnnot();
if (wsc != null && wsc.wsdlLocation() != null) {
String wsdlLocation = wsc.wsdlLocation();
URL wsdlUrl = getWSDLURL(wsdlLocation);
if (wsdlUrl == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("serviceDescErr4", wsdlLocation));
} else {
url = wsdlUrl;
}
}
}
return url;
}
private static URL createWsdlURL(String wsdlLocation) {
URL theUrl = null;
try {
theUrl = new URL(wsdlLocation);
} catch (Exception ex) {
// Just return a null to indicate we couldn't create a URL from the string
if (log.isDebugEnabled()) {
log.debug("Unable to obtain URL for WSDL file: " + wsdlLocation
+ " by using File reference");
}
}
return theUrl;
}
ServiceDescriptionImpl(
HashMap<String, DescriptionBuilderComposite> dbcMap,
DescriptionBuilderComposite composite) {
this(dbcMap, composite, null);
}
ServiceDescriptionImpl(HashMap<String, DescriptionBuilderComposite> dbcMap,
DescriptionBuilderComposite composite,
ConfigurationContext configContext) {
this(dbcMap, composite, configContext, null);
}
/**
* Create a service-provider side Service description hierachy. The hierachy is created entirely
* from composite. All relevant classes and interfaces referenced from the class represented by
* composite must be included in the map.
* @param dbcMap
* @param composite
*/
ServiceDescriptionImpl(
HashMap<String, DescriptionBuilderComposite> dbcMap,
DescriptionBuilderComposite composite,
ConfigurationContext configContext,
QName serviceQName) {
this.composite = composite;
this.configContext = configContext;
if (log.isDebugEnabled()) {
log.debug("ServiceDescriptionImpl(HashMap<String,DescriptionBuilderComposite>,ConfigurationContext)");
}
String serviceImplName = this.composite.getClassName();
this.dbcMap = dbcMap;
this.isServerSide = true;
this.serviceQName = serviceQName;
this.catalogManager = this.composite.getCatalogManager();
// if the ServiceDescriptionImpl was constructed with a specific service QName
// we should use that to retrieve the potential list of PortComposite objects
List<PortComposite> portComposites = null;
if(this.serviceQName != null) {
portComposites = composite.getPortComposites(this.serviceQName);
}
else {
portComposites = composite.getPortComposites();
}
//capture the WSDL, if there is any...to be used for later processing
setupWsdlDefinition();
// Do a first pass validation for this DescriptionBuilderComposite.
// This is not intended to be a full integrity check, but rather a fail-fast mechanism
validateDBCLIntegrity();
// The ServiceQName instance variable is set based on annotation or default
// It will be set by the EndpointDescriptionImpl since it is the one that knows
// how to process the annotations and the defaults.
// If PortComposite instances were specified on the DBC we are currently processing
// we want to switch the context of processing to the PortComposites
if(portComposites != null
&&
!portComposites.isEmpty()) {
if(log.isDebugEnabled()) {
log.debug("Constructing EndpointDescription instance from PortComposites for " +
"implementation class: " + composite.getClassName());
}
int i = 0;
for(PortComposite portComposite : portComposites) {
// get the properties from the SEI and the Impl
Map<String, Object> props = getAllProps(portComposite, dbcMap);
// here we pass in an index so the EndpointDescriptionImpl instance will know
// which PortComposite instance it is associated with and can retrieve that
// instance as required
EndpointDescriptionImpl endpointDescription =
new EndpointDescriptionImpl(this, serviceImplName, props, i);
addEndpointDescription(endpointDescription);
i++;
}
}
// If no PortComposites then we build the EndpointDescriptionImpl instance from the
// DBC that was supplied
else {
if(log.isDebugEnabled()) {
log.debug("No PortComposites found for implementation class: " + composite.getClassName());
}
// get the properties from the SEI and the Impl
Map<String, Object> props = getAllProps(composite, dbcMap);
// Create the single EndpointDescription hierachy from the service impl annotations; Since the PortQName is null,
// it will be set to the annotation value.
EndpointDescriptionImpl endpointDescription =
new EndpointDescriptionImpl(this, serviceImplName, props, null);
addEndpointDescription(endpointDescription);
}
}
/*=======================================================================*/
/*=======================================================================*/
// START of public accessor methods
/**
* Update or create an EndpointDescription. Updates to existing EndpointDescriptons will be
* based on the SEI class and its annotations. Both declared ports and dynamic ports can be
* updated. A declared port is one that is defined (e.g. in WSDL or via annotations); a dyamic
* port is one that is not defined (e.g. not via WSDL or annotations) and has been added via
* Serivce.addPort.
* <p/>
* For predefined ports, a composite of sparse metadata, such as from a deployment descriptor
* may be supplied. This can be used to modify the endpoint interfaceannotations such as
* adding a handler chain. The sparse composite is NOT supported for dynamic (i.e. ADD_PORT)
* or dispatch clients.
* <p/>
* Notes on how an EndpointDescription can be updated or created: 1) Service.createDispatch can
* create a Dispatch client for either a declared or dynamic port 2) Note that creating a
* Dispatch does not associate an SEI with an endpoint 3) Service.getPort will associate an SEI
* with a port 4) A getPort on an endpoint which was originally created for a Distpatch will
* update that EndpointDescription with the SEI provided on the getPort 5) Service.getPort can
* not be called on a dynamic port (per the JAX-WS spec) 6) Service.addPort can not be called
* for a declared port
*
* @param sei This will be non-null if the update is of type GET_PORT; it will be null if
* the update is ADD_PORT or CREATE_DISPATCH
* @param portQName
* @param updateType Indicates what is causing the update GET_PORT is an attempt to get a
* declared SEI-based port ADD_PORT is an attempt to add a previously
* non-existent dynamic port CREATE_DISPATCH is an attempt to create a
* Dispatch-based client to either a declared port or a pre-existing dynamic
* port.
* @param composite May contain sparse metadata, for example from a deployment descriptor, that
* should be used in conjunction with the class annotations to update the
* description hierarchy. For example, it may contain a HandlerChain annotation
* based on information in a JSR-109 deployment descriptor.
*/
EndpointDescription updateEndpointDescription(Class sei,
QName portQName,
DescriptionFactory.UpdateType updateType,
DescriptionBuilderComposite composite,
Object serviceDelegateKey,
String bindingId,
String endpointAddress) {
EndpointDescriptionImpl endpointDescription = getEndpointDescriptionImpl(portQName);
boolean isPortDeclared = isPortDeclared(portQName);
// If a defined endpointDescription is not available, try and locate a dynamic endpoint.
// Note that a dynamic port will only be found for the client that created it, per the
// serviceDelegateKey
if (endpointDescription == null && serviceDelegateKey != null) {
endpointDescription = getDynamicEndpointDescriptionImpl(portQName, serviceDelegateKey);
}
// If no QName was specified in the arguments, one may have been specified in the sparse
// composite metadata when the service was created.
if (DescriptionUtils.isEmpty(portQName)) {
QName preferredPortQN = getPreferredPort(serviceDelegateKey);
if (!DescriptionUtils.isEmpty(preferredPortQN)) {
portQName = preferredPortQN;
}
}
switch (updateType) {
case ADD_PORT:
if (composite != null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("serviceDescErr5", portQName.toString()));
}
// Port must NOT be declared (e.g. can not already exist in WSDL)
// If an EndpointDesc doesn't exist; create it as long as it doesn't exist in the WSDL
if (DescriptionUtils.isEmpty(portQName)) {
throw ExceptionFactory
.makeWebServiceException(Messages.getMessage("addPortErr2"));
}
if (getWSDLWrapper() != null && isPortDeclared) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("addPortDup", portQName.toString()));
} else if (endpointDescription == null) {
// Use the SEI Class and its annotations to finish creating the Description hierarchy. Note that EndpointInterface, Operations, Parameters, etc.
// are not created for dynamic ports. It would be an error to later do a getPort against a dynamic port (per the JAX-WS spec)
// If we can't add the dynamic port under a specific service delegate, that is an error
if (serviceDelegateKey == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("serviceDescriptionImplAddPortErr"));
}
endpointDescription = createEndpointDescriptionImpl(sei, portQName, bindingId, endpointAddress);
addDynamicEndpointDescriptionImpl(endpointDescription, serviceDelegateKey);
} else {
// All error chJeck above passed, the EndpointDescription already exists and needs no updating
}
break;
case GET_PORT:
// try to find existing endpointDesc by SEI class if portQName was not specified
if (endpointDescription == null && portQName == null && sei != null) {
endpointDescription = getEndpointDescriptionImpl(sei);
}
// If an endpointDesc doesn't exist, and the port exists in the WSDL, create it
// If an endpointDesc already exists and has an associated SEI already, make sure they match
// If an endpointDesc already exists and was created for Dispatch (no SEI), update that with the SEI provided on the getPort
// Port must be declared (e.g. in WSDL or via annotations)
// TODO: Once isPortDeclared understands annotations and not just WSDL, the 2nd part of this check can possibly be removed.
// Although consider the check below that updates an existing EndpointDescritpion with an SEI.
if (!isPortDeclared ||
(endpointDescription != null && endpointDescription.isDynamicPort())) {
// This guards against the case where an addPort was done previously and now a getPort is done on it.
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("updateEPDescrErr1",(portQName != null ? portQName.toString() : "not specified")));
} else if (sei == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("updateEPDescrErr2",(portQName != null ? portQName.toString() : "not specified")));
} else if (endpointDescription == null) {
// Use the SEI Class and its annotations to finish creating the Description hierachy: Endpoint, EndpointInterface, Operations, Parameters, etc.
endpointDescription = new EndpointDescriptionImpl(sei, portQName, this, composite, serviceDelegateKey);
addEndpointDescription(endpointDescription);
/*
* We must reset the service runtime description after adding a new endpoint
* since the runtime description information could have references to old
* information. See MarshalServiceRuntimeDescriptionFactory and
* MarshalServiceRuntimeDescription.
*/
resetServiceRuntimeDescription();
} else
if (getEndpointSEI(portQName) == null && !endpointDescription.isDynamicPort()) {
// Existing endpointDesc from a declared port needs to be updated with an SEI.
// This could happen if the client first did a CREATE_DISPATCH on a declared
// port, which would cause it to be created, and then did a GET_PORT on the
// same port later, providing an SEI.
// Notes
// 1) An EndpointDescritption created from an addPort (i.e. a dynamic port) can
// not do this.
// 2) A sparse composite may be specified. We don't allow mixing JAX-WS unmanaged
// apis (CREATE_DISPATCH) with JSR-109 managed apis (GET_PORT with sparse
// composite metadata from a DD). Since the sparse composite is stored by
// a key AND CREATE_DISPATCH and ADD_PORT will thrown an exception of a composite
// is specified, having a composite and key on the GET_PORTs shouldn't be
// a problem.
endpointDescription.updateWithSEI(sei, composite, serviceDelegateKey);
} else if (getEndpointSEI(portQName) != sei) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("updateEPDescrErr3",portQName.toString(),
sei.getName(),getEndpointSEI(portQName).getName()));
} else {
// All error check above passed, the EndpointDescription already exists and needs no updating
// Just add the sparse composite if one was specified.
endpointDescription.getDescriptionBuilderComposite().setSparseComposite(serviceDelegateKey, composite);
}
break;
case CREATE_DISPATCH:
if (composite != null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("serviceDescErr6"));
}
// Port may or may not exist in WSDL.
// If an endpointDesc doesn't exist and it is in the WSDL, it can be created
// Otherwise, it is an error.
if (DescriptionUtils.isEmpty(portQName)) {
throw ExceptionFactory
.makeWebServiceException(Messages.getMessage("createDispatchFail0"));
} else if (endpointDescription != null) {
// The EndpointDescription already exists; nothing needs to be done
} else if (sei != null) {
// The Dispatch should not have an SEI associated with it on the update call.
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("createDispatchFail3",portQName.toString()));
} else if (getWSDLWrapper() != null && isPortDeclared) {
// EndpointDescription doesn't exist and this is a declared Port, so create one
// Use the SEI Class and its annotations to finish creating the Description hierarchy.
// Note that EndpointInterface, Operations, Parameters, etc. are not created for
// Dispatch-based ports, but might be updated later if a getPort is done against
// the same declared port.
endpointDescription = new EndpointDescriptionImpl(sei, portQName, this);
addEndpointDescription(endpointDescription);
} else {
// The port is not a declared port and it does not have an EndpointDescription,
// meaning an addPort has not been done for it
// This is an error.
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("createDispatchFail1", portQName.toString()));
}
break;
}
return endpointDescription;
}
private EndpointDescriptionImpl createEndpointDescriptionImpl(Class sei, QName portQName, String bindingId, String endpointAddress) {
if (log.isDebugEnabled()) {
log.debug("Calling createEndpointDescriptionImpl : ("
+ portQName + "," + bindingId + "," + endpointAddress + ")");
}
EndpointDescriptionImpl endpointDescription = null;
AxisConfiguration configuration = configContext.getAxisConfiguration();
if (log.isDebugEnabled()) {
log.debug("looking for " + JAXWS_DYNAMIC_ENDPOINTS + " in AxisConfiguration : " + configuration);
}
Parameter parameter = configuration.getParameter(JAXWS_DYNAMIC_ENDPOINTS);
HashMap cachedDescriptions = (HashMap)
((parameter == null) ? null : parameter.getValue());
if(cachedDescriptions == null) {
cachedDescriptions = new HashMap();
try {
configuration.addParameter(JAXWS_DYNAMIC_ENDPOINTS, cachedDescriptions);
} catch (AxisFault axisFault) {
throw new RuntimeException(axisFault);
}
if (log.isDebugEnabled()) {
log.debug("Added new instance of cachedDescriptions : " + cachedDescriptions);
}
} else {
if (log.isDebugEnabled()) {
log.debug("found old jaxws.dynamic.endpoints cache in AxisConfiguration (" + cachedDescriptions + ") with size : ("
+ cachedDescriptions.size() + ")");
}
}
StringBuffer key = new StringBuffer();
key.append(portQName == null ? "NULL" : portQName.toString());
key.append(':');
key.append(bindingId == null ? "NULL" : bindingId);
key.append(':');
key.append(endpointAddress == null ? "NULL" : endpointAddress);
synchronized(cachedDescriptions) {
WeakReference ref = (WeakReference) cachedDescriptions.get(key.toString());
if (ref != null) {
endpointDescription = (EndpointDescriptionImpl) ref.get();
}
}
if(endpointDescription == null) {
endpointDescription = new EndpointDescriptionImpl(sei, portQName, true, this);
synchronized(cachedDescriptions) {
if (log.isDebugEnabled()) {
log.debug("Calling cachedDescriptions.put : ("
+ key.toString() + ") : size - " + cachedDescriptions.size());
}
cachedDescriptions.put(key.toString(), new WeakReference(endpointDescription));
}
} else {
if (log.isDebugEnabled()) {
log.debug("found old entry for endpointDescription in jaxws.dynamic.endpoints cache : ("
+ cachedDescriptions.size() + ")");
}
}
return endpointDescription;
}
/**
* This method will get all properties that have been set on the DescriptionBuilderComposite
* instance. If the DBC represents an implementation class that references an SEI, the
* properties from the SEI will also be merged with the returned result.
*/
private Map<String, Object> getAllProps(DescriptionBuilderComposite dbc,
Map<String, DescriptionBuilderComposite> dbcMap) {
Map<String, Object> props = new HashMap<String, Object>();
// first get the properties from the DBC
if(dbc.getProperties() != null
&&
!dbc.getProperties().isEmpty()) {
props.putAll(dbc.getProperties());
}
// no need to continue if the 'dbcMap' is null
if(dbcMap != null) {
// now if this is a web service impl with an SEI, get the SEI props
if(dbc.getWebServiceAnnot() != null
&&
!DescriptionUtils.isEmpty(dbc.getWebServiceAnnot().endpointInterface())) {
DescriptionBuilderComposite seiDBC = dbcMap.get(dbc.getWebServiceAnnot().endpointInterface());
if(seiDBC != null
&&
seiDBC.getProperties() != null
&&
!seiDBC.getProperties().isEmpty()) {
props.putAll(seiDBC.getProperties());
}
}
}
return props;
}
private Class getEndpointSEI(QName portQName) {
Class endpointSEI = null;
EndpointDescription endpointDesc = getEndpointDescription(portQName);
if (endpointDesc != null) {
EndpointInterfaceDescription endpointInterfaceDesc =
endpointDesc.getEndpointInterfaceDescription();
if (endpointInterfaceDesc != null ) {
endpointSEI = endpointInterfaceDesc.getSEIClass();
}
}
return endpointSEI;
}
private boolean isPortDeclared(QName portQName) {
// TODO: This needs to account for declaration of the port via annotations in addition to just WSDL
// TODO: Add logic to check the portQN namespace against the WSDL Definition NS
boolean portIsDeclared = false;
if (!DescriptionUtils.isEmpty(portQName)) {
if (getWSDLWrapper() != null) {
Definition wsdlDefn = getWSDLWrapper().getDefinition();
Service wsdlService = wsdlDefn.getService(serviceQName);
Port wsdlPort = wsdlService.getPort(portQName.getLocalPart());
portIsDeclared = (wsdlPort != null);
} else {
// TODO: Add logic to determine if port is declared via annotations when no WSDL is present. For now, we have to assume it is declared
// so getPort(...) and createDispatch(...) calls work when there is no WSDL.
portIsDeclared = true;
}
} else {
// PortQName is null, so the runtime gets to choose which one to use. Since there's no WSDL
// we'll use annotations, so it is implicitly declared
portIsDeclared = true;
}
return portIsDeclared;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getEndpointDescriptions()
*/
public EndpointDescription[] getEndpointDescriptions() {
return definedEndpointDescriptions.values().toArray(new EndpointDescriptionImpl[0]);
}
public Collection<EndpointDescriptionImpl> getDynamicEndpointDescriptions_AsCollection(Object serviceDelegateKey) {
Collection <EndpointDescriptionImpl> dynamicEndpoints = null;
if (serviceDelegateKey != null ) {
if (dynamicEndpointDescriptions.get(serviceDelegateKey) != null)
dynamicEndpoints = dynamicEndpointDescriptions.get(serviceDelegateKey).values();
}
return dynamicEndpoints;
}
public Collection<EndpointDescription> getEndpointDescriptions_AsCollection() {
return definedEndpointDescriptions.values();
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getEndpointDescription(javax.xml.namespace.QName)
*/
public EndpointDescription getEndpointDescription(QName portQName) {
return getEndpointDescription(portQName, null);
}
public EndpointDescription getEndpointDescription(QName portQName, Object serviceDelegateKey) {
EndpointDescription returnDesc = null;
if (!DescriptionUtils.isEmpty(portQName)) {
returnDesc = definedEndpointDescriptions.get(portQName);
if (returnDesc == null && serviceDelegateKey != null) {
returnDesc = getDynamicEndpointDescriptionImpl(portQName, serviceDelegateKey);
}
}
return returnDesc;
}
EndpointDescriptionImpl getEndpointDescriptionImpl(QName portQName) {
return (EndpointDescriptionImpl)getEndpointDescription(portQName, null);
}
EndpointDescriptionImpl getEndpointDescriptionImpl(QName portQName, Object serviceDelegateKey) {
return (EndpointDescriptionImpl)getEndpointDescription(portQName);
}
EndpointDescriptionImpl getEndpointDescriptionImpl(Class seiClass) {
for (EndpointDescription endpointDescription : definedEndpointDescriptions.values()) {
EndpointInterfaceDescription endpointInterfaceDesc =
endpointDescription.getEndpointInterfaceDescription();
// Note that Dispatch endpoints will not have an endpointInterface because the do not have an associated SEI
if (endpointInterfaceDesc != null) {
Class endpointSEIClass = endpointInterfaceDesc.getSEIClass();
if (endpointSEIClass != null && endpointSEIClass.equals(seiClass)) {
return (EndpointDescriptionImpl)endpointDescription;
}
}
}
return null;
}
public DescriptionBuilderComposite getDescriptionBuilderComposite() {
return getDescriptionBuilderComposite(null, null);
}
/**
* This method provides a means for accessing a DescriptionBuilderComposite instance.
* If the integer value passed in is an index in the list of PortComposite objects,
* then the indiciated PortComposite will be returned. Otherwise, the instance DBC
* will be returned.
*/
public DescriptionBuilderComposite getDescriptionBuilderComposite(QName serviceQName,
Integer portCompositeIndex) {
DescriptionBuilderComposite dbc = null;
// if the service QName was specified let's attempt to get the correct
// PortComposite list
if(serviceQName != null
&&
composite.getServiceQNames() != null
&&
!composite.getServiceQNames().isEmpty()
&&
portCompositeIndex != null) {
List<PortComposite> pcList = composite.getPortComposites(serviceQName);
if(pcList != null) {
dbc = pcList.get(portCompositeIndex);
}
else {
dbc = composite;
}
}
// ignore null values or values that would cause an IndexOutOfBoundsException
else if(portCompositeIndex == null
||
composite.getPortComposites() == null
||
portCompositeIndex < 0
||
portCompositeIndex >= composite.getPortComposites().size()) {
dbc = composite;
}
// return the appropriate PortComposite instance
else {
if(log.isDebugEnabled()) {
log.debug("Returning PortComposite at index: " + portCompositeIndex +
" from ServiceDescriptionImpl: " + this.hashCode());
}
dbc = composite.getPortComposites().get(portCompositeIndex);
}
return dbc;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getEndpointDescription(java.lang.Class)
*/
public EndpointDescription[] getEndpointDescription(Class seiClass) {
EndpointDescription[] returnEndpointDesc = null;
ArrayList<EndpointDescriptionImpl> matchingEndpoints =
new ArrayList<EndpointDescriptionImpl>();
for (EndpointDescription endpointDescription : definedEndpointDescriptions.values()) {
EndpointInterfaceDescription endpointInterfaceDesc =
endpointDescription.getEndpointInterfaceDescription();
// Note that Dispatch endpoints will not have an endpointInterface because the do not have an associated SEI
if (endpointInterfaceDesc != null) {
Class endpointSEIClass = endpointInterfaceDesc.getSEIClass();
if (endpointSEIClass != null && endpointSEIClass.equals(seiClass)) {
matchingEndpoints.add((EndpointDescriptionImpl)endpointDescription);
}
}
}
if (matchingEndpoints.size() > 0) {
returnEndpointDesc = matchingEndpoints.toArray(new EndpointDescriptionImpl[0]);
}
return returnEndpointDesc;
}
// END of public accessor methods
/*=======================================================================*/
/*=======================================================================*/
private void addEndpointDescription(EndpointDescriptionImpl endpoint) {
definedEndpointDescriptions.put(endpoint.getPortQName(), endpoint);
}
private void setupWsdlDefinition() {
// Note that there may be no WSDL provided, for example when called from
// Service.create(QName serviceName).
if (log.isDebugEnabled()) {
log.debug("setupWsdlDefinition()");
}
if (composite.isServiceProvider()) {
// Currently, there is a bug which allows the wsdlDefinition to be placed
// on either the impl class composite or the sei composite, or both. We need to
// look in both places and find the correct one, if it exists.
if(serviceQName != null
&&
composite.getWsdlDefinition(serviceQName) != null) {
if(log.isDebugEnabled()) {
log.debug("Found WSDL definition by service QName");
}
Definition def = composite.getWsdlDefinition(serviceQName);
URL url = composite.getWsdlURL(serviceQName);
this.wsdlURL = url != null ? url.toString() : null;
try {
if (log.isDebugEnabled() ) {
if (configContext != null) {
log.debug("new WSDL4JWrapper-ConfigContext not null1");
} else {
log.debug("new WSDL4JWrapper-ConfigContext null1");
}
}
this.wsdlWrapper = new WSDL4JWrapper(url,
def,
configContext,
this.catalogManager);
} catch (WSDLException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("wsdlException", e.getMessage()), e);
}
}
else if (((composite.getWebServiceAnnot() != null) &&
DescriptionUtils.isEmpty(composite.getWebServiceAnnot().endpointInterface()))
||
(!(composite.getWebServiceProviderAnnot() == null))) {
//This is either an implicit SEI, or a WebService Provider
if (composite.getWsdlDefinition() != null) {
URL url = composite.getWsdlURL();
this.wsdlURL = url == null ? null : url.toString();
try {
if (log.isDebugEnabled() ) {
if (configContext != null) {
log.debug("new WSDL4JWrapper-ConfigContext not null1");
} else {
log.debug("new WSDL4JWrapper-ConfigContext null1");
}
}
this.wsdlWrapper = new WSDL4JWrapper(url,
composite.getWsdlDefinition(),
configContext,
this.catalogManager);
} catch (WSDLException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("wsdlException", e.getMessage()), e);
}
} else {
String wsdlLocation = null;
wsdlLocation = composite.getWebServiceAnnot() != null ? composite.getWebServiceAnnot().wsdlLocation() :
composite.getWebServiceProviderAnnot().wsdlLocation();
if(wsdlLocation != null
&&
!"".equals(wsdlLocation)) {
setWSDLDefinitionOnDBC(wsdlLocation);
}
}
} else if (composite.getWebServiceAnnot() != null) {
//This impl class specifies an SEI...this is a special case. There is a bug
//in the tooling that allows for the wsdllocation to be specifed on either the
//impl. class, or the SEI, or both. So, we need to look for the wsdl as follows:
// 1. If the Wsdl exists on the SEI, then check for it on the impl.
// 2. If it is not found in either location, in that order, then generate
DescriptionBuilderComposite seic =
getDBCMap().get(composite.getWebServiceAnnot().endpointInterface());
try {
if (seic == null) {
if (log.isDebugEnabled()) {
log.debug("The SEI class " + composite.getWebServiceAnnot().endpointInterface() + " was not found.");
}
}
if (seic != null && seic.getWsdlDefinition() != null) {
// set the wsdl def from the SEI composite
if (log.isDebugEnabled()) {
log.debug("Get the wsdl definition from the SEI composite.");
}
URL url = seic.getWsdlURL();
this.wsdlURL = url.toString();
if (log.isDebugEnabled() ) {
if (configContext != null) {
log.debug("new WSDL4JWrapper-ConfigContext not null2");
} else {
log.debug("new WSDL4JWrapper-ConfigContext null2");
}
}
this.wsdlWrapper =
new WSDL4JWrapper(seic.getWsdlURL(),
seic.getWsdlDefinition(),
configContext,
this.catalogManager);
} else if (composite.getWsdlDefinition() != null) {
//set the wsdl def from the impl. class composite
if (log.isDebugEnabled()) {
log.debug("Get the wsdl definition from the impl class composite.");
}
if (log.isDebugEnabled() ) {
if (configContext != null) {
log.debug("new WSDL4JWrapper-ConfigContext not null3");
} else {
log.debug("new WSDL4JWrapper-ConfigContext null3");
}
}
URL url = composite.getWsdlURL();
this.wsdlURL = url == null ? null : url.toString();
this.wsdlWrapper = new WSDL4JWrapper(composite.getWsdlURL(),
composite.getWsdlDefinition(),
configContext,
this.catalogManager);
} else {
String wsdlLocation = null;
// first check to see if the wsdlLocation is on the SEI
if(seic != null
&&
seic.getWebServiceAnnot() != null) {
if (log.isDebugEnabled()) {
log.debug("Get the wsdl location from the SEI composite.");
}
wsdlLocation = seic.getWebServiceAnnot().wsdlLocation();
}
// now check the impl
if(wsdlLocation == null
||
"".equals(wsdlLocation)) {
if (log.isDebugEnabled()) {
log.debug("Get the wsdl location from the impl class composite.");
}
wsdlLocation = composite.getWebServiceAnnot().wsdlLocation();
}
if(wsdlLocation != null
&&
!"".equals(wsdlLocation)) {
if (log.isDebugEnabled()) {
log.debug("wsdl location =" + wsdlLocation);
}
this.wsdlURL = wsdlLocation;
setWSDLDefinitionOnDBC(wsdlLocation);
}
}
} catch (WSDLException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("wsdlException", e.getMessage()), e);
}
}
//Deprecate this code block when MDQ is fully integrated
} else if (wsdlURL != null) {
try {
if (log.isDebugEnabled() ) {
if (configContext != null) {
log.debug("new WSDL4JWrapper-ConfigContext not null4");
} else {
log.debug("new WSDL4JWrapper-ConfigContext null4");
}
}
this.wsdlWrapper = new WSDL4JWrapper(new URL(this.wsdlURL),configContext,
this.catalogManager);
}
catch (FileNotFoundException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("wsdlNotFoundErr", e.getMessage()), e);
}
catch (UnknownHostException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("unknownHost", e.getMessage()), e);
}
catch (ConnectException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("connectionRefused", e.getMessage()), e);
}
catch(IOException e) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("urlStream", e.getMessage()), e);
}
catch (WSDLException e) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("wsdlException", e.getMessage()), e);
}
}
}
/**
* This method accepts a location of a WSDL document and attempts to
* load and set the WSDL definition on the DBC object.
* @param wsdlLocation
*/
private void setWSDLDefinitionOnDBC(String wsdlLocation) {
if(log.isDebugEnabled()) {
log.debug("Attempting to load WSDL file from location specified in annotation: " +
wsdlLocation);
}
if(composite.getClassLoader() == null) {
if(log.isDebugEnabled()) {
log.debug("A classloader could not be found for class: " + composite.
getClassName() + ". The WSDL file: " + wsdlLocation + " will not be " +
"processed, and the ServiceDescription will be built from " +
"annotations");
}
}
try {
if(log.isDebugEnabled()) {
log.debug("Attempting to read WSDL: " + wsdlLocation + " for web " +
"service endpoint: " + composite.getClassName());
}
if (log.isDebugEnabled() ) {
if (configContext != null) {
log.debug("new WSDL4JWrapper-ConfigContext not null5");
} else {
log.debug("new WSDL4JWrapper-ConfigContext null5");
}
}
URL url = getWSDLURL(wsdlLocation);
ConfigurationContext cc = composite.getConfigurationContext();
if (cc != null) {
this.wsdlWrapper = new WSDL4JWrapper(url, cc, this.catalogManager);
} else {
// Probably shouldn't get here. But if we do, use a memory sensitive
// wsdl wrapper
this.wsdlWrapper = new WSDL4JWrapper(url, this.catalogManager, true, 2);
}
composite.setWsdlDefinition(wsdlWrapper.getDefinition());
}
catch(Exception e) {
if(log.isDebugEnabled()) {
log.debug("The WSDL file: " + wsdlLocation + " for class: " + composite.getClassName() +
"could not be processed. The ServiceDescription will be built from " +
"annotations");
}
}
}
/**
* This method will handle obtaining a URL for the given WSDL location. The WSDL will be
* looked for in the following places in this order:
*
* PreResolution) check for xmlcatalog resolver
* 1) As a resource on the classpath
* 2) As a fully specified URL
* 3) As a file on the filesystem. This is analagous to what the generated
* Service client does. Is prepends "file:/" to whatever is specified in the
* @WebServiceClient.wsdlLocation element.
*
* @param wsdlLocation The WSDL for which a URL is wanted
* @return A URL if the WSDL can be located, or null
*/
private URL getWSDLURL(String wsdlLocation) {
// Look for the WSDL file as follows:
// PreResolution) check for xmlcatalog resolver
wsdlLocation = resolveWSDLLocationByCatalog(wsdlLocation);
// 1) As a resource on the classpath
ClassLoader loader = composite.getClassLoader();
URL url = null;
if (loader != null) {
url = getResource(wsdlLocation, loader);
}
// Try the context class loader
if(url == null){
ClassLoader classLoader = getContextClassLoader(null);
if(classLoader != loader){
url = getResource(wsdlLocation, classLoader);
}
}
// 2) As a fully specified URL
if (url == null) {
if (log.isDebugEnabled()) {
log.debug("URL for wsdl file: " + wsdlLocation + " could not be "
+ "determined by classloader... looking for file reference");
}
url = createWsdlURL(wsdlLocation);
}
// 3) As a file on the filesystem. This is analagous to what the generated
// Service client does. Is prepends "file:/" to whatever is specified in the
// @WebServiceClient.wsdlLocation element.
if (url == null) {
if (log.isDebugEnabled()) {
log.debug("URL for wsdl file: " + wsdlLocation + " could not be "
+ "found as local file reference... prepending file: protocol");
}
// This check is necessary because Unix/Linux file paths begin
// with a '/'. When adding the prefix 'jar:file:/' we may end
// up with '//' after the 'file:' part. This causes the URL
// object to treat this like a remote resource
if(wsdlLocation.indexOf("/") == 0) {
wsdlLocation = wsdlLocation.substring(1, wsdlLocation.length());
}
url = createWsdlURL("file:/" + wsdlLocation);
}
if (url == null) {
if (log.isDebugEnabled()) {
log.debug("Unable to obtain URL for WSDL file: " + wsdlLocation
+ " by using prepended file: protocol");
}
}
return url;
}
private URL getResource(final String wsdlLocation, final ClassLoader loader) {
return (URL) AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return loader.getResource(wsdlLocation);
}
}
);
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescriptionWSDL#getWSDLWrapper()
*/
public WSDLWrapper getWSDLWrapper() {
return wsdlWrapper;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescriptionWSDL#getWSDLLocation()
*/
public String getWSDLLocation() {
return wsdlURL;
}
public WSDLWrapper getGeneratedWsdlWrapper() {
return this.generatedWsdlWrapper;
}
void setAxisConfigContext(ConfigurationContext config) {
this.configContext = config;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getAxisConfigContext()
*/
public ConfigurationContext getAxisConfigContext() {
if (configContext == null) {
configContext = getClientConfigurationFactory().getClientConfigurationContext();
}
return configContext;
}
ClientConfigurationFactory getClientConfigurationFactory() {
if (clientConfigFactory == null) {
clientConfigFactory = DescriptionFactory.createClientConfigurationFactory();
}
return clientConfigFactory;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getServiceClient(javax.xml.namespace.QName)
*/
public ServiceClient getServiceClient(QName portQName, Object serviceDelegateKey) {
ServiceClient returnServiceClient = null;
if (!DescriptionUtils.isEmpty(portQName)) {
EndpointDescription endpointDesc = getEndpointDescription(portQName, serviceDelegateKey);
if (endpointDesc != null) {
returnServiceClient = endpointDesc.getServiceClient();
}
else {
// Couldn't find Endpoint Description for port QName
if (log.isDebugEnabled()) {
log.debug("Could not find portQName: " + portQName
+ " under ServiceDescription: " + toString());
}
}
}
else {
// PortQName is empty
if (log.isDebugEnabled()) {
log.debug("PortQName agrument is invalid; it can not be null or an empty string: " + portQName);
}
}
return returnServiceClient;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getServiceQName()
*/
public QName getServiceQName() {
//It is assumed that this will always be set in the constructor rather than
//built up from the class or DBC
return serviceQName;
}
void setServiceQName(QName theName) {
serviceQName = theName;
}
public JAXWSCatalogManager getCatalogManager() {
return catalogManager;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#isMTOMEnabled(java.lang.Object)
*/
public boolean isMTOMEnabled(Object key) {
return getDescriptionBuilderComposite().isMTOMEnabled(key);
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#isMTOMEnabled(java.lang.Object, Class seiClass)
*/
public boolean isMTOMEnabled(Object key, Class seiClass) {
if(log.isDebugEnabled()) {
log.debug("isMTOMEnabled, key= " + key + ", seiClass= " + seiClass);
}
boolean mtomEnabled = false;
DescriptionBuilderComposite sparseComposite = getDescriptionBuilderComposite().getSparseComposite(key);
if(sparseComposite != null
&&
seiClass != null) {
Map<String, Boolean> seiToMTOM = (Map<String, Boolean>)
sparseComposite.getProperties().get(MDQConstants.SEI_MTOM_ENABLEMENT_MAP);
if(seiToMTOM != null
&&
seiToMTOM.get(seiClass.getName()) != null) {
mtomEnabled = seiToMTOM.get(seiClass.getName());
}
else {
mtomEnabled = isMTOMEnabled(key);
}
}
else {
mtomEnabled = isMTOMEnabled(key);
}
if(log.isDebugEnabled()) {
log.debug("isMTOMEnabled, key= " + key + ", seiClass= " + seiClass + ", isMTOMEnabled= " + mtomEnabled);
}
return mtomEnabled;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getBindingProperites(java.lang.Object, String key)
*/
public Map<String, Object> getBindingProperties(Object serviceDelegateKey, String key) {
if(log.isDebugEnabled()) {
log.debug("getBindingProperties, serviceDelegateKey= " + serviceDelegateKey +
", key= " + key);
}
Map<String, Object> bindingProps = null;
DescriptionBuilderComposite sparseComposite = getDescriptionBuilderComposite().getSparseComposite(serviceDelegateKey);
if(sparseComposite != null) {
Map<String, Map<String, Object>> allBindingProps = (Map<String, Map<String, Object>>)
sparseComposite.getProperties().get(MDQConstants.BINDING_PROPS_MAP);
bindingProps = allBindingProps != null ? (Map<String, Object>) allBindingProps.get(key) : null;
}
if(log.isDebugEnabled()) {
log.debug("getBindingProperties, serviceDelegateKey= " + serviceDelegateKey +
", key= " + key + ", propsSize= " + (bindingProps != null ? bindingProps.size() : 0));
}
return bindingProps;
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getPreferredPort(java.lang.Object)
*/
public QName getPreferredPort(Object key) {
return getDescriptionBuilderComposite().getPreferredPort(key);
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#isServerSide()
*/
public boolean isServerSide() {
return isServerSide;
}
HashMap<String, DescriptionBuilderComposite> getDBCMap() {
return dbcMap;
}
void setGeneratedWsdlWrapper(WSDL4JWrapper wrapper) {
this.generatedWsdlWrapper = wrapper;
}
void setWsdlWrapper(WSDL4JWrapper wrapper) {
this.wsdlWrapper = wrapper;
}
private void validateDBCLIntegrity() {
//First, check the integrity of this input composite
//and retrieve
//the composite that represents this impl
try {
validateIntegrity();
}
catch (Exception ex) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("dbclIntegrityErr",ex.toString(),composite.toString()), ex);
}
}
/*
* Validates the integrity of an impl. class. This should not be called directly for an SEI composite
*/
void validateIntegrity() {
//In General, this integrity checker should do gross level checking
//It should not be setting spec-defined default values, but can look
//at things like empty strings or null values
//Verify that, if this implements a strongly typed provider interface, that it
// also contain a WebServiceProvider annotation per JAXWS Sec. 5.1
Iterator<String> iter =
composite.getInterfacesList().iterator();
// Remember if we've validated the Provider interface. Later we'll make sure that if we have an
// WebServiceProvider annotation, we found a valid interface here.
boolean providerInterfaceValid = false;
while (iter.hasNext()) {
String interfaceString = iter.next();
if (interfaceString.equals(MDQConstants.PROVIDER_SOURCE)
|| interfaceString.equals(MDQConstants.PROVIDER_SOAP)
|| interfaceString.equals(MDQConstants.PROVIDER_DATASOURCE)
|| interfaceString.equals(MDQConstants.PROVIDER_STRING)
|| interfaceString.equals(MDQConstants.PROVIDER_OMELEMENT)) {
providerInterfaceValid = true;
//This is a provider based endpoint, make sure the annotation exists
if (composite.getWebServiceProviderAnnot() == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr1",composite.getClassName()));
}
}
}
//Verify that WebService and WebServiceProvider are not both specified
//per JAXWS - Sec. 7.7
if (composite.getWebServiceAnnot() != null &&
composite.getWebServiceProviderAnnot() != null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr2",composite.getClassName()));
}
if (composite.getWebServiceProviderAnnot() != null) {
if (!providerInterfaceValid) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr3",composite.getClassName()));
}
// There must be a public default constructor per JAXWS - Sec 5.1
if (!validateDefaultConstructor()) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr4",composite.getClassName()));
}
// There must be an invoke method per JAXWS - Sec 5.1.1
if (!validateInvokeMethod()) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr5",composite.getClassName()));
}
//If ServiceMode annotation specifies 'payload', then make sure that it is not typed with
// SOAPMessage or DataSource
validateProviderInterfaces();
} else if (composite.getWebServiceAnnot() != null) {
if (composite.getServiceModeAnnot() != null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr6",composite.getClassName()));
}
if (!composite.isInterface()) {
// TODO: Validate on the class that this.classModifiers Array does not contain the strings
// FINAL or ABSTRACT, but does contain PUBLIC
// TODO: Validate on the class that a public constructor exists
// TODO: Validate on the class that a finalize() method does not exist
if (!DescriptionUtils.isEmpty(composite.getWebServiceAnnot().wsdlLocation())) {
if (composite.getWsdlDefinition(getServiceQName()) == null
&&
composite.getWsdlDefinition() == null
&&
composite.getWsdlURL() == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr7",composite.getClassName(),
composite.getWebServiceAnnot().wsdlLocation()));
}
}
// setWebServiceAnnotDefaults(true=impl); Must happen before we start checking annot
if (!DescriptionUtils.isEmpty(composite.getWebServiceAnnot().endpointInterface())) {
DescriptionBuilderComposite seic =
dbcMap.get(composite.getWebServiceAnnot().endpointInterface());
//Verify that we can find the SEI in the composite list
if (seic == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr8",composite.getClassName(),
composite.getWebServiceAnnot().endpointInterface()));
}
// Verify that the only class annotations are WebService and HandlerChain
// (per JSR181 Sec. 3.1). Note that this applies to JSR-181 annotations; the restriction
// does not apply to JSR-224 annotations such as BindingType
if (composite.getSoapBindingAnnot() != null
|| composite.getWebFaultAnnot() != null
|| composite.getWebServiceClientAnnot() != null
) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr9",composite.getClassName()));
}
//Verify that WebService annotation does not contain a name attribute
//(per JSR181 Sec. 3.1)
if (!DescriptionUtils.isEmpty(composite.getWebServiceAnnot().name())) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr10",composite.getClassName(),
composite.getWebServiceAnnot().name()));
}
validateSEI(seic);
//Verify that that this implementation class implements all methods in the interface
validateImplementation(seic);
//Verify that this impl. class does not contain any @WebMethod annotations
if (webMethodAnnotationsExist()) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr11",composite.getClassName()));
}
} else { //this is an implicit SEI (i.e. impl w/out endpointInterface
checkImplicitSEIAgainstWSDL();
// TODO: Call ValidateWebMethodAnnots()
// - this method will check that all methods are public - ???
//
}
} else { //this is an interface...we should not be processing interfaces here
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr12",composite.getClassName()));
}
// Verify that the SOAPBinding annotations are supported.
if (composite.getSoapBindingAnnot() != null) {
if (composite.getSoapBindingAnnot().use() == javax.jws.soap.SOAPBinding.Use.ENCODED) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateIntegrityErr13",composite.getClassName()));
}
}
checkMethodsAgainstWSDL();
}
}
/**
* Validate there is an invoke method on the composite.
*
* @return
*/
private boolean validateInvokeMethod() {
boolean validInvokeMethod = false;
List<MethodDescriptionComposite> invokeMethodList =
composite.getMethodDescriptionComposite("invoke");
if (invokeMethodList != null && !invokeMethodList.isEmpty()) {
validInvokeMethod = true;
}
return validInvokeMethod;
}
/**
* Validate that, if using PAYLOAD mode, then interfaces list cannot contain SOAPMessage or
* DataSource
*
* @return
*/
private void validateProviderInterfaces() {
// Default for ServiceMode is 'PAYLOAD'. So, if it is specified (explicitly or
// implicitly) then verify that we are not implementing improper interfaces)
if ((composite.getServiceModeAnnot() == null)
|| composite.getServiceModeAnnot().value() == javax.xml.ws.Service.Mode.PAYLOAD) {
Iterator<String> iter = composite.getInterfacesList().iterator();
while (iter.hasNext()) {
String interfaceString = iter.next();
if (interfaceString.equals(MDQConstants.PROVIDER_SOAP)
|| interfaceString.equals(MDQConstants.PROVIDER_DATASOURCE)) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validatePIsErr1",composite.getClassName()));
}
}
} else {
// We are in MESSAGE mode
// Conformance: JAXWS Spec.- Sec. 4.3 (javax.activation.DataSource)
// REVIEW: Should the provider interface validation be moved to post-construction validation,
// since it seems that the logic to understand the default values for binding type
// (see comment below) should be left to the creation of the Description objects.
String bindingType = null;
if (composite.getBindingTypeAnnot() != null) {
bindingType = composite.getBindingTypeAnnot().value();
}
Iterator<String> iter = composite.getInterfacesList().iterator();
while (iter.hasNext()) {
String interfaceString = iter.next();
if (interfaceString.equals(MDQConstants.PROVIDER_SOAP)) {
// Make sure BindingType is SOAP/HTTP with SOAPMessage
// object, Default for Binding Type is SOAP/HTTP
if (!DescriptionUtils.isEmpty(bindingType)
&& !bindingType
.equals(SOAPBinding.SOAP11HTTP_BINDING)
&& !bindingType
.equals(SOAPBinding.SOAP11HTTP_MTOM_BINDING)
&& !bindingType
.equals(SOAPBinding.SOAP12HTTP_BINDING)
&& !bindingType
.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING)
&& !bindingType
.equals(MDQConstants.SOAP11JMS_BINDING)
&& !bindingType
.equals(MDQConstants.SOAP11JMS_MTOM_BINDING)
&& !bindingType
.equals(MDQConstants.SOAP12JMS_BINDING)
&& !bindingType
.equals(MDQConstants.SOAP12JMS_MTOM_BINDING)
&& !bindingType
.equals(MDQConstants.SOAP_HTTP_BINDING))
throw ExceptionFactory.makeWebServiceException(Messages
.getMessage("validatePIsErr2", composite
.getClassName()));
} else if (interfaceString
.equals(MDQConstants.PROVIDER_DATASOURCE)) {
// Make sure BindingType is XML/HTTP with DataSource object
if (DescriptionUtils.isEmpty(bindingType)
|| !bindingType
.equals(javax.xml.ws.http.HTTPBinding.HTTP_BINDING))
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validatePIsErr3",composite.getClassName()));
}
}
}
}
/**
* Validate there is a default no-argument constructor on the composite.
*
* @return
*/
private boolean validateDefaultConstructor() {
boolean validDefaultCtor = false;
List<MethodDescriptionComposite> constructorList =
composite.getMethodDescriptionComposite("<init>");
if (constructorList != null && !constructorList.isEmpty()) {
// There are public constructors; make sure there is one that takes no arguments.
for (MethodDescriptionComposite checkCtor : constructorList) {
List<ParameterDescriptionComposite> paramList =
checkCtor.getParameterDescriptionCompositeList();
if (paramList == null || paramList.isEmpty()) {
validDefaultCtor = true;
break;
}
}
}
return validDefaultCtor;
}
private void validateImplementation(DescriptionBuilderComposite seic) {
/*
* Verify that an impl class implements all the methods of the SEI. We have to verify this
* because an impl class is not required to actually use the 'implements' clause. So, if
* it doesn't, the Java compiler won't catch it. Don't need to worry about chaining
* because only one EndpointInterface can be specified, and the SEI cannot specify an
* EndpointInterface, so the Java compiler will take care of everything else.
*
* Note, however, that we do need to take overloaded methods into a consideration. The
* same method name can be specified for multiple methods, but they can have different
* parameters. Note that methods which differ only in the return type or the exceptions
* thrown are not overloaded (and therefore would cause a compile error).
*/
List<MethodDescriptionComposite> implMethods = composite.getMethodDescriptionsList();
// Add methods declared in the implementation's superclass
addSuperClassMethods(implMethods, composite);
List<MethodDescriptionComposite> seiMethods = seic.getMethodDescriptionsList();
// Add any methods declared in superinterfaces of the SEI
addSuperClassMethods(seiMethods, seic);
// Make sure all the methods in the SEI (including any inherited from superinterfaces) are
// implemented by the bean (including inherited methods on the bean), taking into
// account overloaded methods.
Iterator<MethodDescriptionComposite> verifySEIIterator = seiMethods.iterator();
while (verifySEIIterator.hasNext()) {
MethodDescriptionComposite seiMDC = verifySEIIterator.next();
// Make sure the implementation implements this SEI method. Since we have to account
// for method overloading, we look for ALL methods with the same name in the
// implementation, then from that collection of methods, we look for one that has the
// same parameters. If we find one with the same parameters, then we check the return
// and exceptions. Note that in Java, overloaded methods are ones that have the same
// name but different parameters; a difference in the return type or thrown exceptions
// does not constitute overloading and is a compile error.
Iterator<MethodDescriptionComposite> implMDCIterator = implMethods.iterator();
boolean methodImplFound = false;
while (implMDCIterator.hasNext()) {
MethodDescriptionComposite implMDC = implMDCIterator.next();
if (seiMDC.getMethodName().equals(implMDC.getMethodName())) {
// The method names match, so now check the parameters
try {
validateMethodParameters(seiMDC, implMDC, seic.getClassName());
methodImplFound = true;
}
catch (Exception ex) {
// The parameters didn't match, so we'll check the next
// implemntation method on the next iteration of the inner loop.
}
// If the name and the parameters matched, then we've found the method
// implementation, even if it was overloaded. Now check the return value and
// thrown exceptions. Note these will methods throw exceptions if validation fails.
// If all the validation passes, we can break out of the inner loop since we
// found the implementation for this sei method.
if (methodImplFound) {
validateMethodExceptions(seiMDC, implMDC, seic.getClassName());
validateMethodReturnValue(seiMDC, implMDC, seic.getClassName());
break;
}
}
}
if (!methodImplFound) {
// We didn't find the implementation for this SEI method, so throw a validation
// exception.
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateImplErr",composite.getClassName(),
seiMDC.getMethodName(),seic.getClassName()));
}
}
}
private void validateMethodParameters(MethodDescriptionComposite seiMDC,
MethodDescriptionComposite implMDC, String className) {
List<ParameterDescriptionComposite> seiPDCList = seiMDC
.getParameterDescriptionCompositeList();
List<ParameterDescriptionComposite> implPDCList = implMDC
.getParameterDescriptionCompositeList();
if ((seiPDCList == null || seiPDCList.isEmpty())
&& (implPDCList == null || implPDCList.isEmpty())) {
// There are no parameters on the SEI or the impl; all is well
} else if ((seiPDCList == null || seiPDCList.isEmpty())
&& !(implPDCList == null || implPDCList.isEmpty())) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodParamErr1",implPDCList.toString(),
composite.getClassName(),seiMDC.getMethodName(),className));
} else if ((seiPDCList != null && !seiPDCList.isEmpty())
&& !(implPDCList != null && !implPDCList.isEmpty())) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodParamErr2",seiPDCList.toString(),
composite.getClassName(),seiMDC.getMethodName(),className));
} else if (seiPDCList.size() != implPDCList.size()) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodParamErr3",
new Integer(seiPDCList.size()).toString(),
new Integer(implPDCList.size()).toString(),composite.getClassName(),
seiMDC.getMethodName(),className));
} else {
// Make sure the order and type of parameters match
// REVIEW: This checks for strict equality of the fully qualified
// type. It does not
// take into consideration object hierachy. For example foo(Animal)
// will not equal bar(Zebra)
boolean parametersMatch = true;
String failingMessage = null;
for (int paramNumber = 0; paramNumber < seiPDCList.size(); paramNumber++) {
String seiParamType = seiPDCList.get(paramNumber).getParameterType();
String implParamType = implPDCList.get(paramNumber).getParameterType();
if (!seiParamType.equals(implParamType)) {
parametersMatch = false;
String[] inserts = new String[] {
String.valueOf(paramNumber),
seiParamType,
implParamType,
composite.getClassName(),
seiMDC.getMethodName(),
className
};
failingMessage = Messages.getMessage("serviceDescriptionImplValidationErr",
inserts);
break;
}
}
if (!parametersMatch) {
throw ExceptionFactory.makeWebServiceException(failingMessage);
}
}
}
private void validateMethodReturnValue(MethodDescriptionComposite seiMDC,
MethodDescriptionComposite implMDC, String className) {
String seiReturnValue = seiMDC.getReturnType();
String implReturnValue = implMDC.getReturnType();
if (seiReturnValue == null && implReturnValue == null) {
// Neither specify a return value; all is well
} else if (seiReturnValue == null && implReturnValue != null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodRVErr1",implReturnValue,
composite.getClassName(),seiMDC.getMethodName(),className));
} else if (seiReturnValue != null && implReturnValue == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodRVErr2",seiReturnValue,
composite.getClassName(),seiMDC.getMethodName(),className));
} else if (!seiReturnValue.equals(implReturnValue)) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodRVErr3",seiReturnValue,implReturnValue,
composite.getClassName(),seiMDC.getMethodName(),className));
}
}
private void validateMethodExceptions ( MethodDescriptionComposite seiMDC,
MethodDescriptionComposite implMDC,
String className) {
String[] seiExceptions = seiMDC.getExceptions();
String[] implExceptions = implMDC.getExceptions();
// An impl can choose to throw fewer checked exceptions than declared on the SEI, but not more.
// This is analagous to the Java rules for interfaces.
if (seiExceptions == null) {
if (implExceptions == null) {
return;
} else {
// SEI delcares no checked exceptions, but the implementation has checked exceptions, which is an error
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodExceptionErr1",
composite.getClassName(),seiMDC.getMethodName(),className));
}
} else if (implExceptions == null) {
// Implementation throws fewer checked exceptions than SEI, which is OK.
return;
}
// Check the list length; An implementation can not declare more exceptions than the SEI
if (seiExceptions.length < implExceptions.length) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodExceptionErr2",
new Integer(implExceptions.length).toString(),
new Integer(seiExceptions.length).toString(),
composite.getClassName(),seiMDC.getMethodName(),className));
}
// Make sure that each checked exception declared by the
// implementation is on the SEI also
if (implExceptions.length > 0) {
for (String implException : implExceptions) {
boolean foundIt = false;
if (seiExceptions.length > 0) {
for (String seiException : seiExceptions) {
if (seiException.equals(implException)) {
foundIt = true;
break;
}
}
}
if (!foundIt) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateMethodExceptionErr3",implException,
composite.getClassName(),seiMDC.getMethodName(),className));
}
}
}
}
/**
* Adds any methods declared in superclasses to the List. The hierachy starting with the DBC
* will be walked up recursively, adding methods from each parent DBC encountered.
* <p/>
* Note that this can be used for either classes or interfaces.
*
* @param methodList The current collection of methods, including overloaded ones
* @param dbc The composite to be checked for methods to be added to the collection
*/
private void addSuperClassMethods(List<MethodDescriptionComposite> methodList, DescriptionBuilderComposite dbc) {
DescriptionBuilderComposite superDBC = dbcMap.get(dbc.getSuperClassName());
if (superDBC != null) {
Iterator<MethodDescriptionComposite> mIter = superDBC.getMethodDescriptionsList().iterator();
while (mIter.hasNext()) {
MethodDescriptionComposite mdc = mIter.next();
methodList.add(mdc);
}
addSuperClassMethods(methodList, superDBC);
}
}
/*
* This method verifies that, if there are any WebMethod with exclude == false, then
* make sure that we find all of those methods represented in the wsdl. However, if
* there are no exclusions == false, or there are no WebMethod annotations, then verify
* that all the public methods are in the wsdl
*/
private void checkMethodsAgainstWSDL() {
// Verify that, for ImplicitSEI, that all methods that should exist(if one false found, then
// only look for WebMethods w/ False, else take all public methods but ignore those with
// exclude == true
if (webMethodAnnotationsExist()) {
if (DescriptionUtils.falseExclusionsExist(composite))
verifyFalseExclusionsWithWSDL();
else
verifyPublicMethodsWithWSDL();
} else {
verifyPublicMethodsWithWSDL();
}
}
private void checkImplicitSEIAgainstWSDL() {
//TODO: If there is a WSDL, then verify that all WebMethods on this class and in the
// superclasses chain are represented in the WSDL...Look at logic below to make
// sure this really happening
if (webMethodAnnotationsExist()) {
if (DescriptionUtils.falseExclusionsExist(composite))
verifyFalseExclusionsWithWSDL();
else
verifyPublicMethodsWithWSDL();
} else {
verifyPublicMethodsWithWSDL();
}
}
private void checkSEIAgainstWSDL() {
//TODO: Place logic here to verify that each publicMethod with WebMethod annot
// is contained in the WSDL (If there is a WSDL) If we find
// a WebMethod annotation, use its values for looking in the WSDL
}
private void validateSEI(DescriptionBuilderComposite seic) {
if (seic.getWebServiceAnnot() == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateSEIErr1",composite.getClassName(),seic.getClassName()));
}
if (!seic.getWebServiceAnnot().endpointInterface().equals("")) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("validateSEIErr2",composite.getClassName(),
seic.getClassName(),seic.getWebServiceAnnot().endpointInterface()));
}
// Verify that the SOAPBinding annotations are supported.
if (seic.getSoapBindingAnnot() != null &&
seic.getSoapBindingAnnot().use() == javax.jws.soap.SOAPBinding.Use.ENCODED) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("validateSEIErr3",seic.getClassName()));
}
checkSEIAgainstWSDL();
//TODO: More validation here
//TODO: Make sure we don't find any WebMethod annotations with exclude == true
// anywhere in the superclasses chain
//TODO: Check that all WebMethod annotations in the superclass chain are represented in
// WSDL, assuming there is WSDL
//TODO: Validate that the interface is public
// Call ValidateWebMethodAnnots()
//
//This will perform validation for all methods, regardless of WebMethod annotations
//It is called for the SEI, and an impl. class that does not specify an endpointInterface
validateMethods(seic.getMethodDescriptionsList());
}
/** @return Returns TRUE if we find just one WebMethod Annotation */
private boolean webMethodAnnotationsExist() {
MethodDescriptionComposite mdc = null;
Iterator<MethodDescriptionComposite> iter =
composite.getMethodDescriptionsList().iterator();
while (iter.hasNext()) {
mdc = iter.next();
if (mdc.getWebMethodAnnot() != null)
return true;
}
return false;
}
private void verifyFalseExclusionsWithWSDL() {
//TODO: Place logic here to verify that each exclude==false WebMethod annot we find
// is contained in the WSDL
}
private void verifyPublicMethodsWithWSDL() {
//TODO: Place logic here to verify that each publicMethod with no WebMethod annot
// is contained in the WSDL
}
private void validateMethods(List<MethodDescriptionComposite> mdcList) {
if (mdcList != null && !mdcList.isEmpty()) {
for (MethodDescriptionComposite mdc : mdcList) {
String returnType = mdc.getReturnType();
if (returnType != null
&& (returnType.equals(RETURN_TYPE_FUTURE) || returnType
.equals(RETURN_TYPE_RESPONSE))) {
throw ExceptionFactory.makeWebServiceException(Messages
.getMessage("serverSideAsync", mdc.getDeclaringClass(), mdc
.getMethodName()));
}
// Verify that the SOAPBinding annotation values are supported.
if (mdc.getSoapBindingAnnot() != null) {
// For this JAXWS engine, SOAPBinding.Use = ENCODED is unsupported
if (mdc.getSoapBindingAnnot().use() == javax.jws.soap.SOAPBinding.Use.ENCODED) {
throw ExceptionFactory.
makeWebServiceException(Messages.getMessage("soapBindingUseEncoded",
mdc.getDeclaringClass(),
mdc.getMethodName()));
}
// Verify that, if a SOAPBinding annotation exists, that its style be set to
// only DOCUMENT JSR181-Sec 4.7.1
if (mdc.getSoapBindingAnnot().style() == javax.jws.soap.SOAPBinding.Style.RPC) {
throw ExceptionFactory.
makeWebServiceException(Messages.getMessage("soapBindingStyle",
mdc.getDeclaringClass(),
mdc.getMethodName()));
}
}
}
}
// TODO: Fill this out to validate all MethodDescriptionComposite (and
// their inclusive
// annotations on this SEI (SEI is assumed here)
//check oneway
//
//This could be an SEI, or an impl. class that doesn' specify an EndpointInterface (so, it
//is implicitly an SEI...need to consider this
//
//TODO: Verify that, if this is an interface...that there are no Methods with WebMethod
// annotations that contain exclude == true
//TODO: Verify that, if a SOAPBinding annotation exists, that its style be set to
// only DOCUMENT JSR181-Sec 4.7.1
}
private void validateWSDLOperations() {
//Verifies that all operations on the wsdl are found in the impl/sei class
}
public boolean isWSDLSpecified() {
boolean wsdlSpecified = false;
if (getWSDLWrapper() != null) {
wsdlSpecified = (getWSDLWrapper().getDefinition() != null);
}
return wsdlSpecified;
}
// ===========================================
// ANNOTATION: HandlerChain
// ===========================================
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getHandlerChain()
*/
public HandlerChainsType getHandlerChain() {
return getHandlerChain(null);
}
/* (non-Javadoc)
* @see org.apache.axis2.jaxws.description.ServiceDescription#getHandlerChain(java.lang.Object)
*/
public HandlerChainsType getHandlerChain(Object sparseCompositeKey) {
DescriptionBuilderComposite sparseComposite = null;
// If there is a HandlerChainsType in the sparse composite for this ServiceDelegate
// (i.e. this sparseCompositeKey), then return that.
if (sparseCompositeKey != null) {
sparseComposite = composite.getSparseComposite(sparseCompositeKey);
if (sparseComposite != null && sparseComposite.getHandlerChainsType() != null) {
return sparseComposite.getHandlerChainsType();
}
}
// If there is no HandlerChainsType in the composite, then read in the file specified
// on the HandlerChain annotation if it is present.
if (handlerChainsType == null) {
getAnnoHandlerChainAnnotation(sparseCompositeKey);
if (handlerChainAnnotation != null) {
String handlerFileName = handlerChainAnnotation.file();
if (log.isDebugEnabled()) {
log.debug("EndpointDescriptionImpl.getHandlerChain: fileName: "
+ handlerFileName + " className: " + composite.getClassName());
}
String className = composite.getClassName();
ClassLoader classLoader = composite.getClassLoader();
InputStream is =
DescriptionUtils.openHandlerConfigStream(handlerFileName,
className,
classLoader);
if (is == null) {
// config stream is still null. This may mean the @HandlerChain annotation is on a *driver* class
// next to a @WebServiceRef annotation, so the path is relative to the class declaring @HandlerChain
// and NOT relative to the Service or Endpoint class, which also means we should use the sparseComposite
// since that is where the @HandlerChain annotation info would have been loaded.
if (sparseComposite != null) {
String handlerChainDeclaringClass = (String)sparseComposite.getProperties().get(MDQConstants.HANDLER_CHAIN_DECLARING_CLASS);
if (handlerChainDeclaringClass != null) {
className = handlerChainDeclaringClass;
is = DescriptionUtils.openHandlerConfigStream(handlerFileName, className, classLoader);
}
}
}
if(is == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("handlerChainNS",
handlerFileName, className));
}
else {
handlerChainsType =
DescriptionUtils.loadHandlerChains(is,
getClassLoader(this.getClass()));
}
}
}
return handlerChainsType;
}
/*
* This is a client side only method. The generated service class may contain
* handler chain annotations
*/
public HandlerChain getAnnoHandlerChainAnnotation(Object sparseCompositeKey) {
if (this.handlerChainAnnotation == null) {
Class serviceClass = composite.getCorrespondingClass();
if (serviceClass != null) {
handlerChainAnnotation =
(HandlerChain) getAnnotation(serviceClass, HandlerChain.class);
}
}
if (handlerChainAnnotation == null) {
if (sparseCompositeKey != null) {
DescriptionBuilderComposite sparseComposite = composite.getSparseComposite(sparseCompositeKey);
if (sparseComposite != null && sparseComposite.getHandlerChainAnnot() != null) {
handlerChainAnnotation = sparseComposite.getHandlerChainAnnot();
}
}
}
return handlerChainAnnotation;
}
/* Returns the WSDL definiton as specified in the metadata. Note that this WSDL may not be
* complete.
*/
public Definition getWSDLDefinition() {
Definition defn = null;
if (getWSDLWrapper() != null) {
defn = getWSDLWrapper().getDefinition();
}
return defn;
}
/**
* Returns the WSDL definiton as created by calling the WSDL generator. This will be null
* unless the WSDL definition provided by the metadata is incomplete
*/
public Definition getWSDLGeneratedDefinition() {
Definition defn = null;
if (getGeneratedWsdlWrapper() != null) {
defn = getGeneratedWsdlWrapper().getDefinition();
}
return defn;
}
public Service getWSDLService() {
Service returnWSDLService = null;
Definition defn = getWSDLDefinition();
if (defn != null) {
returnWSDLService = defn.getService(getServiceQName());
}
return returnWSDLService;
}
public Map getWSDLPorts() {
Service wsdlService = getWSDLService();
if (wsdlService != null) {
return wsdlService.getPorts();
} else {
return null;
}
}
public List<QName> getPorts(Object serviceDelegateKey) {
ArrayList<QName> portList = new ArrayList<QName>();
// Note that we don't cache these results because the list of ports can be added
// to via getPort(...) and addPort(...).
// If the WSDL is specified, get the list of ports under this service
Map wsdlPortsMap = getWSDLPorts();
if (wsdlPortsMap != null) {
Iterator wsdlPortsIterator = wsdlPortsMap.values().iterator();
// Note that the WSDL Ports do not have a target namespace associated with them.
// JAXWS says to use the TNS from the Service.
String serviceTNS = getServiceQName().getNamespaceURI();
for (Port wsdlPort = null; wsdlPortsIterator.hasNext();) {
wsdlPort = (Port)wsdlPortsIterator.next();
String wsdlPortLocalPart = wsdlPort.getName();
portList.add(new QName(serviceTNS, wsdlPortLocalPart));
}
}
// Go through the list of Endpoints that have been created and add any
// not already in the list. This will include ports added to the Service
// via getPort(...) and addPort(...)
Collection<EndpointDescription> endpointDescs = getEndpointDescriptions_AsCollection();
for (EndpointDescription endpointDesc : endpointDescs) {
QName endpointPortQName = endpointDesc.getPortQName();
if (!portList.contains(endpointPortQName)) {
portList.add(endpointPortQName);
}
}
//Retrieve all the dynamic ports for this client
if (serviceDelegateKey != null) {
Collection<EndpointDescriptionImpl> dynamicEndpointDescs = getDynamicEndpointDescriptions_AsCollection(serviceDelegateKey);
if (dynamicEndpointDescs != null) {
for (EndpointDescription dynamicEndpointDesc : dynamicEndpointDescs) {
QName endpointPortQName = dynamicEndpointDesc
.getPortQName();
if (!portList.contains(endpointPortQName)) {
portList.add(endpointPortQName);
}
}
}
}
return portList;
}
public List<Port> getWSDLPortsUsingPortType(QName portTypeQN) {
ArrayList<Port> portList = new ArrayList<Port>();
if (!DescriptionUtils.isEmpty(portTypeQN)) {
Map wsdlPortMap = getWSDLPorts();
if (wsdlPortMap != null && !wsdlPortMap.isEmpty()) {
for (Object mapElement : wsdlPortMap.values()) {
Port wsdlPort = (Port)mapElement;
PortType wsdlPortType = wsdlPort.getBinding().getPortType();
QName wsdlPortTypeQN = wsdlPortType.getQName();
if (portTypeQN.equals(wsdlPortTypeQN)) {
portList.add(wsdlPort);
}
}
}
}
return portList;
}
public List<Port> getWSDLPortsUsingSOAPAddress(List<Port> wsdlPorts) {
ArrayList<Port> portsUsingAddress = new ArrayList<Port>();
if (wsdlPorts != null && !wsdlPorts.isEmpty()) {
for (Port checkPort : wsdlPorts) {
List extensibilityElementList = checkPort.getExtensibilityElements();
for (Object checkElement : extensibilityElementList) {
if (EndpointDescriptionImpl
.isSOAPAddressElement((ExtensibilityElement)checkElement)) {
portsUsingAddress.add(checkPort);
}
}
}
}
return portsUsingAddress;
}
public ServiceRuntimeDescription getServiceRuntimeDesc(String name) {
return runtimeDescMap.get(name);
}
public void setServiceRuntimeDesc(ServiceRuntimeDescription srd) {
runtimeDescMap.put(srd.getKey(), srd);
}
private void resetServiceRuntimeDescription() {
runtimeDescMap.clear();
}
/**
* Return the name of the client-side service class if it exists.
*/
protected String getServiceClassName() {
return composite.getClassName();
}
private EndpointDescriptionImpl getDynamicEndpointDescriptionImpl(QName portQName, Object key) {
Map<QName, EndpointDescriptionImpl> innerMap = null;
synchronized(dynamicEndpointDescriptions) {
innerMap = dynamicEndpointDescriptions.get(key);
if (innerMap != null) {
return innerMap.get(portQName);
}
}
return null;
}
private void addDynamicEndpointDescriptionImpl(EndpointDescriptionImpl endpointDescriptionImpl,
Object key) {
Map<QName, EndpointDescriptionImpl> innerMap = null;
synchronized(dynamicEndpointDescriptions) {
innerMap = dynamicEndpointDescriptions.get(key);
if (innerMap == null) {
innerMap = new HashMap<QName, EndpointDescriptionImpl>();
dynamicEndpointDescriptions.put(key, innerMap);
}
innerMap.put(endpointDescriptionImpl.getPortQName(), endpointDescriptionImpl);
}
}
/** Return a string representing this Description object and all the objects it contains. */
public String toString() {
final String newline = "\n";
final String sameline = "; ";
// This produces a TREMENDOUS amount of output if we have the WSDL Definition objects
// do a toString on themselves.
boolean dumpWSDLContents = false;
StringBuffer string = new StringBuffer();
try {
// Basic information
string.append(super.toString());
string.append(newline);
string.append("ServiceQName: " + getServiceQName());
// WSDL information
string.append(newline);
string.append("isWSDLSpecified: " + isWSDLSpecified());
string.append(sameline);
string.append("WSDL Location: " + getWSDLLocation());
string.append(newline);
if (dumpWSDLContents) {
string.append("WSDL Definition: " + getWSDLDefinition());
string.append(newline);
string.append("Generated WSDL Definition: " + getWSDLGeneratedDefinition());
} else {
string.append("WSDL Definition available: " + (getWSDLDefinition() != null));
string.append(sameline);
string.append("Generated WSDL Definition available: " +
(getWSDLGeneratedDefinition() != null));
}
// Ports
string.append(newline);
List<QName> ports = getPorts(null);
string.append("Number of defined ports: " + ports.size());
//TODO: Show the map that contains the dynamic ports
string.append(newline);
string.append("Port QNames: ");
for (QName port : ports) {
string.append(port + sameline);
}
// Axis Config information
// We don't print out the config context because it will force one to be created
// if it doesn't already exist.
// string.append(newline);
// string.append("ConfigurationContext: " + getAxisConfigContext());
// EndpointDescriptions
string.append(newline);
Collection<EndpointDescription> endpointDescs = getEndpointDescriptions_AsCollection();
if (endpointDescs == null) {
string.append("EndpointDescription array is null");
}
else {
string.append("Number of EndpointDescrptions: " + endpointDescs.size());
string.append(newline);
for (EndpointDescription endpointDesc : endpointDescs) {
string.append(endpointDesc.toString());
string.append(newline);
}
}
string.append("RuntimeDescriptions:" + this.runtimeDescMap.size());
string.append(newline);
for (ServiceRuntimeDescription runtimeDesc : runtimeDescMap.values()) {
string.append(runtimeDesc.toString());
string.append(newline);
}
}
catch (Throwable t) {
string.append(newline);
string.append("Complete debug information not currently available for " +
"ServiceDescription");
return string.toString();
}
return string.toString();
}
/**
* Get an annotation. This is wrappered to avoid a Java2Security violation.
* @param cls Class that contains annotation
* @param annotation Class of requrested Annotation
* @return annotation or null
*/
private static Annotation getAnnotation(final Class cls, final Class annotation) {
return (Annotation) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return cls.getAnnotation(annotation);
}
});
}
private static ClassLoader getContextClassLoader(final ClassLoader classLoader) {
ClassLoader cl;
try {
cl = (ClassLoader) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws ClassNotFoundException {
return classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader();
}
}
);
} catch (PrivilegedActionException e) {
if (log.isDebugEnabled()) {
log.debug("Exception thrown from AccessController: " + e.getMessage(), e);
}
throw ExceptionFactory.makeWebServiceException(e.getException());
}
return cl;
}
private static ClassLoader getClassLoader(final Class cls) {
ClassLoader cl = null;
try {
cl = (ClassLoader) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws ClassNotFoundException {
return cls.getClassLoader();
}
}
);
} catch (PrivilegedActionException e) {
if (log.isDebugEnabled()) {
log.debug("Exception thrown from AccessController: " + e);
}
throw ExceptionFactory.makeWebServiceException(e.getException());
}
return cl;
}
public void setResolvedHandlersDescription(PortInfo portInfo, ResolvedHandlersDescription resolvedHandlersInfo) {
// Get the cache and store the handler description
Map<PortInfo, ResolvedHandlersDescription> cache = resolvedHandlersDescription.get();
if (cache == null) {
cache = new ConcurrentHashMap<PortInfo, ResolvedHandlersDescription>();
resolvedHandlersDescription =
new SoftReference<Map<PortInfo, ResolvedHandlersDescription>>(cache);
}
cache.put(portInfo, resolvedHandlersInfo);
}
public ResolvedHandlersDescription getResolvedHandlersDescription(PortInfo portInfo) {
Map<PortInfo, ResolvedHandlersDescription> cache = resolvedHandlersDescription.get();
return (cache == null) ?
null: // No Cache
cache.get(portInfo);
}
private String resolveWSDLLocationByCatalog(String wsdlLocation) {
if (catalogManager != null) {
Catalog catalog = catalogManager.getCatalog();
if (catalog != null) {
String resolvedLocation = null;
try {
resolvedLocation = catalog.resolveSystem(wsdlLocation);
if (resolvedLocation == null) {
resolvedLocation = catalog.resolveURI(wsdlLocation);
}
// normally, one might also do the following, but in this case we're looking at a top-level WSDL, so no parent
// resolvedLocation = catalog.resolvePublic(wsdlLocation, parent);
if (resolvedLocation != null) {
if (log.isDebugEnabled()) {
log.debug("XMLCatalog transformed original wsdl location \""
+ wsdlLocation
+ "\" to \""
+ resolvedLocation + "\"");
}
return resolvedLocation;
}
} catch (Exception e) {
if (log.isDebugEnabled()) {
log.debug("Catalog resolution attempt caused exception: "
+ e);
}
}
}
}
return wsdlLocation;
}
/**
* Increment the use count for this ServiceDescription instance. Note the use count is
* only used on the client side.
* @return
*/
boolean isInUse() {
return useCount > 0;
}
/**
* Register that this ServiceDescription is being used by a service delegate instance. Note
* this is only used on the client side (since the service delegate is what is being
* registered).
*
* Note that this is package protected since only the implementation classes should be calling
* it.
*/
void registerUse() {
useCount++;
}
/**
* Deregister that this ServiceDescription is being used by a service delegate instance. Note
* this is only used on the client side (since the service delegate is what is being
* registered).
* Note that this is package protected since only the implementation classes should be calling
* it.
*/
void deregisterUse() {
if (useCount > 0) {
useCount--;
}
}
public void releaseResources(Object delegate) {
try {
if (log.isDebugEnabled()) {
log.debug("ServiceDescription release resources called with delegate " + delegate);
}
// If the service desc can be removed from the cache, which means no other service delegates
// are using it, then we will release the resources associated with it. If it can't be
// removed because it is still in use, then just return.
if (!DescriptionFactoryImpl.removeFromCache(this)) {
if (log.isDebugEnabled()) {
log.debug("ServiceDesc was not removed from cache, so it will not be released");
}
return;
}
if (log.isDebugEnabled()) {
log.debug("ServiceDesc was removed from cache, so releasing associated resources");
}
// Close all the endpoint descs, both declared and dynamic
Collection<EndpointDescription> definedEndpoints = definedEndpointDescriptions.values();
if (definedEndpoints.size() > 0) {
if (log.isDebugEnabled()) {
log.debug("Releasing defined endpoints, size: " + definedEndpoints.size());
}
for (EndpointDescription endpointDesc : definedEndpoints) {
((EndpointDescriptionImpl) endpointDesc).releaseResources(getAxisConfigContext());
}
}
definedEndpointDescriptions.clear();
Collection<Map<QName, EndpointDescriptionImpl>> dynamicEndpointsMap =
dynamicEndpointDescriptions.values();
if (log.isDebugEnabled()) {
log.debug("Releasing dynamic endpoints, size: " + dynamicEndpointsMap.size());
}
Iterator<Map<QName, EndpointDescriptionImpl>> dynamicEndpointsMapIterator = dynamicEndpointsMap.iterator();
while (dynamicEndpointsMapIterator.hasNext()) {
Map<QName, EndpointDescriptionImpl> mapEntry = dynamicEndpointsMapIterator.next();
Collection<EndpointDescriptionImpl> dynamicEndpoints = mapEntry.values();
if (dynamicEndpoints != null && dynamicEndpoints.size() > 0) {
for (EndpointDescription endpointDesc : dynamicEndpoints) {
((EndpointDescriptionImpl) endpointDesc).releaseResources(getAxisConfigContext());
// Remove this endpoint from the list on axis config
removeFromDynamicEndpointCache(endpointDesc);
}
}
}
dynamicEndpointDescriptions.clear();
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug("Release resorces in ServiceDesc caught throwable ", t);
}
throw ExceptionFactory.makeWebServiceException(t);
}
}
/**
* Remove the endpointDescription from the list of dynamic ports held on the
* AxisConfiguration object.
*
* @param endpointDesc The endpointDescription to be removed from the list.
*/
private void removeFromDynamicEndpointCache(EndpointDescription endpointDesc) {
AxisConfiguration configuration = configContext.getAxisConfiguration();
Parameter parameter = configuration.getParameter(JAXWS_DYNAMIC_ENDPOINTS);
HashMap cachedDescriptions = (HashMap)
((parameter == null) ? null : parameter.getValue());
if (cachedDescriptions != null) {
synchronized(cachedDescriptions) {
Set cachedDescSet = cachedDescriptions.entrySet();
Iterator cachedDescIterator = cachedDescSet.iterator();
while (cachedDescIterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) cachedDescIterator.next();
WeakReference weakRef = (WeakReference) mapEntry.getValue();
if (weakRef != null) {
EndpointDescriptionImpl checkDynamicEndpointDesc = (EndpointDescriptionImpl) weakRef.get();
if (endpointDesc == checkDynamicEndpointDesc) {
cachedDescIterator.remove();
if (log.isDebugEnabled()) {
log.debug("Removing endpoint desc from dynamic cache on configuration");
}
}
}
}
}
}
}
}