1 package org.codehaus.ivory.provider;
2
3 import java.lang.reflect.InvocationHandler;
4 import java.lang.reflect.InvocationTargetException;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Proxy;
7
8 import javax.xml.rpc.server.ServiceLifecycle;
9
10 import org.apache.avalon.framework.service.ServiceManager;
11 import org.apache.axis.AxisFault;
12 import org.apache.axis.MessageContext;
13 import org.apache.axis.handlers.soap.SOAPService;
14
15 /***
16 *
17 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
18 * @since May 23, 2003
19 */
20 public class IvoryAvalonProvider
21 extends IvoryProvider
22 {
23 /***
24 * Constant used to retrieve the ServiceManager reference
25 * from the MessageContext object.
26 */
27 public static final String SERVICE_MANAGER = "service-manager";
28
29 /***
30 * Constant which represents the name of the ROLE this
31 * provider should <i>lookup</i> to service a request with. This is
32 * specified in the <parameter name="" value=""/> part of the
33 * deployment xml.
34 */
35 public static final String ROLE = "role";
36
37 /***
38 * Returns the service object.
39 *
40 * @param msgContext the message context
41 * @param role the Avalon ROLE to lookup to find the service object implementation
42 * @return an object that implements the service
43 * @exception Exception if an error occurs
44 */
45 protected Object makeNewServiceObject(
46 MessageContext msgContext,
47 String role)
48 throws Exception
49 {
50 ServiceManager manager =
51 (ServiceManager) msgContext
52 .getAxisEngine()
53 .getApplicationSession()
54 .get( SERVICE_MANAGER );
55
56 if (manager == null)
57 throw new AxisFault("Could not access Avalon ServiceManager");
58
59 return decorate(manager.lookup(role), manager);
60 }
61
62 /***
63 * Helper method for decorating a <code>Component</code> with a Handler
64 * proxy (see below).
65 *
66 * @param object a <code>Component</code> instance
67 * @param manager a <code>ComponentManager</code> instance
68 * @return the <code>Proxy</code> wrapped <code>Component</code> instance
69 * @exception Exception if an error occurs
70 */
71 private Object decorate(final Object object, final ServiceManager manager)
72 throws Exception
73 {
74
75 Class[] interfaces = object.getClass().getInterfaces();
76
77
78 Class[] adjusted = new Class[interfaces.length + 1];
79 System.arraycopy(interfaces, 0, adjusted, 0, interfaces.length);
80 adjusted[interfaces.length] = ServiceLifecycle.class;
81
82
83 Object proxy =
84 Proxy.newProxyInstance(
85 this.getClass().getClassLoader(),
86 adjusted,
87 new Handler(object, manager));
88
89
90 return proxy;
91 }
92
93 /***
94 * Get the service class description
95 *
96 * @param role the Avalon ROLE name
97 * @param service a <code>SOAPService</code> instance
98 * @param msgContext the message context
99 * @return service class description
100 * @exception AxisFault if an error occurs
101 */
102 protected Class getServiceClass(
103 String role,
104 SOAPService service,
105 MessageContext msgContext)
106 throws AxisFault
107 {
108
109
110
111
112 int i;
113
114 ClassLoader cl = Thread.currentThread().getContextClassLoader();
115 String className = role;
116
117 if ((i = role.indexOf('/')) != -1)
118 {
119 className = role.substring(0, i);
120 }
121
122 try
123 {
124 return cl.loadClass( className );
125 }
126 catch (ClassNotFoundException e)
127 {
128 throw new AxisFault( "Couldn't find class " + className, e );
129 }
130 }
131
132 /***
133 * <code>InvocationHandler</code> class for managing Avalon
134 * <code>Components</code>.
135 *
136 * <p>
137 * Components retrieved from an Avalon ComponentManager must be
138 * returned to the manager when they are no longer required.
139 * </p>
140 *
141 * <p>
142 * The returning of Components to their ComponentManager is handled
143 * by a Proxy class which uses the following InvocationHandler.
144 * </p>
145 *
146 * <p>
147 * Each Component returned by this Provider is wrapped inside a
148 * Proxy class which implements all of the Component's interfaces
149 * including javax.xml.rpc.server.ServiceLifecycle.
150 * </p>
151 *
152 * <p>
153 * When Axis is finished with the object returned by this provider,
154 * it invokes ServiceLifecycle.destroy(). This is intercepted by the
155 * InvocationHandler and the Component is returned at this time back
156 * to the ComponentManager it was retrieved from.
157 * </p>
158 *
159 * <p>
160 * <b>Note</b>, when Axis invokes ServiceLifecycle.destroy() is dependant
161 * on the scope of the service (ie. Request, Session & Application).
162 * </p>
163 */
164 final class Handler implements InvocationHandler
165 {
166
167 private final String SL_DESTROY = "destroy";
168 private final Class SL_CLASS = ServiceLifecycle.class;
169
170
171 private final Object m_object;
172 private final ServiceManager m_manager;
173
174 /***
175 * Simple constructor, sets all internal references
176 *
177 * @param object a <code>Component</code> instance
178 * @param manager a <code>ComponentManager</code> instance
179 * @param log a <code>Logger</code> instance
180 */
181 public Handler(final Object object, final ServiceManager manager)
182 {
183 m_object = object;
184 m_manager = manager;
185 }
186
187 /***
188 * <code>invoke</code> method, handles all method invocations for this
189 * particular proxy.
190 *
191 * <p>
192 * Usually the invocation is passed through to the
193 * actual component the proxy wraps, unless the method belongs to
194 * the <code>ServiceLifecycle</code> interface where it is handled
195 * locally.
196 * </p>
197 *
198 * @param proxy the <code>Proxy</code> instance the method was invoked on
199 * @param method the invoked method <code>Method</code> object
200 * @param args an <code>Object[]</code> array of arguments
201 * @return an <code>Object</code> value or null if none
202 * @exception Throwable if an error occurs
203 */
204 public Object invoke(Object proxy, Method method, Object[] args)
205 throws Throwable
206 {
207 try
208 {
209
210 if (method.getDeclaringClass().equals(SL_CLASS))
211 {
212 if (method.getName().equals(SL_DESTROY))
213 {
214 m_manager.release(m_object);
215 }
216
217 return null;
218 }
219 else
220 {
221 return method.invoke(m_object, args);
222 }
223 }
224 catch ( InvocationTargetException e )
225 {
226 throw e.getTargetException();
227 }
228 }
229 }
230 }