KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > axis > providers > AvalonProvider


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 // package org.apache.axis.providers.java;
17
// currently part of Cocoon until it's officially in Axis CVS (BZ#12903)
18
package org.apache.cocoon.components.axis.providers;
19
20 import org.apache.avalon.framework.component.Component;
21 import org.apache.avalon.framework.component.ComponentManager;
22
23 import org.apache.axis.AxisFault;
24 import org.apache.axis.MessageContext;
25 import org.apache.axis.providers.java.RPCProvider;
26 import org.apache.axis.handlers.soap.SOAPService;
27
28 import java.lang.reflect.Method JavaDoc;
29 import java.lang.reflect.InvocationHandler JavaDoc;
30 import java.lang.reflect.Proxy JavaDoc;
31
32 import javax.xml.rpc.server.ServiceLifecycle JavaDoc;
33
34 /**
35  * Provider class which allows you to specify an Avalon <b>ROLE</b> for
36  * servicing Axis SOAP requests.
37  *
38  * <p>
39  * The specified <b>ROLE</b> corresponds to a particular implementation
40  * which is retrieved by a given Avalon <code>ComponentManager</code>.
41  * For more information about Avalon, see the Avalon.
42  * <a HREF="http://jakarta.apache.org/avalon">website</a>.
43  * </p>
44  *
45  * <p>
46  * To use this class, you need to add your Avalon <code>ComponentManager</code>
47  * instance to the <code>MessageContext</code> that is Axis uses to process
48  * messages with.
49  * </p>
50  *
51  * <p>
52  * To do this you could for example subclass the AxisServlet and override the
53  * <code>createMessageContext()</code> method adding the ComponentManager, eg:
54  *
55  * <pre>
56  * protected MessageContext createMessageContext(...)
57  * {
58  * MessageContext context = super.createMessageContext();
59  * context.setProperty(AvalonProvider.COMPONENT_MANAGER, m_manager);
60  * return context;
61  * }
62  * </pre>
63  *
64  * and appropriately add the AvalonProvider to the list of handlers in your
65  * server-config.wsdd (suggestions on how to improve this are welcomed)
66  * </p>
67  *
68  * <p>
69  * This provider will use that <code>ComponentManager</code> reference to
70  * retrieve objects.
71  * </p>
72  *
73  * <p>
74  * In your deployment descriptor use the following syntax:
75  *
76  * <pre>
77  * &lt;service name="myservice" provider="java:Avalon"&gt;
78  * &lt;parameter name="role" value="my.avalon.role.name"/&gt;
79  * &lt;parameter name="className" value="my.avalon.roles.interface.name"/&gt;
80  * &lt;parameter name="allowedMethods" value="allowed.methods"/&gt;
81  * &lt;/service&gt;
82  * </pre>
83  *
84  * </p>
85  *
86  * @author <a HREF="mailto:crafterm@apache.org">Marcus Crafter</a>
87  * @version CVS $Id: AvalonProvider.java 149132 2005-01-30 18:24:33Z cziegeler $
88  */

