KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > jmx > connector > invoker > InvokerAdaptorService


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.jmx.connector.invoker;
23
24 import java.lang.reflect.InvocationTargetException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.lang.reflect.UndeclaredThrowableException JavaDoc;
27 import java.rmi.RemoteException JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.security.Principal JavaDoc;
33 import javax.management.InstanceNotFoundException JavaDoc;
34 import javax.management.ListenerNotFoundException JavaDoc;
35 import javax.management.MBeanServer JavaDoc;
36 import javax.management.Notification JavaDoc;
37 import javax.management.NotificationFilter JavaDoc;
38 import javax.management.NotificationListener JavaDoc;
39 import javax.management.ObjectName JavaDoc;
40
41 import org.jboss.invocation.Invocation;
42 import org.jboss.invocation.MarshalledInvocation;
43 import org.jboss.jmx.adaptor.rmi.RMINotificationListener;
44 import org.jboss.jmx.connector.invoker.client.InvokerAdaptorException;
45 import org.jboss.mx.server.ServerConstants;
46 import org.jboss.system.Registry;
47 import org.jboss.system.ServiceMBeanSupport;
48
49 /**
50  * A JBoss service exposes an invoke(Invocation) operation that maps
51  * calls to the ExposedInterface onto the MBeanServer this service
52  * is registered with. It is used in conjunction with a proxy factory
53  * to expose the MBeanServer to remote clients through arbitrary
54  * protocols.<p>
55  *
56  * It sets up the correct classloader before unmarshalling the
57  * arguments, this relies on the ObjectName being seperate from
58  * from the other method arguments to avoid unmarshalling them
59  * before the classloader is determined from the ObjectName.<p>
60  *
61  * The interface is configurable, it must be similar to MBeanServer,
62  * though not necessarily derived from it<p>
63  *
64  * The invoker is configurable and must be specified
65  *
66  * @author <a HREF="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>
67  * @author Scott.Stark@jboss.org
68  * @version $Revision: 37459 $
69  *
70  * @jmx:mbean name="jboss.jmx:type=adaptor,protocol=INVOKER"
71  * extends="org.jboss.system.ServiceMBean"
72  **/

73 public class InvokerAdaptorService
74    extends ServiceMBeanSupport
75    implements InvokerAdaptorServiceMBean, ServerConstants
76 {
77    private ObjectName JavaDoc mbeanRegistry;
78    /** */
79    private Map JavaDoc marshalledInvocationMapping = new HashMap JavaDoc();
80    /** */
81    private Class JavaDoc[] exportedInterfaces;
82    /** A HashSet<Method> addNotificationListener methods */
83    private HashSet JavaDoc addNotificationListeners = new HashSet JavaDoc();
84    /** A HashSet<Method> removeNotificationListener methods */
85    private HashSet JavaDoc removeNotificationListeners = new HashSet JavaDoc();
86    /** A HashSet<RMINotificationListener, NotificationListenerDelegate> for the
87     registered listeners */

88    protected HashMap JavaDoc remoteListeners = new HashMap JavaDoc();
89
90    public InvokerAdaptorService()
91    {
92    }
93
94    /**
95     * @jmx:managed-attribute
96     */

97    public Class JavaDoc[] getExportedInterfaces()
98    {
99       return exportedInterfaces;
100    }
101    /**
102     * @jmx:managed-attribute
103     */

104    public void setExportedInterfaces(Class JavaDoc[] exportedInterfaces)
105    {
106       this.exportedInterfaces = exportedInterfaces;
107    }
108
109    protected void startService()
110       throws Exception JavaDoc
111    {
112       mbeanRegistry = new ObjectName JavaDoc(MBEAN_REGISTRY);
113
114       // Build the interface method map
115
HashMap JavaDoc tmpMap = new HashMap JavaDoc(61);
116       for(int n = 0; n < exportedInterfaces.length; n ++)
117       {
118          Class JavaDoc iface = exportedInterfaces[n];
119          Method JavaDoc[] methods = iface.getMethods();
120          for(int m = 0; m < methods.length; m ++)
121          {
122             Method JavaDoc method = methods[m];
123             Long JavaDoc hash = new Long JavaDoc(MarshalledInvocation.calculateHash(method));
124             tmpMap.put(hash, method);
125          }
126          /* Look for a void addNotificationListener(ObjectName name,
127                RMINotificationListener listener, NotificationFilter filter,
128                Object handback)
129          */

130          try
131          {
132             Class JavaDoc[] sig = {ObjectName JavaDoc.class, RMINotificationListener.class,
133                NotificationFilter JavaDoc.class, Object JavaDoc.class};
134             Method JavaDoc addNotificationListener = iface.getMethod(
135                "addNotificationListener", sig);
136             addNotificationListeners.add(addNotificationListener);
137          }
138          catch(Exception JavaDoc e)
139          {
140             log.debug(iface+"No addNotificationListener(ObjectName, RMINotificationListener)");
141          }
142
143          /* Look for a void removeNotificationListener(ObjectName,
144             RMINotificationListener)
145          */

146          try
147          {
148             Class JavaDoc[] sig = {ObjectName JavaDoc.class, RMINotificationListener.class};
149             Method JavaDoc removeNotificationListener = iface.getMethod(
150                "removeNotificationListener", sig);
151             removeNotificationListeners.add(removeNotificationListener);
152          }
153          catch(Exception JavaDoc e)
154          {
155             log.debug(iface+"No removeNotificationListener(ObjectName, RMINotificationListener)");
156          }
157       }
158       marshalledInvocationMapping = Collections.unmodifiableMap(tmpMap);
159
160       // Place our ObjectName hash into the Registry so invokers can resolve it
161
Registry.bind(new Integer JavaDoc(serviceName.hashCode()), serviceName);
162    }
163
164    protected void stopService()
165       throws Exception JavaDoc
166    {
167       // Remove the method hashses
168
if( exportedInterfaces != null )
169       {
170          for(int n = 0; n < exportedInterfaces.length; n ++)
171             MarshalledInvocation.removeHashes(exportedInterfaces[n]);
172       }
173       marshalledInvocationMapping = null;
174       remoteListeners.clear();
175       Registry.unbind(new Integer JavaDoc(serviceName.hashCode()));
176    }
177
178    /**
179     * Expose the service interface mapping as a read-only attribute
180     *
181     * @jmx:managed-attribute
182     *
183     * @return A Map<Long hash, Method> of the MBeanServer
184     */

185    public Map JavaDoc getMethodMap()
186    {
187       return marshalledInvocationMapping;
188    }
189
190    /**
191     * Expose the MBeanServer service via JMX to invokers.
192     *
193     * @jmx:managed-operation
194     *
195     * @param invocation A pointer to the invocation object
196     * @return Return value of method invocation.
197     *
198     * @throws Exception Failed to invoke method.
199     */

200    public Object JavaDoc invoke(Invocation invocation)
201        throws Exception JavaDoc
202    {
203       try
204       {
205          // Make sure we have the correct classloader before unmarshalling
206
ClassLoader JavaDoc oldCL = SecurityActions.getContextClassLoader();
207
208          ClassLoader JavaDoc newCL = null;
209          // Get the MBean this operation applies to
210
ObjectName JavaDoc objectName = (ObjectName JavaDoc) invocation.getValue("JMX_OBJECT_NAME");
211          if (objectName != null)
212          {
213             // Obtain the ClassLoader associated with the MBean deployment
214
newCL = (ClassLoader JavaDoc) server.invoke
215             (
216                mbeanRegistry, "getValue",
217                new Object JavaDoc[] { objectName, CLASSLOADER },
218                new String JavaDoc[] { ObjectName JavaDoc.class.getName(), String JavaDoc.class.getName() }
219             );
220          }
221
222          if (newCL != null && newCL != oldCL)
223             SecurityActions.setContextClassLoader(newCL);
224
225          try
226          {
227             // Set the method hash to Method mapping
228
if (invocation instanceof MarshalledInvocation)
229             {
230                MarshalledInvocation mi = (MarshalledInvocation) invocation;
231                mi.setMethodMap(marshalledInvocationMapping);
232             }
233             // Invoke the MBeanServer method via reflection
234
Method JavaDoc method = invocation.getMethod();
235             Object JavaDoc[] args = invocation.getArguments();
236             Principal JavaDoc principal = invocation.getPrincipal();
237             Object JavaDoc credential = invocation.getCredential();
238             Object JavaDoc value = null;
239             // Associate the method
240
SecurityActions.pushSubjectContext(principal, credential, null);
241
242             try
243             {
244                if( addNotificationListeners.contains(method) )
245                {
246                   ObjectName JavaDoc name = (ObjectName JavaDoc) args[0];
247                   RMINotificationListener listener = (RMINotificationListener)
248                      args[1];
249                   NotificationFilter JavaDoc filter = (NotificationFilter JavaDoc) args[2];
250                   Object JavaDoc handback = args[3];
251                   addNotificationListener(name, listener, filter, handback);
252                }
253                else if( removeNotificationListeners.contains(method) )
254                {
255                   ObjectName JavaDoc name = (ObjectName JavaDoc) args[0];
256                   RMINotificationListener listener = (RMINotificationListener)
257                      args[1];
258                   removeNotificationListener(name, listener);
259                }
260                else
261                {
262                   String JavaDoc name = method.getName();
263                   Class JavaDoc[] paramTypes = method.getParameterTypes();
264                   Method JavaDoc mbeanServerMethod = MBeanServer JavaDoc.class.getMethod(name,
265                      paramTypes);
266                   value = mbeanServerMethod.invoke(server, args);
267                }
268             }
269             catch(InvocationTargetException JavaDoc e)
270             {
271                Throwable JavaDoc t = e.getTargetException();
272                if( t instanceof Exception JavaDoc )
273                   throw (Exception JavaDoc) t;
274                else
275                   throw new UndeclaredThrowableException JavaDoc(t, method.toString());
276             }
277
278             return value;
279          }
280          finally
281          {
282             // Restore the input security context
283
SecurityActions.popSubjectContext();
284             // Restore the input class loader
285
if (newCL != null && newCL != oldCL)
286                SecurityActions.setContextClassLoader(oldCL);
287          }
288       }
289       catch (Throwable JavaDoc t)
290       {
291          throw new InvokerAdaptorException(t);
292       }
293    }
294
295    public void addNotificationListener(ObjectName JavaDoc name,
296       RMINotificationListener listener, NotificationFilter JavaDoc filter,
297       Object JavaDoc handback)
298       throws InstanceNotFoundException JavaDoc, RemoteException JavaDoc
299    {
300       if( log.isTraceEnabled() )
301          log.trace("addNotificationListener, name="+name+", listener="+listener);
302       NotificationListenerDelegate delegate =
303          new NotificationListenerDelegate(listener, name);
304       remoteListeners.put(listener, delegate);
305       getServer().addNotificationListener(name, delegate, filter, handback);
306    }
307
308    public void removeNotificationListener(ObjectName JavaDoc name,
309       RMINotificationListener listener)
310       throws InstanceNotFoundException JavaDoc, ListenerNotFoundException JavaDoc,
311       RemoteException JavaDoc
312    {
313       if( log.isTraceEnabled() )
314          log.trace("removeNotificationListener, name="+name+", listener="+listener);
315       NotificationListenerDelegate delegate = (NotificationListenerDelegate)
316          remoteListeners.remove(listener);
317       if( delegate == null )
318          throw new ListenerNotFoundException JavaDoc("No listener matches: "+listener);
319       getServer().removeNotificationListener(name, delegate);
320    }
321
322    private class NotificationListenerDelegate
323       implements NotificationListener JavaDoc
324    {
325       /** The remote client */
326       private RMINotificationListener client;
327       /** The mbean the client is monitoring */
328       private ObjectName JavaDoc targetName;
329
330       public NotificationListenerDelegate(RMINotificationListener client,
331          ObjectName JavaDoc targetName)
332       {
333          this.client = client;
334          this.targetName = targetName;
335       }
336
337       public void handleNotification(Notification JavaDoc notification,
338          Object JavaDoc handback)
339       {
340          try
341          {
342             if( log.isTraceEnabled() )
343             {
344                log.trace("Sending notification to client, event:"+notification);
345             }
346             client.handleNotification(notification, handback);
347          }
348          catch(Throwable JavaDoc t)
349          {
350             log.debug("Failed to notify client, unregistering listener", t);
351             try
352             {
353                removeNotificationListener(targetName, client);
354             }
355             catch(Exception JavaDoc e)
356             {
357                log.debug("Failed to unregister listener", e);
358             }
359          }
360       }
361    }
362
363 }
364
Popular Tags