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 // obtain a list of all interfaces this object implements
75 Class[] interfaces = object.getClass().getInterfaces();
76
77 // add ServiceLifecycle to it
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 // create a proxy implementing those interfaces
83 Object proxy =
84 Proxy.newProxyInstance(
85 this.getClass().getClassLoader(),
86 adjusted,
87 new Handler(object, manager));
88
89 // return the proxy
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 // Assuming ExcaliburComponentManager semantics the ROLE name is
109 // actually the class name, potentially with a variant following
110 // the class name with a '/' separator
111
112 int i;
113
114 if ((i = role.indexOf('/')) != -1)
115 {
116 return super.getServiceClass( role.substring(0, i), service, msgContext );
117 }
118 else
119 {
120 return super.getServiceClass( role, service, msgContext );
121 }
122
123 }
124
125 /***
126 * <code>InvocationHandler</code> class for managing Avalon
127 * <code>Components</code>.
128 *
129 * <p>
130 * Components retrieved from an Avalon ComponentManager must be
131 * returned to the manager when they are no longer required.
132 * </p>
133 *
134 * <p>
135 * The returning of Components to their ComponentManager is handled
136 * by a Proxy class which uses the following InvocationHandler.
137 * </p>
138 *
139 * <p>
140 * Each Component returned by this Provider is wrapped inside a
141 * Proxy class which implements all of the Component's interfaces
142 * including javax.xml.rpc.server.ServiceLifecycle.
143 * </p>
144 *
145 * <p>
146 * When Axis is finished with the object returned by this provider,
147 * it invokes ServiceLifecycle.destroy(). This is intercepted by the
148 * InvocationHandler and the Component is returned at this time back
149 * to the ComponentManager it was retrieved from.
150 * </p>
151 *
152 * <p>
153 * <b>Note</b>, when Axis invokes ServiceLifecycle.destroy() is dependant
154 * on the scope of the service (ie. Request, Session & Application).
155 * </p>
156 */
157 final class Handler implements InvocationHandler
158 {
159 // Constants describing the ServiceLifecycle.destroy method
160 private final String SL_DESTROY = "destroy";
161 private final Class SL_CLASS = ServiceLifecycle.class;
162
163 // Component & ServiceManager references
164 private final Object m_object;
165 private final ServiceManager m_manager;
166
167 /***
168 * Simple constructor, sets all internal references
169 *
170 * @param object a <code>Component</code> instance
171 * @param manager a <code>ComponentManager</code> instance
172 * @param log a <code>Logger</code> instance
173 */
174 public Handler(final Object object, final ServiceManager manager)
175 {
176 m_object = object;
177 m_manager = manager;
178 }
179
180 /***
181 * <code>invoke</code> method, handles all method invocations for this
182 * particular proxy.
183 *
184 * <p>
185 * Usually the invocation is passed through to the
186 * actual component the proxy wraps, unless the method belongs to
187 * the <code>ServiceLifecycle</code> interface where it is handled
188 * locally.
189 * </p>
190 *
191 * @param proxy the <code>Proxy</code> instance the method was invoked on
192 * @param method the invoked method <code>Method</code> object
193 * @param args an <code>Object[]</code> array of arguments
194 * @return an <code>Object</code> value or null if none
195 * @exception Throwable if an error occurs
196 */
197 public Object invoke(Object proxy, Method method, Object[] args)
198 throws Throwable
199 {
200 try
201 {
202 // if ServiceLifecycle.destroy() called, return to CM
203 if (method.getDeclaringClass().equals(SL_CLASS))
204 {
205 if (method.getName().equals(SL_DESTROY))
206 {
207 m_manager.release(m_object);
208 }
209
210 return null;
211 }
212 else // otherwise pass call to the real object
213 {
214 return method.invoke(m_object, args);
215 }
216 }
217 catch ( InvocationTargetException e )
218 {
219 throw e.getTargetException();
220 }
221 }
222 }
223 }
This page was automatically generated by Maven