89 public class AvalonProvider extends RPCProvider
90 {
91     /**
92      * Constant used to retrieve the ComponentManager reference
93      * from the MessageContext object.
94      */

95     public static final String JavaDoc COMPONENT_MANAGER = "component-manager";
96
97     /**
98      * Constant which represents the name of the ROLE this
99      * provider should <i>lookup</i> to service a request with. This is
100      * specified in the &lt;parameter name="" value=""/&gt; part of the
101      * deployment xml.
102      */

103     public static final String JavaDoc ROLE = "role";
104
105     /**
106      * Returns the service object.
107      *
108      * @param msgContext the message context
109      * @param role the Avalon ROLE to lookup to find the service object implementation
110      * @return an object that implements the service
111      * @exception Exception if an error occurs
112      */

113     protected Object JavaDoc makeNewServiceObject(MessageContext msgContext, String JavaDoc role)
114     throws Exception JavaDoc {
115         ComponentManager manager =
116             (ComponentManager) msgContext.getProperty(COMPONENT_MANAGER);
117
118         if (manager == null)
119             throw new AxisFault("Could not access Avalon ComponentManager");
120
121         return decorate(manager.lookup(role), manager);
122     }
123
124     /**
125      * Helper method for decorating a <code>Component</code> with a Handler
126      * proxy (see below).
127      *
128      * @param object a <code>Component</code> instance
129      * @param manager a <code>ComponentManager</code> instance
130      * @return the <code>Proxy</code> wrapped <code>Component</code> instance
131      * @exception Exception if an error occurs
132      */

133     private Object JavaDoc decorate(final Component object, final ComponentManager manager)
134     throws Exception JavaDoc {
135         // obtain a list of all interfaces this object implements
136
Class JavaDoc[] interfaces = object.getClass().getInterfaces();
137
138         // add ServiceLifecycle to it
139
Class JavaDoc[] adjusted = new Class JavaDoc[ interfaces.length + 1 ];
140         System.arraycopy(interfaces, 0, adjusted, 0, interfaces.length);
141         adjusted[interfaces.length] = ServiceLifecycle JavaDoc.class;
142
143         // create a proxy implementing those interfaces
144
Object JavaDoc proxy =
145             Proxy.newProxyInstance(
146                 this.getClass().getClassLoader(),
147                 adjusted,
148                 new Handler JavaDoc(object, manager)
149             );
150
151         // return the proxy
152
return proxy;
153     }
154
155     /**
156      * Return the option in the configuration that contains the service class
157      * name. In the Avalon case, it is the ROLE name to lookup.
158      */

159     protected String JavaDoc getServiceClassNameOptionName() {
160         return ROLE;
161     }
162
163     /**
164      * Get the service class description
165      *
166      * @param role the Avalon ROLE name
167      * @param service a <code>SOAPService</code> instance
168      * @param msgContext the message context
169      * @return service class description
170      * @exception AxisFault if an error occurs
171      */

172     protected Class JavaDoc getServiceClass(
173         String JavaDoc role, SOAPService service, MessageContext msgContext)
174     throws AxisFault {
175         // Assuming ExcaliburComponentManager semantics the ROLE name is
176
// actually the class name, potentially with a variant following
177
// the class name with a '/' separator
178

179         try {
180             int i;
181
182             if ((i = role.indexOf('/')) != -1)
183             {
184                 return Class.forName(role.substring(0, i));
185             }
186             return Class.forName(role);
187         } catch (ClassNotFoundException JavaDoc e) {
188             throw new AxisFault("Couldn't create class object for role " + role, e);
189         }
190     }
191
192     /**
193      * <code>InvocationHandler</code> class for managing Avalon
194      * <code>Components</code>.
195      *
196      * <p>
197      * Components retrieved from an Avalon ComponentManager must be
198      * returned to the manager when they are no longer required.
199      * </p>
200      *
201      * <p>
202      * The returning of Components to their ComponentManager is handled
203      * by a Proxy class which uses the following InvocationHandler.
204      * </p>
205      *
206      * <p>
207      * Each Component returned by this Provider is wrapped inside a
208      * Proxy class which implements all of the Component's interfaces
209      * including javax.xml.rpc.server.ServiceLifecycle.
210      * </p>
211      *
212      * <p>
213      * When Axis is finished with the object returned by this provider,
214      * it invokes ServiceLifecycle.destroy(). This is intercepted by the
215      * InvocationHandler and the Component is returned at this time back
216      * to the ComponentManager it was retrieved from.
217      * </p>
218      *
219      * <p>
220      * <b>Note</b>, when Axis invokes ServiceLifecycle.destroy() is dependant
221      * on the scope of the service (ie. Request, Session & Application).
222      * </p>
223      */

224     final static class Handler implements InvocationHandler JavaDoc {
225         
226         // Constants describing the ServiceLifecycle.destroy method
227
private final static String JavaDoc SL_DESTROY = "destroy";
228         private final Class JavaDoc SL_CLASS = ServiceLifecycle JavaDoc.class;
229
230         // Component & ComponentManager references
231
private final Component m_object;
232         private final ComponentManager m_manager;
233
234         /**
235          * Simple constructor, sets all internal references
236          *
237          * @param object a <code>Component</code> instance
238          * @param manager a <code>ComponentManager</code> instance
239          */

240         public Handler(final Component object, final ComponentManager manager) {
241             m_object = object;
242             m_manager = manager;
243         }
244
245         /**
246          * <code>invoke</code> method, handles all method invocations for this
247          * particular proxy.
248          *
249          * <p>
250          * Usually the invocation is passed through to the
251          * actual component the proxy wraps, unless the method belongs to
252          * the <code>ServiceLifecycle</code> interface where it is handled
253          * locally.
254          * </p>
255          *
256          * @param proxy the <code>Proxy</code> instance the method was invoked on
257          * @param method the invoked method <code>Method</code> object
258          * @param args an <code>Object[]</code> array of arguments
259          * @return an <code>Object</code> value or null if none
260          * @exception Throwable if an error occurs
261          */

262         public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args)
263         throws Throwable JavaDoc {
264             // if ServiceLifecycle.destroy() called, return to CM
265
if (method.getDeclaringClass().equals(SL_CLASS)) {
266                 if (method.getName().equals(SL_DESTROY)) {
267                     m_manager.release(m_object);
268                 }
269
270                 return null;
271             }
272             // otherwise pass call to the real object
273
return method.invoke(m_object, args);
274         }
275     }
276 }
277
Popular Tags