
com.legstar.proxy.invoke.jaxws.WebServiceInvoker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of legstar-distribution
Show all versions of legstar-distribution
Used to create a single distribution for the entire LegStar project.
The newest version!
/*******************************************************************************
* Copyright (c) 2010 LegSem.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser Public License v2.1
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
* Contributors:
* LegSem - initial API and implementation
******************************************************************************/
package com.legstar.proxy.invoke.jaxws;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.soap.Detail;
import javax.xml.soap.DetailEntry;
import javax.xml.soap.SOAPFault;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;
import javax.xml.ws.soap.SOAPFaultException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.legstar.coxb.util.JAXBAnnotationException;
import com.legstar.coxb.util.JAXBElementDescriptor;
import com.legstar.coxb.util.NameUtil;
import com.legstar.proxy.invoke.AbstractProxyInvoker;
import com.legstar.proxy.invoke.ProxyInvokerException;
import com.legstar.proxy.invoke.ReflectOperationProxy;
/**
* This provides a direct Web Service invoker via {@link java.xml.ws.Dispatch}.
*
* The class is immutable. All parameters are passed at construction time.
* Limitations:
*
* - SOAPBinding.SOAP11HTTP_BINDING there is no support for MTOM or SOAP 1.2
* - Service.Mode.PAYLOAD JAXB Objects are used to create the SOAP payload
* - No support for authentication against target Web Service
*
*
*/
public class WebServiceInvoker extends AbstractProxyInvoker {
/* ====================================================================== */
/* = Constants section = */
/* ====================================================================== */
/** URL locating target Web service WSDL. */
public static final String WSDL_URL_PROPERTY = "wsdlUrl";
/** Target Web service WSDL namespace. */
public static final String WSDL_TARGET_NAMESPACE_PROPERTY = "wsdlTargetNamespace";
/** Target Web service WSDL service name. */
public static final String WSDL_SERVICE_NAME_PROPERTY = "wsdlServiceName";
/** Target Web service WSDL port name. */
public static final String WSDL_PORT_NAME_PROPERTY = "wsdlPortName";
/* The following set of parameters is the same as ReflectOperationProxy */
/** Request JAXB type configuration parameter. */
public static final String REQUEST_JAXB_TYPE_PROPERTY = ReflectOperationProxy.REQUEST_JAXB_TYPE_PROPERTY;
/** Request JAXB package name configuration parameter. */
public static final String REQUEST_JAXB_PACKAGE_NAME_PROPERTY = ReflectOperationProxy.REQUEST_JAXB_PACKAGE_NAME_PROPERTY;
/** Response JAXB type. */
public static final String RESPONSE_JAXB_TYPE_PROPERTY = ReflectOperationProxy.RESPONSE_JAXB_TYPE_PROPERTY;
/** Response JAXB package name. */
public static final String RESPONSE_JAXB_PACKAGE_NAME_PROPERTY = ReflectOperationProxy.RESPONSE_JAXB_PACKAGE_NAME_PROPERTY;
/* ====================================================================== */
/* = Properties section = */
/* ====================================================================== */
/** The WSDL URL. */
private String mWsdlUrl;
/** The WSDL target namespace. */
private String mWsdlTargetNamespace;
/** The WSDL service name. */
private String mWsdlServiceName;
/** The WSDL port name. */
private String mWsdlPortName;
/** The request descriptor. */
private JAXBElementDescriptor mRequestElementDescriptor;
/** The response descriptor. */
private JAXBElementDescriptor mResponseElementDescriptor;
/**
* The dispatcher is thread safe starting with JAX-WS RI 2.1.2 provided we
* don't change the JAXB classes.
*/
private final Dispatch < Object > _dispatcher;
/** Logger. */
private final Log _log = LogFactory.getLog(getClass());
/**
* Standard constructor. The configuration parameters supported are:
*
* - wsdlUrl: Target web service wsdl URL
* - wsdlTargetNamespace: Target web service WSDL namespace
* - wsdlServiceName: Target web service name
* - wsdlPortName: Target web service port name
* - requestJaxbType: JAXB request type
* - requestJaxbPackageName: JAXB request package name
* - responseJaxbType: JAXB response type
* - responseJaxbPackageName: JAXB response package name
*
*
* @param config configuration parameters
* @throws WebServiceInvokerException if configuration is wrong
*/
public WebServiceInvoker(final Map < String, String > config)
throws WebServiceInvokerException {
super(config);
mWsdlUrl = config.get(WSDL_URL_PROPERTY);
if (mWsdlUrl == null || mWsdlUrl.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a wsdl URL using the "
+ WSDL_URL_PROPERTY + " attribute");
}
mWsdlTargetNamespace = config.get(WSDL_TARGET_NAMESPACE_PROPERTY);
if (mWsdlTargetNamespace == null || mWsdlTargetNamespace.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a wsdl target namespace using the "
+ WSDL_TARGET_NAMESPACE_PROPERTY + " attribute");
}
mWsdlServiceName = config.get(WSDL_SERVICE_NAME_PROPERTY);
if (mWsdlServiceName == null || mWsdlServiceName.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a service name using the "
+ WSDL_SERVICE_NAME_PROPERTY + " attribute");
}
mWsdlPortName = config.get(WSDL_PORT_NAME_PROPERTY);
if (mWsdlPortName == null || mWsdlPortName.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a port name using the "
+ WSDL_PORT_NAME_PROPERTY + " attribute");
}
String requestJaxbType = config.get(REQUEST_JAXB_TYPE_PROPERTY);
if (requestJaxbType == null || requestJaxbType.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a jaxb request type using the "
+ REQUEST_JAXB_TYPE_PROPERTY + " attribute");
}
String requestJaxbPackageName = config
.get(REQUEST_JAXB_PACKAGE_NAME_PROPERTY);
if (requestJaxbPackageName == null
|| requestJaxbPackageName.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a jaxb request package name using the "
+ REQUEST_JAXB_PACKAGE_NAME_PROPERTY + " attribute");
}
String responseJaxbType = config.get(RESPONSE_JAXB_TYPE_PROPERTY);
if (responseJaxbType == null || responseJaxbType.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a jaxb response type using the "
+ RESPONSE_JAXB_TYPE_PROPERTY + " attribute");
}
String responseJaxbPackageName = config
.get(RESPONSE_JAXB_PACKAGE_NAME_PROPERTY);
if (responseJaxbPackageName == null
|| responseJaxbPackageName.length() == 0) {
throw new WebServiceInvokerException(
"You must specify a jaxb response package name using the "
+ RESPONSE_JAXB_PACKAGE_NAME_PROPERTY
+ " attribute");
}
try {
mRequestElementDescriptor = new JAXBElementDescriptor(
requestJaxbPackageName, requestJaxbType);
mResponseElementDescriptor = new JAXBElementDescriptor(
responseJaxbPackageName, responseJaxbType);
_dispatcher = createDispatcher();
} catch (JAXBAnnotationException e) {
throw new WebServiceInvokerException(e);
}
if (_log.isDebugEnabled()) {
_log.debug("WebServiceInvoker setup configuration:");
_log.debug("Wsdl Url=" + getWsdlUrl());
_log.debug("Wsdl service name=" + getWsdlServiceName());
_log.debug("Wsdl target namespace=" + getWsdlTargetNamespace());
_log.debug("Wsdl port=" + getWsdlPortName());
_log.debug("Request element=["
+ getRequestElementDescriptor().toString() + "]");
_log.debug("Response element=["
+ getResponseElementDescriptor().toString() + "]");
_log.debug("Dispatcher=[" + _dispatcher + "]");
}
}
/**
* {@inheritDoc}
*
* Had to synchronize because the JAX-WS RI dispatcher 2.1.3/2.1.4 is not
* threadsafe (@see WebServiceInvokerTest)
* */
@SuppressWarnings("unchecked")
public synchronized T invoke(final String requestID,
final Object oRequest) throws ProxyInvokerException {
if (_log.isDebugEnabled()) {
_log.debug("About to call invokeDispatch for service="
+ getWsdlServiceName() + " request ID=" + requestID);
}
Object replyObject = invokeDispatch(oRequest);
if (_log.isDebugEnabled()) {
_log.debug("Returned from invokeDispatch for service="
+ getWsdlServiceName() + " request ID=" + requestID);
}
return (T) replyObject;
}
/**
* @return a JAXBContext for request and response types
* @throws WebServiceInvokerException if JABContext cannot be created
*/
private JAXBContext createJAXBContext() throws WebServiceInvokerException {
try {
if (getResponseElementDescriptor().getJaxbPackageName().compareTo(
getRequestElementDescriptor().getJaxbPackageName()) == 0) {
return JAXBContext.newInstance(getRequestElementDescriptor()
.getObjectFactory().getClass());
} else {
return JAXBContext.newInstance(getRequestElementDescriptor()
.getObjectFactory().getClass(),
getResponseElementDescriptor().getObjectFactory()
.getClass());
}
} catch (JAXBException e) {
throw new WebServiceInvokerException(e);
}
}
/**
* Call the JAXWS dispatch method.
*
* The parameters passed to dispatch.invoke must have an XmlRootElement
* annotation or otherwise must be wrapped in a JAXBElement.
*
* Similarly, the reply could be wrapped in a JAXBElement in which case we
* return its inner content model.
*
* @param oRequest the request object
* @return the object response
* @throws WebServiceInvokerException if dispatch fails
*/
private Object invokeDispatch(final Object oRequest)
throws WebServiceInvokerException {
try {
Object oResponse;
if (getRequestElementDescriptor().isXmlRootElement()) {
oResponse = _dispatcher.invoke(oRequest);
} else {
JAXBElement < ? > jeRequest = getJAXBElement(
getRequestElementDescriptor().getObjectFactory(),
getRequestElementDescriptor().getElementName(),
oRequest);
oResponse = _dispatcher.invoke(jeRequest);
}
if (_log.isDebugEnabled()) {
_log.debug("invokeDispatch returned " + oResponse);
}
if (getResponseElementDescriptor().isXmlRootElement()) {
return oResponse;
} else {
return ((JAXBElement < ? >) oResponse).getValue();
}
} catch (SOAPFaultException e) {
throw new WebServiceInvokerException(getFaultReasonText(e), e);
}
}
/**
* Try to extract something meaningful from a SOAP Fault.
*
* @param e the SOAP Fault exception
* @return a fault description
*/
@SuppressWarnings("rawtypes")
public String getFaultReasonText(final SOAPFaultException e) {
if (_log.isDebugEnabled()) {
SOAPFault fault = e.getFault();
if (fault != null) {
QName code = fault.getFaultCodeAsQName();
String string = fault.getFaultString();
String actor = fault.getFaultActor();
_log.debug("SOAP fault contains: ");
_log.debug(" Fault code = " + code.toString());
_log.debug(" Local name = " + code.getLocalPart());
_log.debug(" Namespace prefix = " + code.getPrefix()
+ ", bound to " + code.getNamespaceURI());
_log.debug(" Fault string = " + string);
if (actor != null) {
_log.debug(" Fault actor = " + actor);
}
Detail detail = fault.getDetail();
if (detail != null) {
Iterator entries = detail.getDetailEntries();
while (entries.hasNext()) {
DetailEntry newEntry = (DetailEntry) entries.next();
String value = newEntry.getValue();
_log.debug(" Detail entry = " + value);
}
}
} else {
_log.debug(e);
}
}
SOAPFault fault = e.getFault();
if (fault != null) {
StringBuffer faultMessage = new StringBuffer(e.getFault()
.getFaultString());
Detail detail = fault.getDetail();
if (detail != null) {
Iterator entries = detail.getDetailEntries();
while (entries.hasNext()) {
DetailEntry newEntry = (DetailEntry) entries.next();
faultMessage.append(" [" + newEntry.getValue() + "]");
}
}
return faultMessage.toString();
} else {
return e.getMessage();
}
}
/**
* Creates a JAX-WS dispatcher.
*
* @return an instance of jaxws dynamic client invoker.
* @throws WebServiceInvokerException if attempt to instantiate dispatcher
* fails
*/
public Dispatch < Object > createDispatcher()
throws WebServiceInvokerException {
QName serviceQname = new QName(getWsdlTargetNamespace(),
getWsdlServiceName());
QName portQname = new QName(getWsdlTargetNamespace(), getWsdlPortName());
Service service = Service.create(serviceQname);
service.addPort(portQname, SOAPBinding.SOAP11HTTP_BINDING, getWsdlUrl());
Dispatch < Object > dispatcher = service.createDispatch(portQname,
createJAXBContext(), Service.Mode.PAYLOAD);
if (_log.isDebugEnabled()) {
_log.debug("New javax.xml.ws.Dispatch created for "
+ getWsdlServiceName());
}
return dispatcher;
}
/**
* Root elements can be created with special methods in the JAXB object
* factory. This method will use reflection to create a JAXBElement.
*
* @param objectFactory the JAXB object factory
* @param elementName the XML element name
* @param type an occurrence of the element type
* @return a JAXBElement
* @throws WebServiceInvokerException if the JAXBElement cannot be created
*/
private JAXBElement < ? > getJAXBElement(final Object objectFactory,
final String elementName, final Object type)
throws WebServiceInvokerException {
try {
String createName = "create" + NameUtil.toClassName(elementName);
Method creator = objectFactory.getClass().getMethod(createName,
type.getClass());
return (JAXBElement < ? >) creator.invoke(objectFactory, type);
} catch (IllegalAccessException e) {
throw new WebServiceInvokerException(e);
} catch (SecurityException e) {
throw new WebServiceInvokerException(e);
} catch (NoSuchMethodException e) {
throw new WebServiceInvokerException(e);
} catch (IllegalArgumentException e) {
throw new WebServiceInvokerException(e);
} catch (InvocationTargetException e) {
throw new WebServiceInvokerException(e);
}
}
/**
* @return the request element descriptor
*/
public JAXBElementDescriptor getRequestElementDescriptor() {
return mRequestElementDescriptor;
}
/**
* @return the response element descriptor
*/
public JAXBElementDescriptor getResponseElementDescriptor() {
return mResponseElementDescriptor;
}
/**
* @return the WSDL service name
*/
public String getWsdlServiceName() {
return mWsdlServiceName;
}
/**
* @return the WSDL port name
*/
public String getWsdlPortName() {
return mWsdlPortName;
}
/**
* @return the WSDL target namespace
*/
public String getWsdlTargetNamespace() {
return mWsdlTargetNamespace;
}
/**
* @return the WSDL URL
*/
public String getWsdlUrl() {
return mWsdlUrl;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy