001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.notification;
023:
024: import java.lang.reflect.InvocationHandler;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Proxy;
027:
028: import javax.management.Notification;
029: import javax.management.NotificationListener;
030: import javax.management.ObjectName;
031:
032: /**
033: * A notification listener used to forward notifications to listeners
034: * added through the mbean server.<p>
035: *
036: * The original source is replaced with the object name.
037: *
038: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
039: * @author <a href="mailto:telrod@e2technologies.net">Tom Elrod</a>.
040: * @version $Revision: 57200 $
041: */
042: public class NotificationListenerProxy implements InvocationHandler {
043: // Constants ---------------------------------------------------
044:
045: // Attributes --------------------------------------------------
046:
047: /**
048: * The original listener
049: */
050: private NotificationListener listener;
051:
052: /**
053: * The object name we are proxying
054: */
055: private ObjectName name;
056:
057: /**
058: * The implementation method for NotificationListener
059: * that we want to intercept so that we can set the source
060: * of the Notification object.
061: */
062: private static final String METHODNAME = "handleNotification";
063:
064: /**
065: * Calculated hascode
066: */
067: private final Integer hashCode;
068:
069: // Static ------------------------------------------------------
070:
071: public static Object newInstance(ObjectName name,
072: NotificationListener listener) {
073: // Using set so don't have interface duplicates (which shouldn't happen anyways)
074: java.util.HashSet set = new java.util.HashSet();
075:
076: // Walk the class heirarchy tree and get all interfaces.
077: Class currentClass = listener.getClass();
078: while (currentClass != null) {
079: Class[] classInterfaces = currentClass.getInterfaces();
080: for (int i = 0; i < classInterfaces.length; i++) {
081: set.add(classInterfaces[i]);
082: }
083: currentClass = currentClass.getSuperclass();
084: }
085: Class[] interfaces = new Class[set.size()];
086: interfaces = (Class[]) set.toArray(interfaces);
087:
088: return Proxy.newProxyInstance(listener.getClass()
089: .getClassLoader(), interfaces,
090: new NotificationListenerProxy(name, listener));
091: }
092:
093: // Constructors ------------------------------------------------
094:
095: /**
096: * Create a new Notification Listener Proxy
097: *
098: * @param name the object name
099: * @param listener the original listener
100: */
101: public NotificationListenerProxy(ObjectName name,
102: NotificationListener listener) {
103: this .name = name;
104: this .listener = listener;
105: this .hashCode = new Integer(System.identityHashCode(this ));
106:
107: // Could add code to set the METHODNAME variable based
108: // on the method signature names from the actual listener
109: // interface passed (which would be done dynamically so would
110: // not be hard-coded), in case the NotificationListener
111: // method signature changes.
112: }
113:
114: // Public ------------------------------------------------------
115:
116: // implementation InvocationHandler
117: public Object invoke(Object proxy, Method method, Object[] args)
118: throws Throwable {
119: String localMethodName = method.getName();
120: // check to see if calling handleNotification() method
121: if (localMethodName.equals(METHODNAME)) {
122: for (int x = 0; x < args.length; x++) {
123: if (args[x] instanceof Notification) {
124: // Forward the notification with the object name as source
125: // FIXME: This overwrites the original source, there is no way
126: // to put it back with the current spec
127: ((Notification) args[x]).setSource(name);
128: }
129: }
130: } else if (localMethodName.equals("hashCode")) {
131: return proxyHashCode(proxy);
132: } else if (localMethodName.equals("equals")) {
133: return proxyEquals(proxy, args[0]);
134: } else if (localMethodName.equals("toString")) {
135: return proxyToString(proxy);
136: }
137: return method.invoke(listener, args);
138: }
139:
140: protected Integer proxyHashCode(Object proxy) {
141: return this .hashCode;
142: }
143:
144: protected Boolean proxyEquals(Object proxy, Object other) {
145: return (proxy == other ? Boolean.TRUE : Boolean.FALSE);
146: }
147:
148: protected String proxyToString(Object proxy) {
149: return proxy.getClass().getName() + '@'
150: + Integer.toHexString(proxy.hashCode());
151: }
152:
153: // overrides ---------------------------------------------------
154:
155: // Protected ---------------------------------------------------
156:
157: // Private -----------------------------------------------------
158:
159: // Inner classes -----------------------------------------------
160: }
|