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 * <service name="myservice" provider="java:Avalon">
115 * <parameter name="role" value="my.avalon.role.name"/>
116 * <parameter name="className" value="my.avalon.roles.interface.name"/>
117 * <parameter name="allowedMethods" value="allowed.methods"/>
118 * </service>
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 <parameter name="" value=""/> 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 protected Object makeNewServiceObject(
152 MessageContext msgContext,
153 String role)
154 throws Exception
155 {
156 ServiceManager manager =
157 (ServiceManager) msgContext
158 .getAxisEngine()
159 .getApplicationSession()
160 .get( SERVICE_MANAGER );
161
162 if (manager == null)
163 throw new AxisFault("Could not access Avalon ServiceManager");
164
165 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 private Object decorate(final Object object, final ServiceManager manager)
178 throws Exception
179 {
180 // obtain a list of all interfaces this object implements
181 Class[] interfaces = object.getClass().getInterfaces();
182
183 // add ServiceLifecycle to it
184 Class[] adjusted = new Class[interfaces.length + 1];
185 System.arraycopy(interfaces, 0, adjusted, 0, interfaces.length);
186 adjusted[interfaces.length] = ServiceLifecycle.class;
187
188 // create a proxy implementing those interfaces
189 Object proxy =
190 Proxy.newProxyInstance(
191 this.getClass().getClassLoader(),
192 adjusted,
193 new Handler(object, manager));
194
195 // return the proxy
196 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 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 int i;
219
220 if ((i = role.indexOf('/')) != -1)
221 {
222 return super.getServiceClass( role.substring(0, i), service, msgContext );
223 }
224 else
225 {
226 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 public Handler(final Object object, final ServiceManager manager)
281 {
282 m_object = object;
283 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 public Object invoke(Object proxy, Method method, Object[] args)
304 throws Throwable
305 {
306 try
307 {
308 // if ServiceLifecycle.destroy() called, return to CM
309 if (method.getDeclaringClass().equals(SL_CLASS))
310 {
311 if (method.getName().equals(SL_DESTROY))
312 {
313 m_manager.release(m_object);
314 }
315
316 return null;
317 }
318 else // otherwise pass call to the real object
319 {
320 return method.invoke(m_object, args);
321 }
322 }
323 catch ( InvocationTargetException e )
324 {
325 throw e.getTargetException();
326 }
327 }
328 }
329 }
This page was automatically generated by Maven