Clover coverage report - Ivory - 1.0-alpha-5
Coverage timestamp: Sun Nov 9 2003 22:02:40 EST
file stats: LOC: 330   Methods: 5
NCLOC: 96   Classes: 2
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
AvalonProvider.java 0% 0% 0% 0%
coverage
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  *
 5   
  * Copyright (c) 2001 The Apache Software Foundation.  All rights
 6   
  * reserved.
 7   
  *
 8   
  * Redistribution and use in source and binary forms, with or without
 9   
  * modification, are permitted provided that the following conditions
 10   
  * are met:
 11   
  *
 12   
  * 1. Redistributions of source code must retain the above copyright
 13   
  *    notice, this list of conditions and the following disclaimer.
 14   
  *
 15   
  * 2. Redistributions in binary form must reproduce the above copyright
 16   
  *    notice, this list of conditions and the following disclaimer in
 17   
  *    the documentation and/or other materials provided with the
 18   
  *    distribution.
 19   
  *
 20   
  * 3. The end-user documentation included with the redistribution,
 21   
  *    if any, must include the following acknowledgment:
 22   
  *       "This product includes software developed by the
 23   
  *        Apache Software Foundation (http://www.apache.org/)."
 24   
  *    Alternately, this acknowledgment may appear in the software itself,
 25   
  *    if and wherever such third-party acknowledgments normally appear.
 26   
  *
 27   
  * 4. The names "Axis" and "Apache Software Foundation" must
 28   
  *    not be used to endorse or promote products derived from this
 29   
  *    software without prior written permission. For written
 30   
  *    permission, please contact apache@apache.org.
 31   
  *
 32   
  * 5. Products derived from this software may not be called "Apache",
 33   
  *    nor may "Apache" appear in their name, without prior written
 34   
  *    permission of the Apache Software Foundation.
 35   
  *
 36   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 37   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 38   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 39   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 40   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 41   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 42   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 43   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 44   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 45   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 46   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 47   
  * SUCH DAMAGE.
 48   
  * ====================================================================
 49   
  *
 50   
  * This software consists of voluntary contributions made by many
 51   
  * individuals on behalf of the Apache Software Foundation.  For more
 52   
  * information on the Apache Software Foundation, please see
 53   
  * <http://www.apache.org/>.
 54   
  */
 55   
 
 56   
 package org.codehaus.ivory.provider;
 57   
 
 58   
 import java.lang.reflect.InvocationHandler;
 59   
 import java.lang.reflect.InvocationTargetException;
 60   
 import java.lang.reflect.Method;
 61   
 import java.lang.reflect.Proxy;
 62   
 
 63   
 import javax.xml.rpc.server.ServiceLifecycle;
 64   
 
 65   
 import org.apache.avalon.framework.service.ServiceManager;
 66   
 import org.apache.axis.AxisFault;
 67   
 import org.apache.axis.MessageContext;
 68   
 import org.apache.axis.handlers.soap.SOAPService;
 69   
 import org.apache.axis.providers.java.RPCProvider;
 70   
 
 71   
 /**
 72   
  * Provider class which allows you to specify an Avalon <b>ROLE</b> for
 73   
  * servicing Axis SOAP requests.
 74   
  *
 75   
  * <p>
 76   
  *  The specified <b>ROLE</b> corresponds to a particular implementation
 77   
  *  which is retrieved by a given Avalon <code>ComponentManager</code>.
 78   
  *  For more information about Avalon, see the Avalon.
 79   
  *  <a href="http://jakarta.apache.org/avalon">website</a>.
 80   
  * </p>
 81   
  *
 82   
  * <p>
 83   
  *  To use this class, you need to add your Avalon <code>ComponentManager</code>
 84   
  *  instance to the <code>MessageContext</code> that is Axis uses to process
 85   
  *  messages with.
 86   
  * </p>
 87   
  *
 88   
  * <p>
 89   
  *  To do this you could for example subclass the AxisServlet and override the
 90   
  *  <code>createMessageContext()</code> method adding the ComponentManager, eg:
 91   
  *
 92   
  *  <pre>
 93   
  *   protected MessageContext createMessageContext(...)
 94   
  *   {
 95   
  *      MessageContext context = super.createMessageContext();
 96   
  *      context.setProperty(AvalonProvider.COMPONENT_MANAGER, m_manager);
 97   
  *      return context;
 98   
  *   }
 99   
  *  </pre>
 100   
  *
 101   
  *  and appropriately add the AvalonProvider to the list of handlers in your
 102   
  *  server-config.wsdd (suggestions on how to improve this are welcomed)
 103   
  * </p>
 104   
  *
 105   
  * <p>
 106   
  *  This provider will use that <code>ComponentManager</code> reference to
 107   
  *  retrieve objects.
 108   
  * </p>
 109   
  *
 110   
  * <p>
 111   
  *  In your deployment descriptor use the following syntax:
 112   
  *
 113   
  * <pre>
 114   
  *  &lt;service name="myservice" provider="java:Avalon"&gt;
 115   
  *    &lt;parameter name="role" value="my.avalon.role.name"/&gt;
 116   
  *    &lt;parameter name="className" value="my.avalon.roles.interface.name"/&gt;
 117   
  *    &lt;parameter name="allowedMethods" value="allowed.methods"/&gt;
 118   
  *  &lt;/service&gt;
 119   
  * </pre>
 120   
  *
 121   
  * </p>
 122   
  *
 123   
  * @author <a href="mailto:crafterm@apache.org">Marcus Crafter</a>
 124   
  * @revision CVS $Id: AvalonProvider.java,v 1.1 2003/07/02 21:29:30 dandiep Exp $
 125   
  */
 126   
 public class AvalonProvider
 127   
     extends RPCProvider
 128   
 {
 129   
     /**
 130   
      * Constant used to retrieve the ServiceManager reference
 131   
      * from the MessageContext object.
 132   
      */
 133   
     public static final String SERVICE_MANAGER = "service-manager";
 134   
 
 135   
     /**
 136   
      * Constant which represents the name of the ROLE this
 137   
      * provider should <i>lookup</i> to service a request with. This is
 138   
      * specified in the &lt;parameter name="" value=""/&gt; part of the
 139   
      * deployment xml.
 140   
      */
 141   
     public static final String ROLE = "role";
 142   
 
 143   
     /**
 144   
      * Returns the service object.
 145   
      * 
 146   
      * @param msgContext the message context
 147   
      * @param role the Avalon ROLE to lookup to find the service object implementation
 148   
      * @return an object that implements the service
 149   
      * @exception Exception if an error occurs
 150   
      */
 151  0
     protected Object makeNewServiceObject(
 152   
         MessageContext msgContext,
 153   
         String role)
 154   
         throws Exception
 155   
     {
 156  0
         ServiceManager manager =
 157   
             (ServiceManager) msgContext
 158   
                 .getAxisEngine()
 159   
                 .getApplicationSession()
 160   
                 .get( SERVICE_MANAGER );
 161   
 
 162  0
         if (manager == null)
 163  0
             throw new AxisFault("Could not access Avalon ServiceManager");
 164   
 
 165  0
         return decorate(manager.lookup(role), manager);
 166   
     }
 167   
 
 168   
     /**
 169   
      * Helper method for decorating a <code>Component</code> with a Handler
 170   
      * proxy (see below).
 171   
      *
 172   
      * @param object a <code>Component</code> instance
 173   
      * @param manager a <code>ComponentManager</code> instance
 174   
      * @return the <code>Proxy</code> wrapped <code>Component</code> instance
 175   
      * @exception Exception if an error occurs
 176   
      */
 177  0
     private Object decorate(final Object object, final ServiceManager manager)
 178   
         throws Exception
 179   
     {
 180   
         // obtain a list of all interfaces this object implements
 181  0
         Class[] interfaces = object.getClass().getInterfaces();
 182   
 
 183   
         // add ServiceLifecycle to it
 184  0
         Class[] adjusted = new Class[interfaces.length + 1];
 185  0
         System.arraycopy(interfaces, 0, adjusted, 0, interfaces.length);
 186  0
         adjusted[interfaces.length] = ServiceLifecycle.class;
 187   
 
 188   
         // create a proxy implementing those interfaces
 189  0
         Object proxy =
 190   
             Proxy.newProxyInstance(
 191   
                 this.getClass().getClassLoader(),
 192   
                 adjusted,
 193   
                 new Handler(object, manager));
 194   
 
 195   
         // return the proxy
 196  0
         return proxy;
 197   
     }
 198   
 
 199   
     /**
 200   
      * Get the service class description
 201   
      * 
 202   
      * @param role the Avalon ROLE name
 203   
      * @param service a <code>SOAPService</code> instance
 204   
      * @param msgContext the message context
 205   
      * @return service class description
 206   
      * @exception AxisFault if an error occurs
 207   
      */
 208  0
     protected Class getServiceClass(
 209   
         String role,
 210   
         SOAPService service,
 211   
         MessageContext msgContext)
 212   
         throws AxisFault
 213   
     {
 214   
         // Assuming ExcaliburComponentManager semantics the ROLE name is
 215   
         // actually the class name, potentially with a variant following
 216   
         // the class name with a '/' separator
 217   
 
 218  0
         int i;
 219   
 
 220  0
         if ((i = role.indexOf('/')) != -1)
 221   
         {
 222  0
             return super.getServiceClass( role.substring(0, i), service, msgContext );
 223   
         }
 224   
         else
 225   
         {
 226  0
             return super.getServiceClass( role, service, msgContext );
 227   
         }
 228   
 
 229   
     }
 230   
 
 231   
     /**
 232   
      * <code>InvocationHandler</code> class for managing Avalon
 233   
      * <code>Components</code>.
 234   
      *
 235   
      * <p>
 236   
      *  Components retrieved from an Avalon ComponentManager must be
 237   
      *  returned to the manager when they are no longer required.
 238   
      * </p>
 239   
      *
 240   
      * <p>
 241   
      *  The returning of Components to their ComponentManager is handled
 242   
      *  by a Proxy class which uses the following InvocationHandler.
 243   
      * </p>
 244   
      *
 245   
      * <p>
 246   
      *  Each Component returned by this Provider is wrapped inside a 
 247   
      *  Proxy class which implements all of the Component's interfaces
 248   
      *  including javax.xml.rpc.server.ServiceLifecycle.
 249   
      * </p>
 250   
      *
 251   
      * <p>
 252   
      *  When Axis is finished with the object returned by this provider,
 253   
      *  it invokes ServiceLifecycle.destroy(). This is intercepted by the
 254   
      *  InvocationHandler and the Component is returned at this time back
 255   
      *  to the ComponentManager it was retrieved from.
 256   
      * </p>
 257   
      *
 258   
      * <p>
 259   
      *  <b>Note</b>, when Axis invokes ServiceLifecycle.destroy() is dependant
 260   
      *  on the scope of the service (ie. Request, Session & Application).
 261   
      * </p>
 262   
      */
 263   
     final class Handler implements InvocationHandler
 264   
     {
 265   
         // Constants describing the ServiceLifecycle.destroy method
 266   
         private final String SL_DESTROY = "destroy";
 267   
         private final Class SL_CLASS = ServiceLifecycle.class;
 268   
 
 269   
         // Component & ServiceManager references
 270   
         private final Object m_object;
 271   
         private final ServiceManager m_manager;
 272   
 
 273   
         /**
 274   
          * Simple constructor, sets all internal references
 275   
          *
 276   
          * @param object a <code>Component</code> instance
 277   
          * @param manager a <code>ComponentManager</code> instance
 278   
          * @param log a <code>Logger</code> instance
 279   
          */
 280  0
         public Handler(final Object object, final ServiceManager manager)
 281   
         {
 282  0
             m_object = object;
 283  0
             m_manager = manager;
 284   
         }
 285   
 
 286   
         /**
 287   
          * <code>invoke</code> method, handles all method invocations for this
 288   
          * particular proxy.
 289   
          *
 290   
          * <p>
 291   
          *  Usually the invocation is passed through to the
 292   
          *  actual component the proxy wraps, unless the method belongs to
 293   
          *  the <code>ServiceLifecycle</code> interface where it is handled
 294   
          *  locally.
 295   
          * </p>
 296   
          *
 297   
          * @param proxy the <code>Proxy</code> instance the method was invoked on
 298   
          * @param method the invoked method <code>Method</code> object
 299   
          * @param args an <code>Object[]</code> array of arguments
 300   
          * @return an <code>Object</code> value or null if none
 301   
          * @exception Throwable if an error occurs
 302   
          */
 303  0
         public Object invoke(Object proxy, Method method, Object[] args)
 304   
             throws Throwable
 305   
         {
 306  0
             try
 307   
             {
 308   
                 // if ServiceLifecycle.destroy() called, return to CM
 309  0
                 if (method.getDeclaringClass().equals(SL_CLASS))
 310   
                 {
 311  0
                     if (method.getName().equals(SL_DESTROY))
 312   
                     {
 313  0
                         m_manager.release(m_object);
 314   
                     }
 315   
 
 316  0
                     return null;
 317   
                 }
 318   
                 else // otherwise pass call to the real object
 319   
                 {
 320  0
                     return method.invoke(m_object, args);
 321   
                 }
 322   
             }
 323   
             catch ( InvocationTargetException e )
 324   
             {
 325  0
                 throw e.getTargetException();
 326   
             }
 327   
         }
 328   
     }
 329   
 }
 330