Clover coverage report -
Coverage timestamp: Sat Jul 7 2007 16:41:13 CEST
file stats: LOC: 342   Methods: 36
NCLOC: 254   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
JaxWsHelper.java 90% 70.2% 41.7% 64.7%
coverage coverage
 1    /**
 2    * JTRunner is free software; you can redistribute it and/or modify it under the
 3    * terms of the GNU General Public License as published by the Free Software
 4    * Foundation; either version 2, or (at your option) any later version.
 5    */
 6   
 7    package jtr.ws.jaxws;
 8   
 9    import java.lang.reflect.InvocationHandler;
 10    import java.lang.reflect.Method;
 11    import java.lang.reflect.Proxy;
 12    import java.net.MalformedURLException;
 13    import java.net.URL;
 14    import java.util.HashMap;
 15    import java.util.Map;
 16    import java.util.concurrent.Future;
 17    import java.util.concurrent.Semaphore;
 18    import javax.xml.bind.JAXBContext;
 19    import javax.xml.bind.JAXBException;
 20    import javax.xml.namespace.QName;
 21    import javax.xml.ws.AsyncHandler;
 22    import javax.xml.ws.Dispatch;
 23    import javax.xml.ws.Response;
 24    import javax.xml.ws.Service;
 25    import jtr.config.ws.Binding;
 26    import jtr.config.ws.WebServiceConfig;
 27    import jtr.runners.IRunnerWs;
 28    import jtr.ws.IWsHelper;
 29    import jtr.ws.IWsResponse;
 30    import jtr.ws.IWsResponseListener;
 31    import jtr.ws.WsMsgType;
 32    import jtr.ws.WsProviderException;
 33    import org.apache.log4j.Logger;
 34   
 35    /**
 36    * Implementation of the <code>IWsHelper</code> contract, based on the JAX-WS 2.1 API
 37    * and the JAXB 2.1 API.
 38    * This implementation is stateless, thus it can be profitably used by the JTR runtime
 39    * as a shared-helper class for all those concrete runners requiring web-services support.<br>
 40    * Please, also note that this implementation imposes that only JAXB-based objects are used as
 41    * input and output parameters.
 42    *
 43    * @author Francesco Russo
 44    * @version 4.0
 45    * @since 4.0
 46    */
 47    public class JaxWsHelper implements IWsHelper {
 48   
 49    /** Creates a new instance of JaxWsHelper */
 50  2 public JaxWsHelper() {
 51  2 jaxbContextesCache = java.util.Collections.synchronizedMap(new HashMap<String, JAXBContext>());
 52  2 dispacthesCache = java.util.Collections.synchronizedMap(new HashMap<String, Dispatch>());
 53  2 asynchDispatchesCache = java.util.Collections.synchronizedMap((new HashMap<String, Map<String, Dispatch>>()));
 54    }
 55   
 56  6014 public void generateRuntimeConfig(WebServiceConfig wsCfg) throws WsProviderException {
 57    // nop
 58    }
 59   
 60  7495 public Object invoke(IRunnerWs runner, Binding binding, Object input) throws WsProviderException {
 61  7494 Dispatch dispatch = createDispatch(binding);
 62  7500 return dispatch.invoke(input);
 63    }
 64   
 65  4000 public void invokeOneWay(IRunnerWs runner, Binding binding, Object input) throws WsProviderException {
 66  4000 Dispatch dispatch = createDispatch(binding);
 67  4000 dispatch.invokeOneWay(input);
 68    }
 69   
 70  2000 public Future<?> invokeAsync(IRunnerWs runner, Binding binding, Object input, IWsResponseListener rl) throws WsProviderException {
 71    // dynamic-proxy creation
 72  2000 ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
 73  2000 JtrJaxwsAsynchInvocationsBridge bridge = new JtrJaxwsAsynchInvocationsBridge(rl);
 74  2000 AsyncHandler asynchHandler = (AsyncHandler) Proxy.newProxyInstance(ctxCL, new Class[] {AsyncHandler.class}, bridge);
 75    // actual service invocation
 76  2000 Dispatch dispatch = createAsyncDispatch(runner, binding);
 77  2000 return dispatch.invokeAsync(input, asynchHandler);
 78    }
 79   
 80  2000 public IWsResponse invokeAsync(IRunnerWs runner, Binding binding, Object input) throws WsProviderException {
 81    // actual invocation
 82  2000 Dispatch dispatch = createAsyncDispatch(runner, binding);
 83  2000 Response rsp = dispatch.invokeAsync(input);
 84    // dynamic-proxy creation
 85  2000 ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
 86  2000 JaxwsJtrAsynchResponseBridge bridge = new JaxwsJtrAsynchResponseBridge(rsp);
 87  1999 return (IWsResponse) Proxy.newProxyInstance(ctxCL, new Class[] {IWsResponse.class}, bridge);
 88    }
 89   
 90    /**
 91    * This private inner class serves as a bridge, or proxy, for passing every
 92    * invocation made on instances of <code>IWsResponseListener</code> to a dynamic
 93    * instance of <code>AsynchHandler</code>.
 94    * Since the <code>AsynchHandler</code> API exposes a method <code>void handleResponse(Response<T> res)</code>,
 95    * this implementation has to "translate" every argument of type <code>Response</code>
 96    * to arguments of type <code>IWsResponse</code>.
 97    * This is accomplished by means of the <code>JaxwsJtrAsynchResponseBridge</code> class.
 98    */
 99    private class JtrJaxwsAsynchInvocationsBridge implements InvocationHandler {
 100  1999 JtrJaxwsAsynchInvocationsBridge(IWsResponseListener lsnr) {
 101  2000 target = lsnr;
 102    }
 103   
 104  1991 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 105    // the AsynchHandler interface only admits one method: 'void handleResponse(Response<T> res)'
 106    // thus we have to translate every 'javax.xml.ws.Response' instance into a
 107    // 'jtr.ws.IWsResponseListener.IWsResponse'
 108  1996 Method targetMethod = null;
 109    // method resolution and potential proxy creation
 110  1992 if(method.getName().equals("handleResponse")) {
 111    // method resolution
 112  1993 targetMethod = IWsResponseListener.class.getMethod(method.getName(), IWsResponse.class);
 113    // dynamic-proxy creation
 114  1996 ClassLoader ctxCL = Thread.currentThread().getContextClassLoader();
 115  1998 JaxwsJtrAsynchResponseBridge bridge = new JaxwsJtrAsynchResponseBridge((Response) args[0]);
 116  1997 IWsResponse wsRsp = (IWsResponse) Proxy.newProxyInstance(ctxCL, new Class[] {IWsResponse.class}, bridge);
 117  2000 return targetMethod.invoke(target, new Object[] {wsRsp});
 118    } else {
 119    // method resolution
 120  0 targetMethod = IWsResponseListener.class.getMethod(method.getName(), method.getParameterTypes());
 121    }
 122    // invocation
 123  0 Object res = targetMethod.invoke(target, args);
 124  0 return res;
 125    }
 126   
 127    private IWsResponseListener target;
 128    }
 129   
 130    /**
 131    * This private inner class serves as a bridge, or proxy, for passing every
 132    * invocation made on instances of <code>Response</code> to a dynamic instance
 133    * of <code>IWsResponse</code>.
 134    */
 135    private class JaxwsJtrAsynchResponseBridge implements InvocationHandler {
 136  3996 JaxwsJtrAsynchResponseBridge(Response rsp) {
 137  3996 target = rsp;
 138    }
 139   
 140  1621659 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
 141    // method resolution
 142  1621631 Method targetMethod = Response.class.getMethod(method.getName(), method.getParameterTypes());
 143    // actual invocation
 144  1621647 Object res = targetMethod.invoke(target, args);
 145  1621647 return res;
 146    }
 147   
 148    private Response target;
 149    }
 150   
 151  11493 private Dispatch createDispatch(Binding binding) throws WsProviderException {
 152  11494 Dispatch res = null;
 153  11498 String key = binding.getUniqueName();
 154  11499 synchronized(dispacthesCache) {
 155  11500 if(dispacthesCache.containsKey(key)) {
 156  11484 res = dispacthesCache.get(key);
 157    } else {
 158  16 res = _createDispatch(binding);
 159  16 dispacthesCache.put(key, res);
 160    }
 161    }
 162  11500 return res;
 163    }
 164   
 165  4000 private Dispatch createAsyncDispatch(IRunnerWs runner, Binding binding) throws WsProviderException {
 166  4000 Dispatch res = null;
 167  4000 String bindingName = binding.getUniqueName();
 168  4000 String runnerId = runner.getName();
 169  3999 synchronized(asynchDispatchesCache) {
 170  4000 if(asynchDispatchesCache.containsKey(runnerId)) {
 171  3980 Map<String,Dispatch> innerMap = asynchDispatchesCache.get(runnerId);
 172  3980 if(innerMap.containsKey(bindingName)) {
 173  3960 res = innerMap.get(bindingName);
 174    } else {
 175  20 res = _createDispatch(binding);
 176  20 innerMap.put(bindingName, res);
 177    }
 178    } else {
 179  20 Map<String,Dispatch> innerMap = java.util.Collections.synchronizedMap(new HashMap<String,Dispatch>());
 180  20 res = _createDispatch(binding);
 181  20 innerMap.put(bindingName, res);
 182  20 asynchDispatchesCache.put(runnerId, innerMap);
 183    }
 184    }
 185  4000 return res;
 186    }
 187   
 188    /**
 189    * Utility method for instantiating <code>Dispatch</code> instances.
 190    */
 191  56 private Dispatch _createDispatch(Binding binding) throws WsProviderException {
 192  56 try {
 193  56 String ns = binding.getNameSpace();
 194  56 String srvcName = binding.getName();
 195  56 String wsdlLoc = binding.getWsdlLoc();
 196  56 String portName = binding.getPortName();
 197  56 String srvcMode = binding.getServiceMode();
 198   
 199  56 JAXBContext jaxbCtx = getJAXBContext(binding.getJaxbObjectFactory());
 200   
 201  56 QName serviceQName = new QName(ns, srvcName);
 202  56 Service service = Service.create(new URL(wsdlLoc), serviceQName);
 203    // port
 204  56 QName portQName = new QName(ns, portName);
 205    // dispatch
 206  56 return service.createDispatch(portQName, jaxbCtx, Service.Mode.valueOf(srvcMode));
 207   
 208    } catch(ClassNotFoundException e) {
 209  0 String msg = "Unable to load JAXB ObjectFactory user-defined class "+binding.getJaxbObjectFactory();
 210  0 logger.fatal(msg,e);
 211  0 throw new WsProviderException(msg,e);
 212    } catch(MalformedURLException e) {
 213  0 String msg = "Unable to retrieve WSDL due to a malformed URL. Please check: "+binding.getWsdlLoc();
 214  0 logger.fatal(msg,e);
 215  0 throw new WsProviderException(msg,e);
 216    }
 217    }
 218   
 219  56 private JAXBContext getJAXBContext(String fqn) throws ClassNotFoundException {
 220  56 JAXBContext ctx = null;
 221  56 synchronized(jaxbContextesCache) {
 222  56 if(jaxbContextesCache.containsKey(fqn)) {
 223  52 ctx = jaxbContextesCache.get(fqn);
 224    } else {
 225  4 Class jaxbObjFactory = Thread.currentThread().getContextClassLoader().loadClass(fqn);
 226  4 ctx = createJAXBContext(jaxbObjFactory);
 227  4 jaxbContextesCache.put(fqn, ctx);
 228    }
 229    }
 230  56 return ctx;
 231    }
 232   
 233    /**
 234    * Utility method for instantiation of the required <code>JAXBContext</code>.
 235    */
 236  4 private JAXBContext createJAXBContext(Class clazz) {
 237  4 try {
 238  4 return JAXBContext.newInstance(clazz);
 239    } catch (JAXBException e) {
 240  0 throw new RuntimeException(e.getMessage(), e);
 241    }
 242    }
 243   
 244    private static final String OP_NOT_SUPP_MSG = "This is a legacy API not supported anymore by this implementation of the "+IWsHelper.class.getSimpleName()+
 245    ". Current implementation is provided by "+JaxWsHelper.class.getName();
 246    protected final Logger logger = Logger.getLogger(JaxWsHelper.class);
 247    // the String key must be the Java FQN of the JAXBContext class
 248    private static Map<String,JAXBContext> jaxbContextesCache;
 249    // the String key must be the unique-name of a JTR binding
 250    private static Map<String,Dispatch> dispacthesCache;
 251    // the first String key must be the runner's unique id (name),
 252    // the second String key must be the unique-name of a JTR binding
 253    private static Map<String,Map<String,Dispatch>> asynchDispatchesCache;
 254   
 255   
 256    //******************************* UNSUPPORTED LEGACY CODE ********************************
 257   
 258  0 @Deprecated
 259    public boolean synchronousInvoke(Binding binding) throws WsProviderException {
 260  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 261    }
 262  0 @Deprecated
 263    public void asynchronousInputOnlyInvoke(Binding binding) throws WsProviderException {
 264  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 265    }
 266  0 @Deprecated
 267    public void setMessageObjectPart(Binding binding, String partName, Object part, WsMsgType msgType) throws WsProviderException {
 268  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 269    }
 270  0 @Deprecated
 271    public void setMessageIntPart(Binding binding, String partName, int part, WsMsgType msgType) {
 272  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 273    }
 274  0 @Deprecated
 275    public void setMessageBooleanPart(Binding binding, String partName, boolean part, WsMsgType msgType) {
 276  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 277    }
 278  0 @Deprecated
 279    public void setMessageBytePart(Binding binding, String partName, byte part, WsMsgType msgType) {
 280  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 281    }
 282  0 @Deprecated
 283    public void setMessageCharPart(Binding binding, String partName, char part, WsMsgType msgType) {
 284  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 285    }
 286  0 @Deprecated
 287    public void setMessageDoublePart(Binding binding, String partName, double part, WsMsgType msgType) {
 288  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 289    }
 290  0 @Deprecated
 291    public void setMessageFloatPart(Binding binding, String partName, float part, WsMsgType msgType) {
 292  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 293    }
 294  0 @Deprecated
 295    public void setMessageLongPart(Binding binding, String partName, long part, WsMsgType msgType) {
 296  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 297    }
 298  0 @Deprecated
 299    public Object getMessageObjectPart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 300  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 301    }
 302  0 @Deprecated
 303    public int getMessageIntPart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 304  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 305    }
 306  0 @Deprecated
 307    public boolean getMessageBooleanPart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 308  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 309    }
 310  0 @Deprecated
 311    public byte getMessageBytePart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 312  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 313    }
 314  0 @Deprecated
 315    public char getMessageCharPart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 316  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 317    }
 318  0 @Deprecated
 319    public double getMessageDoublePart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 320  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 321    }
 322  0 @Deprecated
 323    public float getMessageFloatPart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 324  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 325    }
 326  0 @Deprecated
 327    public long getMessageLongPart(Binding binding, String partName, WsMsgType msgType) throws WsProviderException {
 328  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 329    }
 330  0 @Deprecated
 331    public String[] getMessageParts(Binding binding, WsMsgType msgType) {
 332  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 333    }
 334  0 @Deprecated
 335    public String getFaultMessageAsString(Binding binding) {
 336  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 337    }
 338  0 @Deprecated
 339    public Throwable getFaultCause(Binding binding) {
 340  0 throw new UnsupportedOperationException(OP_NOT_SUPP_MSG);
 341    }
 342    }