1 /**
2 *
3 * Copyright 2004 The Apache Software Foundation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.geronimo.system.jmx;
18
19 import net.sf.cglib.asm.Type;
20 import net.sf.cglib.core.Signature;
21 import net.sf.cglib.proxy.MethodInterceptor;
22 import net.sf.cglib.proxy.MethodProxy;
23 import net.sf.cglib.reflect.FastClass;
24 import org.apache.geronimo.gbean.AbstractName;
25 import org.apache.geronimo.kernel.Kernel;
26 import org.apache.geronimo.kernel.basic.KernelGetAttributeInvoker;
27 import org.apache.geronimo.kernel.basic.KernelOperationInvoker;
28 import org.apache.geronimo.kernel.basic.KernelSetAttributeInvoker;
29 import org.apache.geronimo.kernel.basic.ProxyInvoker;
30 import org.apache.geronimo.kernel.management.State;
31 import org.apache.geronimo.kernel.proxy.DeadProxyException;
32 import org.apache.geronimo.kernel.proxy.GeronimoManagedBean;
33
34 import java.lang.reflect.Method;
35 import java.lang.reflect.Modifier;
36
37 /**
38 * @version $Rev: 430508 $ $Date: 2006-08-10 12:56:47 -0700 (Thu, 10 Aug 2006) $
39 */
40 public class JMXProxyMethodInterceptor implements MethodInterceptor {
41 /**
42 * Type of the proxy interface
43 */
44 private final Class proxyType;
45
46 /**
47 * The object name to which we are connected.
48 */
49 private final AbstractName objectName;
50
51 /**
52 * GBeanInvokers keyed on the proxy interface method index
53 */
54 private ProxyInvoker[] gbeanInvokers;
55
56 public JMXProxyMethodInterceptor(Class proxyType, Kernel kernel, AbstractName targetName) {
57 assert proxyType != null;
58 assert kernel != null;
59 assert targetName != null;
60
61 this.proxyType = proxyType;
62 this.objectName = targetName;
63 gbeanInvokers = createGBeanInvokers(kernel);
64 }
65
66 public synchronized void destroy() {
67 gbeanInvokers = null;
68 }
69
70 public AbstractName getAbstractName() {
71 return objectName;
72 }
73
74 public final Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {
75 ProxyInvoker gbeanInvoker;
76
77 int interfaceIndex = proxy.getSuperIndex();
78 synchronized (this) {
79 if (gbeanInvokers == null) {
80 throw new DeadProxyException("Proxy is no longer valid");
81 }
82 gbeanInvoker = gbeanInvokers[interfaceIndex];
83 }
84
85 if (gbeanInvoker == null) {
86 throw new UnsupportedOperationException("No implementation method: objectName=" + objectName + ", method=" + method);
87 }
88
89 return gbeanInvoker.invoke(objectName, args);
90 }
91
92 private ProxyInvoker[] createGBeanInvokers(Kernel kernel) {
93
94 FastClass fastClass = FastClass.create(proxyType);
95 ProxyInvoker[] invokers = new ProxyInvoker[fastClass.getMaxIndex() + 1];
96 Method[] methods = proxyType.getMethods();
97 for (int i = 0; i < methods.length; i++) {
98 Method method = methods[i];
99 int interfaceIndex = getSuperIndex(proxyType, method);
100 if (interfaceIndex >= 0) {
101 invokers[interfaceIndex] = createProxyInvoker(kernel, method);
102 }
103 }
104
105
106 try {
107 invokers[getSuperIndex(proxyType, proxyType.getMethod("equals", new Class[]{Object.class}))] = new EqualsInvoke(kernel);
108 invokers[getSuperIndex(proxyType, proxyType.getMethod("hashCode", null))] = new HashCodeInvoke();
109 invokers[getSuperIndex(proxyType, proxyType.getMethod("toString", null))] = new ToStringInvoke(proxyType.getName());
110 if(GeronimoManagedBean.class.isAssignableFrom(proxyType)) {
111 invokers[getSuperIndex(proxyType, proxyType.getMethod("getState", null))] = new GetStateInvoke(kernel);
112 invokers[getSuperIndex(proxyType, proxyType.getMethod("getStateInstance", null))] = new GetStateInstanceInvoke(kernel);
113 invokers[getSuperIndex(proxyType, proxyType.getMethod("start", null))] = new StartInvoke(kernel);
114 invokers[getSuperIndex(proxyType, proxyType.getMethod("startRecursive", null))] = new StartRecursiveInvoke(kernel);
115 invokers[getSuperIndex(proxyType, proxyType.getMethod("stop", null))] = new StopInvoke(kernel);
116 invokers[getSuperIndex(proxyType, proxyType.getMethod("getStartTime", null))] = new GetStartTimeInvoke(kernel);
117 invokers[getSuperIndex(proxyType, proxyType.getMethod("getObjectName", null))] = new GetObjectNameInvoke();
118 }
119 } catch (Exception e) {
120
121 throw new AssertionError(e);
122 }
123
124 return invokers;
125 }
126
127 private ProxyInvoker createProxyInvoker(Kernel kernel, Method method) {
128 String methodName = method.getName();
129 if (!Modifier.isPublic(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
130 return null;
131 }
132
133
134 if (method.getParameterTypes().length == 0 && method.getReturnType() != Void.TYPE) {
135 if (methodName.length() > 3 && methodName.startsWith("get") && !methodName.equals("getClass")) {
136 String propertyName = decapitalizePropertyName(methodName.substring(3));
137 return new KernelGetAttributeInvoker(kernel, propertyName);
138 } else if (methodName.length() > 2 && methodName.startsWith("is")) {
139 String propertyName = decapitalizePropertyName(methodName.substring(2));
140 return new KernelGetAttributeInvoker(kernel, propertyName);
141 }
142 }
143
144
145 if (method.getParameterTypes().length == 1 &&
146 method.getReturnType() == Void.TYPE &&
147 methodName.length() > 3 &&
148 methodName.startsWith("set")) {
149 String propertyName = decapitalizePropertyName(methodName.substring(3));
150 return new KernelSetAttributeInvoker(kernel, propertyName);
151 }
152
153
154 return new KernelOperationInvoker(kernel, method);
155 }
156
157 private static int getSuperIndex(Class proxyType, Method method) {
158 Signature signature = new Signature(method.getName(), Type.getReturnType(method), Type.getArgumentTypes(method));
159 MethodProxy methodProxy = MethodProxy.find(proxyType, signature);
160 if (methodProxy != null) {
161 return methodProxy.getSuperIndex();
162 }
163 return -1;
164 }
165
166 private static String decapitalizePropertyName(String propertyName) {
167 if (Character.isUpperCase(propertyName.charAt(0))) {
168 return Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
169 }
170 return propertyName;
171 }
172
173 static final class HashCodeInvoke implements ProxyInvoker {
174 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
175 return new Integer(abstractName.hashCode());
176 }
177 }
178
179 static final class EqualsInvoke implements ProxyInvoker {
180 private final Kernel kernel;
181
182 public EqualsInvoke(Kernel kernel) {
183 this.kernel = kernel;
184 }
185
186 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
187 AbstractName proxyTarget = kernel.getAbstractNameFor(arguments[0]);
188 return Boolean.valueOf(abstractName.equals(proxyTarget));
189 }
190 }
191
192 static final class ToStringInvoke implements ProxyInvoker {
193 private final String interfaceName;
194
195 public ToStringInvoke(String interfaceName) {
196 this.interfaceName = "[" + interfaceName + ": ";
197 }
198
199 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
200 return interfaceName + abstractName + "]";
201 }
202 }
203
204 static final class GetStateInvoke implements ProxyInvoker {
205 private Kernel kernel;
206
207 public GetStateInvoke(Kernel kernel) {
208 this.kernel = kernel;
209 }
210
211 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
212 return new Integer(kernel.getGBeanState(abstractName));
213 }
214 }
215
216 static final class GetStateInstanceInvoke implements ProxyInvoker {
217 private Kernel kernel;
218
219 public GetStateInstanceInvoke(Kernel kernel) {
220 this.kernel = kernel;
221 }
222
223 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
224 return State.fromInt(kernel.getGBeanState(abstractName));
225 }
226 }
227
228 static final class StartInvoke implements ProxyInvoker {
229 private Kernel kernel;
230
231 public StartInvoke(Kernel kernel) {
232 this.kernel = kernel;
233 }
234
235 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
236 kernel.startGBean(abstractName);
237 return null;
238 }
239 }
240
241 static final class StartRecursiveInvoke implements ProxyInvoker {
242 private Kernel kernel;
243
244 public StartRecursiveInvoke(Kernel kernel) {
245 this.kernel = kernel;
246 }
247
248 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
249 kernel.startRecursiveGBean(abstractName);
250 return null;
251 }
252 }
253
254 static final class GetStartTimeInvoke implements ProxyInvoker {
255 private Kernel kernel;
256
257 public GetStartTimeInvoke(Kernel kernel) {
258 this.kernel = kernel;
259 }
260
261 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
262 return new Long(kernel.getGBeanStartTime(abstractName));
263 }
264 }
265
266 static final class StopInvoke implements ProxyInvoker {
267 private Kernel kernel;
268
269 public StopInvoke(Kernel kernel) {
270 this.kernel = kernel;
271 }
272
273 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
274 kernel.stopGBean(abstractName);
275 return null;
276 }
277 }
278
279 static final class GetObjectNameInvoke implements ProxyInvoker {
280 public Object invoke(AbstractName abstractName, Object[] arguments) throws Throwable {
281 return abstractName.getObjectName().getCanonicalName();
282 }
283 }
284 }