001
014
015 package com.liferay.portal.fabric.status;
016
017 import com.liferay.portal.kernel.concurrent.NoticeableFuture;
018 import com.liferay.portal.kernel.process.ProcessCallable;
019 import com.liferay.portal.kernel.process.ProcessException;
020 import com.liferay.portal.kernel.util.ProxyUtil;
021
022 import java.io.Serializable;
023
024 import java.lang.annotation.ElementType;
025 import java.lang.annotation.Retention;
026 import java.lang.annotation.RetentionPolicy;
027 import java.lang.annotation.Target;
028 import java.lang.management.ManagementFactory;
029 import java.lang.management.MemoryUsage;
030 import java.lang.management.PlatformManagedObject;
031 import java.lang.management.ThreadInfo;
032 import java.lang.reflect.Array;
033 import java.lang.reflect.InvocationHandler;
034 import java.lang.reflect.Method;
035
036 import java.util.ArrayList;
037 import java.util.List;
038 import java.util.concurrent.Future;
039
040 import javax.management.Attribute;
041 import javax.management.AttributeNotFoundException;
042 import javax.management.MBeanServer;
043 import javax.management.ObjectName;
044 import javax.management.openmbean.CompositeData;
045
046
049 public class JMXProxyUtil {
050
051 public static <T> T newProxy(
052 ObjectName objectName, Class<T> interfaceClass,
053 ProcessCallableExecutor processCallableExecutor) {
054
055 ClassLoader classLoader = interfaceClass.getClassLoader();
056
057 if (classLoader == null) {
058 classLoader = ClassLoader.getSystemClassLoader();
059 }
060
061 return (T)ProxyUtil.newProxyInstance(
062 classLoader, new Class<?>[] {interfaceClass},
063 new JMXProxyInvocationHandler(objectName, processCallableExecutor));
064 }
065
066 @Retention(RetentionPolicy.RUNTIME)
067 @Target(ElementType.METHOD)
068 public @interface Optional {
069 }
070
071 public interface ProcessCallableExecutor {
072
073 public <V extends Serializable> NoticeableFuture<V> execute(
074 ProcessCallable<V> processCallable);
075
076 }
077
078 protected static Object decode(
079 Class<?> decodedClass, Serializable serializable) {
080
081 if (serializable instanceof CompositeData) {
082 return decodeCompositeData(
083 decodedClass, (CompositeData)serializable);
084 }
085
086 if ((serializable instanceof CompositeData[]) &&
087 decodedClass.isArray()) {
088
089 return decodeCompositeDataArray(
090 decodedClass, (CompositeData[])serializable);
091 }
092
093 if (decodedClass == List.class) {
094 Class<?> clazz = serializable.getClass();
095
096 if (clazz.isArray()) {
097 return decodeArrayToList(serializable);
098 }
099 }
100
101 return serializable;
102 }
103
104 protected static Object decodeArrayToList(Object array) {
105 List<Object> list = new ArrayList<>();
106
107 for (int i = 0; i < Array.getLength(array); i++) {
108 list.add(Array.get(array, i));
109 }
110
111 return list;
112 }
113
114 protected static Object decodeCompositeData(
115 Class<?> decodedClass, CompositeData compositeData) {
116
117 if (decodedClass == MemoryUsage.class) {
118 return MemoryUsage.from(compositeData);
119 }
120
121 if (decodedClass == ThreadInfo.class) {
122 return ThreadInfo.from(compositeData);
123 }
124
125 return compositeData;
126 }
127
128 protected static Object decodeCompositeDataArray(
129 Class<?> decodedClass, CompositeData[] compositeDatas) {
130
131 Object array = Array.newInstance(
132 decodedClass.getComponentType(), compositeDatas.length);
133
134 for (int i = 0; i < compositeDatas.length; i++) {
135 Array.set(
136 array, i,
137 decodeCompositeData(
138 decodedClass.getComponentType(), compositeDatas[i]));
139 }
140
141 return array;
142 }
143
144 protected static boolean equals(ObjectName objectName, Object target) {
145 if (target instanceof PlatformManagedObject) {
146 PlatformManagedObject platformManagedObject =
147 (PlatformManagedObject)target;
148
149 return objectName.equals(platformManagedObject.getObjectName());
150 }
151
152 if (ProxyUtil.isProxyClass(target.getClass())) {
153 InvocationHandler invocationHandler =
154 ProxyUtil.getInvocationHandler(target);
155
156 if (invocationHandler instanceof JMXProxyInvocationHandler) {
157 JMXProxyInvocationHandler jmxProxyInvocationHandler =
158 (JMXProxyInvocationHandler)invocationHandler;
159
160 return objectName.equals(jmxProxyInvocationHandler._objectName);
161 }
162 }
163
164 return false;
165 }
166
167 protected static boolean isGetGetter(
168 String methodName, Class<?>... parameterTypes) {
169
170 if (methodName.startsWith("get") && (parameterTypes.length == 0)) {
171 return true;
172 }
173
174 return false;
175 }
176
177 protected static boolean isIsGetter(
178 String methodName, Class<?>... parameterTypes) {
179
180 if (methodName.startsWith("is") && (parameterTypes.length == 0)) {
181 return true;
182 }
183
184 return false;
185 }
186
187 protected static boolean isObjectEquals(Method method) {
188 if (method.getDeclaringClass() == Object.class) {
189 String methodName = method.getName();
190
191 if (methodName.equals("equals")) {
192 return true;
193 }
194 }
195
196 return false;
197 }
198
199 protected static boolean isObjectHashCode(Method method) {
200 if (method.getDeclaringClass() == Object.class) {
201 String methodName = method.getName();
202
203 if (methodName.equals("hashCode")) {
204 return true;
205 }
206 }
207
208 return false;
209 }
210
211 protected static boolean isObjectToString(Method method) {
212 if (method.getDeclaringClass() == Object.class) {
213 String methodName = method.getName();
214
215 if (methodName.equals("toString")) {
216 return true;
217 }
218 }
219
220 return false;
221 }
222
223 protected static boolean isOptional(Method method) {
224 if (method.getAnnotation(Optional.class) == null) {
225 return false;
226 }
227
228 return true;
229 }
230
231 protected static boolean isSetter(
232 String methodName, Class<?>... parameterTypes) {
233
234 if (methodName.startsWith("set") && (parameterTypes.length == 1)) {
235 return true;
236 }
237
238 return false;
239 }
240
241 protected static class GetAttributeProcessCallable
242 implements ProcessCallable<Serializable> {
243
244 public GetAttributeProcessCallable(
245 ObjectName objectName, String attributeName, boolean optional) {
246
247 _objectName = objectName;
248 _attributeName = attributeName;
249 _optional = optional;
250 }
251
252 @Override
253 public Serializable call() throws ProcessException {
254 MBeanServer mBeanServer =
255 ManagementFactory.getPlatformMBeanServer();
256
257 try {
258 return (Serializable)mBeanServer.getAttribute(
259 _objectName, _attributeName);
260 }
261 catch (AttributeNotFoundException anfe) {
262 if (_optional) {
263 return null;
264 }
265
266 throw new ProcessException(anfe);
267 }
268 catch (Exception e) {
269 throw new ProcessException(e);
270 }
271 }
272
273 private static final long serialVersionUID = 1L;
274
275 private final String _attributeName;
276 private final ObjectName _objectName;
277 private final boolean _optional;
278
279 }
280
281 protected static class JMXProxyInvocationHandler
282 implements InvocationHandler {
283
284 public JMXProxyInvocationHandler(
285 ObjectName objectName,
286 ProcessCallableExecutor processCallableExecutor) {
287
288 _objectName = objectName;
289 _processCallableExecutor = processCallableExecutor;
290 }
291
292 @Override
293 public Object invoke(Object proxy, Method method, Object[] args)
294 throws Throwable {
295
296 if (isObjectEquals(method)) {
297 return JMXProxyUtil.equals(_objectName, args[0]);
298 }
299
300 if (isObjectHashCode(method)) {
301 return _objectName.hashCode();
302 }
303
304 if (isObjectToString(method)) {
305 return _objectName.toString();
306 }
307
308 String methodName = method.getName();
309
310 Class<?>[] parameterTypes = method.getParameterTypes();
311
312 ProcessCallable<Serializable> processCallable = null;
313
314 if (isGetGetter(methodName, parameterTypes)) {
315 processCallable = new GetAttributeProcessCallable(
316 _objectName, methodName.substring(3), isOptional(method));
317 }
318 else if (isIsGetter(methodName, parameterTypes)) {
319 processCallable = new GetAttributeProcessCallable(
320 _objectName, methodName.substring(2), isOptional(method));
321 }
322 else if (isSetter(methodName, parameterTypes)) {
323 processCallable = new SetAttributeProcessCallable(
324 _objectName, methodName.substring(3), (Serializable)args[0],
325 isOptional(method));
326 }
327 else {
328 String[] parameterTypeNames = new String[parameterTypes.length];
329
330 for (int i = 0; i < parameterTypes.length; i++) {
331 parameterTypeNames[i] = parameterTypes[i].getName();
332 }
333
334 processCallable = new OperationProcessCallable(
335 _objectName, methodName, args, parameterTypeNames);
336 }
337
338 Future<? extends Serializable> future =
339 _processCallableExecutor.execute(processCallable);
340
341 return decode(method.getReturnType(), future.get());
342 }
343
344 private final ObjectName _objectName;
345 private final ProcessCallableExecutor _processCallableExecutor;
346
347 }
348
349 protected static class OperationProcessCallable
350 implements ProcessCallable<Serializable> {
351
352 public OperationProcessCallable(
353 ObjectName objectName, String operationName, Object[] arguments,
354 String[] parameterTypeNames) {
355
356 _objectName = objectName;
357 _operationName = operationName;
358 _arguments = arguments;
359 _parameterTypeNames = parameterTypeNames;
360 }
361
362 @Override
363 public Serializable call() throws ProcessException {
364 MBeanServer mBeanServer =
365 ManagementFactory.getPlatformMBeanServer();
366
367 try {
368 return (Serializable)mBeanServer.invoke(
369 _objectName, _operationName, _arguments,
370 _parameterTypeNames);
371 }
372 catch (Exception e) {
373 throw new ProcessException(e);
374 }
375 }
376
377 private static final long serialVersionUID = 1L;
378
379 private final Object[] _arguments;
380 private final ObjectName _objectName;
381 private final String _operationName;
382 private final String[] _parameterTypeNames;
383
384 }
385
386 protected static class SetAttributeProcessCallable
387 implements ProcessCallable<Serializable> {
388
389 public SetAttributeProcessCallable(
390 ObjectName objectName, String attributeName,
391 Serializable attributeValue, boolean optional) {
392
393 _objectName = objectName;
394 _attributeName = attributeName;
395 _attributeValue = attributeValue;
396 _optional = optional;
397 }
398
399 @Override
400 public Serializable call() throws ProcessException {
401 MBeanServer mBeanServer =
402 ManagementFactory.getPlatformMBeanServer();
403
404 try {
405 mBeanServer.setAttribute(
406 _objectName,
407 new Attribute(_attributeName, _attributeValue));
408 }
409 catch (AttributeNotFoundException anfe) {
410 if (!_optional) {
411 throw new ProcessException(anfe);
412 }
413 }
414 catch (Exception e) {
415 throw new ProcessException(e);
416 }
417
418 return null;
419 }
420
421 private static final long serialVersionUID = 1L;
422
423 private final String _attributeName;
424 private final Serializable _attributeValue;
425 private final ObjectName _objectName;
426 private final boolean _optional;
427
428 }
429
430 }