blob: ea3934e3ec902c7957bee41a29def68f543d2e51 [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;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.jaxws.addressing.util.EndpointReferenceUtils;
import org.apache.axis2.jaxws.binding.BindingUtils;
import org.apache.axis2.jaxws.binding.SOAPBinding;
import org.apache.axis2.jaxws.client.PropertyValidator;
import org.apache.axis2.jaxws.core.InvocationContext;
import org.apache.axis2.jaxws.core.MessageContext;
import org.apache.axis2.jaxws.description.EndpointDescription;
import org.apache.axis2.jaxws.description.ServiceDescriptionWSDL;
import org.apache.axis2.jaxws.handler.HandlerResolverImpl;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.spi.ServiceDelegate;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.xml.namespace.QName;
import javax.xml.ws.Binding;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.WebServiceException;
import javax.xml.ws.WebServiceFeature;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.wsaddressing.W3CEndpointReference;
import java.util.Hashtable;
import java.util.Map;
public class BindingProvider implements org.apache.axis2.jaxws.spi.BindingProvider {
private static final Log log = LogFactory.getLog(BindingProvider.class);
protected Map<String, Object> requestContext;
protected Map<String, Object> responseContext;
protected EndpointDescription endpointDesc;
protected ServiceDelegate serviceDelegate;
private org.apache.axis2.jaxws.spi.Binding binding;
public BindingProvider(ServiceDelegate svcDelegate,
EndpointDescription epDesc,
org.apache.axis2.addressing.EndpointReference epr,
String addressingNamespace,
WebServiceFeature... features) {
this.endpointDesc = epDesc;
this.serviceDelegate = svcDelegate;
initialize(epr, addressingNamespace, features);
}
/*
* Initialize any objects needed by the BindingProvider
*/
private void initialize(org.apache.axis2.addressing.EndpointReference epr,
String addressingNamespace,
WebServiceFeature... features) {
requestContext = new ValidatingClientContext();
responseContext = new ValidatingClientContext();
// Setting standard property defaults for the request context
requestContext.put(BindingProvider.SESSION_MAINTAIN_PROPERTY, Boolean.FALSE);
requestContext.put(BindingProvider.SOAPACTION_USE_PROPERTY, Boolean.TRUE);
requestContext.put(AddressingConstants.DISABLE_ADDRESSING_FOR_OUT_MESSAGES, Boolean.TRUE);
// Set the endpoint address
String endpointAddress = (epr != null ) ? epr.getAddress() : endpointDesc.getEndpointAddress();
if (endpointAddress != null && !"".equals(endpointAddress)) {
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpointAddress);
}
// JAXWS 9.2.1.1 requires that we go ahead and create the binding object
// so we can also set the handlerchain
binding = (org.apache.axis2.jaxws.spi.Binding) BindingUtils.createBinding(endpointDesc);
if(log.isDebugEnabled()){
log.debug("Lookign for Handler Resolver");
}
// TODO should we allow the ServiceDelegate to figure out the default handlerresolver? Probably yes, since a client app may look for one there.
HandlerResolver handlerResolver = null;
if(serviceDelegate.getHandlerResolver() != null){
if(log.isDebugEnabled()){
log.debug("Reading default Handler Resolver ");
}
handlerResolver = serviceDelegate.getHandlerResolver();
}
else{
handlerResolver = new HandlerResolverImpl(endpointDesc.getServiceDescription(), serviceDelegate);
if(log.isDebugEnabled()){
log.debug("Creating new Handler Resolver using HandlerResolverImpl");
}
}
// See if the metadata from creating the service indicates that MTOM should be enabled
if (binding instanceof SOAPBinding) {
// MTOM can be enabled either at the ServiceDescription level (via the WSDL binding type) or
// at the EndpointDescription level via the binding type used to create a Dispatch.
boolean enableMTOMFromMetadata = false;
// if we have an SEI for the port, then we'll use it in order to search for MTOM configuration
if(endpointDesc.getEndpointInterfaceDescription() != null
&&
endpointDesc.getEndpointInterfaceDescription().getSEIClass() != null) {
enableMTOMFromMetadata = endpointDesc.getServiceDescription().isMTOMEnabled(serviceDelegate,
endpointDesc.getEndpointInterfaceDescription().getSEIClass());
}
else {
enableMTOMFromMetadata = endpointDesc.getServiceDescription().isMTOMEnabled(serviceDelegate);
}
if (!enableMTOMFromMetadata) {
String bindingType = endpointDesc.getClientBindingID();
enableMTOMFromMetadata = (bindingType.equals(SOAPBinding.SOAP11HTTP_MTOM_BINDING) ||
bindingType.equals(SOAPBinding.SOAP12HTTP_MTOM_BINDING));
}
if (enableMTOMFromMetadata) {
((SOAPBinding) binding).setMTOMEnabled(true);
}
}
// check for properties that need to be set on the BindingProvider
String seiName = null;
if(endpointDesc.getEndpointInterfaceDescription() != null
&&
endpointDesc.getEndpointInterfaceDescription().getSEIClass() != null) {
seiName = endpointDesc.getEndpointInterfaceDescription().getSEIClass().getName();
}
String portQNameString = endpointDesc.getPortQName().toString();
String key = seiName + ":" + portQNameString;
Map<String, Object> bProps = endpointDesc.getServiceDescription().getBindingProperties(serviceDelegate, key);
if(bProps != null) {
if(log.isDebugEnabled()) {
log.debug("Setting binding props with size: " + bProps.size() + " on " +
"BindingProvider RequestContext");
}
requestContext.putAll(bProps);
}
binding.setHandlerChain(handlerResolver.getHandlerChain(endpointDesc.getPortInfo()));
//Set JAX-WS 2.1 related properties.
try {
binding.setAxis2EndpointReference(epr);
binding.setAddressingNamespace(addressingNamespace);
binding.setFeatures(features);
}
catch (Exception e) {
throw ExceptionFactory.makeWebServiceException(e);
}
}
public ServiceDelegate getServiceDelegate() {
return serviceDelegate;
}
public EndpointDescription getEndpointDescription() {
return endpointDesc;
}
public Binding getBinding() {
return binding;
}
public Map<String, Object> getRequestContext() {
return requestContext;
}
public Map<String, Object> getResponseContext() {
return responseContext;
}
/**
* Check for maintain session state enablement either in the
* MessageContext.isMaintainSession() or in the ServiceContext properties.
*
* @param mc
* @param ic
*/
protected void checkMaintainSessionState(MessageContext mc, InvocationContext ic) {
Map<String, Object> properties = ic.getServiceClient().getServiceContext().getProperties();
boolean bValue = false;
if (properties != null
&& properties
.containsKey(javax.xml.ws.BindingProvider.SESSION_MAINTAIN_PROPERTY)) {
bValue = (Boolean) properties
.get(javax.xml.ws.BindingProvider.SESSION_MAINTAIN_PROPERTY);
}
if (mc.isMaintainSession() || bValue == true) {
setupSessionContext(properties);
}
}
/*
* Ensure that the next request context contains the session value returned
* from previous request
*/
protected void setupSessionContext(Map<String, Object> properties) {
String sessionKey = null;
Object sessionValue = null;
if (properties == null) {
throw ExceptionFactory.makeWebServiceException(Messages.getMessage("NoMaintainSessionProperty"));
} else if (properties.containsKey(HTTPConstants.HEADER_LOCATION)) {
sessionKey = HTTPConstants.HEADER_LOCATION;
sessionValue = properties.get(sessionKey);
if (sessionValue != null && !"".equals(sessionValue)) {
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, sessionValue);
}
} else if (properties.containsKey(HTTPConstants.HEADER_COOKIE)) {
sessionKey = HTTPConstants.HEADER_COOKIE;
sessionValue = properties.get(sessionKey);
if (sessionValue != null && !"".equals(sessionValue)) {
requestContext.put(HTTPConstants.COOKIE_STRING, sessionValue);
}
} else if (properties.containsKey(HTTPConstants.HEADER_COOKIE2)) {
sessionKey = HTTPConstants.HEADER_COOKIE2;
sessionValue = properties.get(sessionKey);
if (sessionValue != null && !"".equals(sessionValue)) {
requestContext.put(HTTPConstants.COOKIE_STRING, sessionValue);
}
} else {
throw ExceptionFactory
.makeWebServiceException(Messages.getMessage("NoMaintainSessionProperty"));
}
if (sessionValue == null) {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("NullValueForMaintainSessionProperty", sessionKey));
}
}
/**
* Returns a boolean value representing whether or not a SOAPAction header should be sent with
* the request.
*/
protected boolean useSoapAction() {
//TODO: Add some bit of validation for this property so that we know
// it is actually a Boolean and not a String.
Boolean use = (Boolean)requestContext.get(BindingProvider.SOAPACTION_USE_PROPERTY);
if (use != null) {
if (use.booleanValue()) {
return true;
} else {
return false;
}
} else {
// If the value is not set, then just default to sending a SOAPAction
return true;
}
}
/*
* (non-Javadoc)
* @see javax.xml.ws.BindingProvider#getEndpointReference()
*/
public EndpointReference getEndpointReference() {
return getEndpointReference(W3CEndpointReference.class);
}
/*
* (non-Javadoc)
* @see javax.xml.ws.BindingProvider#getEndpointReference(java.lang.Class)
*/
public <T extends EndpointReference> T getEndpointReference(Class<T> clazz) {
EndpointReference jaxwsEPR = null;
String addressingNamespace = EndpointReferenceUtils.getAddressingNamespace(clazz);
try {
org.apache.axis2.addressing.EndpointReference epr = binding.getAxis2EndpointReference();
if (epr == null) {
String address =
(String) requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
if (address == null)
address = endpointDesc.getEndpointAddress();
QName service = endpointDesc.getServiceQName();
QName port = endpointDesc.getPortQName();
String wsdlLocation = ((ServiceDescriptionWSDL) endpointDesc.getServiceDescription()).getWSDLLocation();
epr = EndpointReferenceUtils.createAxis2EndpointReference(address, service, port, wsdlLocation, addressingNamespace);
}
else if (!addressingNamespace.equals(binding.getAddressingNamespace())) {
throw ExceptionFactory.
makeWebServiceException(Messages.getMessage("bindingProviderErr1",
binding.getAddressingNamespace(),
addressingNamespace));
}
jaxwsEPR = EndpointReferenceUtils.convertFromAxis2(epr, addressingNamespace);
} catch (UnsupportedOperationException e) {
throw e;
} catch (WebServiceException e) {
throw e;
} catch (Exception e) {
throw ExceptionFactory.
makeWebServiceException(Messages.getMessage("endpointRefConstructionFailure3",
e.toString()));
}
return clazz.cast(jaxwsEPR);
}
/*
* An inner class used to validate properties as they are set by the client.
*/
class ValidatingClientContext extends Hashtable<String, Object> {
private static final long serialVersionUID = 3485112205801917858L;
@Override
public synchronized Object put(String key, Object value) {
// super.put rightly throws a NullPointerException if key or value is null, so don't continue if that's the case
if (value == null)
return null;
if (PropertyValidator.validate(key, value)) {
return super.put(key, value);
} else {
throw ExceptionFactory.makeWebServiceException(
Messages.getMessage("invalidPropValue", key, value.getClass().getName(),
PropertyValidator.getExpectedValue(key).getName()));
}
}
}
}