All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.legstar.proxy.invoke.jaxws.WebServiceInvoker Maven / Gradle / Ivy

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