1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.mina.integration.jmx;
18
19 import java.beans.IntrospectionException;
20 import java.beans.Introspector;
21 import java.beans.PropertyDescriptor;
22 import java.beans.PropertyEditor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.net.SocketAddress;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Date;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.LinkedHashMap;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.concurrent.ConcurrentHashMap;
37 import java.util.concurrent.ThreadPoolExecutor;
38
39 import javax.management.Attribute;
40 import javax.management.AttributeChangeNotification;
41 import javax.management.AttributeList;
42 import javax.management.AttributeNotFoundException;
43 import javax.management.InstanceNotFoundException;
44 import javax.management.ListenerNotFoundException;
45 import javax.management.MBeanException;
46 import javax.management.MBeanInfo;
47 import javax.management.MBeanNotificationInfo;
48 import javax.management.MBeanParameterInfo;
49 import javax.management.MBeanRegistration;
50 import javax.management.MBeanServer;
51 import javax.management.Notification;
52 import javax.management.NotificationFilter;
53 import javax.management.NotificationListener;
54 import javax.management.ObjectName;
55 import javax.management.ReflectionException;
56 import javax.management.RuntimeOperationsException;
57 import javax.management.modelmbean.InvalidTargetObjectTypeException;
58 import javax.management.modelmbean.ModelMBean;
59 import javax.management.modelmbean.ModelMBeanAttributeInfo;
60 import javax.management.modelmbean.ModelMBeanConstructorInfo;
61 import javax.management.modelmbean.ModelMBeanInfo;
62 import javax.management.modelmbean.ModelMBeanInfoSupport;
63 import javax.management.modelmbean.ModelMBeanNotificationInfo;
64 import javax.management.modelmbean.ModelMBeanOperationInfo;
65
66 import ognl.ExpressionSyntaxException;
67 import ognl.InappropriateExpressionException;
68 import ognl.NoSuchPropertyException;
69 import ognl.Ognl;
70 import ognl.OgnlContext;
71 import ognl.OgnlException;
72 import ognl.OgnlRuntime;
73 import ognl.TypeConverter;
74
75 import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;
76 import org.apache.mina.core.filterchain.IoFilter;
77 import org.apache.mina.core.filterchain.IoFilterChain;
78 import org.apache.mina.core.filterchain.IoFilterChainBuilder;
79 import org.apache.mina.core.service.IoAcceptor;
80 import org.apache.mina.core.service.IoHandler;
81 import org.apache.mina.core.service.IoService;
82 import org.apache.mina.core.service.TransportMetadata;
83 import org.apache.mina.core.session.IoSession;
84 import org.apache.mina.core.session.IoSessionDataStructureFactory;
85 import org.apache.mina.filter.executor.ExecutorFilter;
86 import org.apache.mina.integration.beans.CollectionEditor;
87 import org.apache.mina.integration.beans.ListEditor;
88 import org.apache.mina.integration.beans.MapEditor;
89 import org.apache.mina.integration.beans.PropertyEditorFactory;
90 import org.apache.mina.integration.beans.SetEditor;
91 import org.apache.mina.integration.ognl.IoFilterPropertyAccessor;
92 import org.apache.mina.integration.ognl.IoServicePropertyAccessor;
93 import org.apache.mina.integration.ognl.IoSessionPropertyAccessor;
94 import org.apache.mina.integration.ognl.PropertyTypeConverter;
95 import org.slf4j.Logger;
96 import org.slf4j.LoggerFactory;
97
98
99
100
101
102
103
104
105 public class ObjectMBean<T> implements ModelMBean, MBeanRegistration {
106
107 private static final Map<ObjectName, Object> sources = new ConcurrentHashMap<ObjectName, Object>();
108
109 public static Object getSource(ObjectName oname) {
110 return sources.get(oname);
111 }
112
113 static {
114 OgnlRuntime.setPropertyAccessor(IoService.class, new IoServicePropertyAccessor());
115 OgnlRuntime.setPropertyAccessor(IoSession.class, new IoSessionPropertyAccessor());
116 OgnlRuntime.setPropertyAccessor(IoFilter.class, new IoFilterPropertyAccessor());
117 }
118
119 protected final static Logger LOGGER = LoggerFactory.getLogger(ObjectMBean.class);
120
121 private final T source;
122
123 private final TransportMetadata transportMetadata;
124
125 private final MBeanInfo info;
126
127 private final Map<String, PropertyDescriptor> propertyDescriptors = new HashMap<String, PropertyDescriptor>();
128
129 private final TypeConverter typeConverter = new OgnlTypeConverter();
130
131 private volatile MBeanServer server;
132
133 private volatile ObjectName name;
134
135
136
137
138 public ObjectMBean(T source) {
139 if (source == null) {
140 throw new IllegalArgumentException("source");
141 }
142
143 this.source = source;
144
145 if (source instanceof IoService) {
146 transportMetadata = ((IoService) source).getTransportMetadata();
147 } else if (source instanceof IoSession) {
148 transportMetadata = ((IoSession) source).getTransportMetadata();
149 } else {
150 transportMetadata = null;
151 }
152
153 this.info = createModelMBeanInfo(source);
154 }
155
156 public final Object getAttribute(String fqan) throws AttributeNotFoundException, MBeanException,
157 ReflectionException {
158 try {
159 return convertValue(source.getClass(), fqan, getAttribute0(fqan), false);
160 } catch (AttributeNotFoundException e) {
161
162 } catch (Throwable e) {
163 throwMBeanException(e);
164 }
165
166
167 PropertyDescriptor pdesc = propertyDescriptors.get(fqan);
168 if (pdesc == null) {
169 throwMBeanException(new IllegalArgumentException("Unknown attribute: " + fqan));
170 }
171
172 try {
173
174 Object parent = getParent(fqan);
175 boolean writable = isWritable(source.getClass(), pdesc);
176
177 return convertValue(parent.getClass(), getLeafAttributeName(fqan),
178 getAttribute(source, fqan, pdesc.getPropertyType()), writable);
179 } catch (Throwable e) {
180 throwMBeanException(e);
181 }
182
183 throw new IllegalStateException();
184 }
185
186 public final void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException,
187 ReflectionException {
188 String aname = attribute.getName();
189 Object avalue = attribute.getValue();
190
191 try {
192 setAttribute0(aname, avalue);
193 } catch (AttributeNotFoundException e) {
194
195 } catch (Throwable e) {
196 throwMBeanException(e);
197 }
198
199 PropertyDescriptor pdesc = propertyDescriptors.get(aname);
200 if (pdesc == null) {
201 throwMBeanException(new IllegalArgumentException("Unknown attribute: " + aname));
202 }
203
204 try {
205 PropertyEditor e = getPropertyEditor(getParent(aname).getClass(), pdesc.getName(), pdesc.getPropertyType());
206 e.setAsText((String) avalue);
207 OgnlContext ctx = (OgnlContext) Ognl.createDefaultContext(source);
208 ctx.setTypeConverter(typeConverter);
209 Ognl.setValue(aname, ctx, source, e.getValue());
210 } catch (Throwable e) {
211 throwMBeanException(e);
212 }
213 }
214
215 public final Object invoke(String name, Object params[], String signature[]) throws MBeanException,
216 ReflectionException {
217
218
219 if (name.equals("unregisterMBean")) {
220 try {
221 server.unregisterMBean(this.name);
222 return null;
223 } catch (InstanceNotFoundException e) {
224 throwMBeanException(e);
225 }
226 }
227
228 try {
229 return convertValue(null, null, invoke0(name, params, signature), false);
230 } catch (NoSuchMethodException e) {
231
232 } catch (Throwable e) {
233 throwMBeanException(e);
234 }
235
236
237 Class<?>[] paramTypes = new Class[signature.length];
238 for (int i = 0; i < paramTypes.length; i++) {
239 try {
240 paramTypes[i] = getAttributeClass(signature[i]);
241 } catch (ClassNotFoundException e) {
242 throwMBeanException(e);
243 }
244
245 PropertyEditor e = getPropertyEditor(source.getClass(), "p" + i, paramTypes[i]);
246 if (e == null) {
247 throwMBeanException(new RuntimeException("Conversion failure: " + params[i]));
248 }
249
250 e.setValue(params[i]);
251 params[i] = e.getAsText();
252 }
253
254 try {
255
256 for (Method m : source.getClass().getMethods()) {
257 if (!m.getName().equalsIgnoreCase(name)) {
258 continue;
259 }
260 Class<?>[] methodParamTypes = m.getParameterTypes();
261 if (methodParamTypes.length != params.length) {
262 continue;
263 }
264
265 Object[] convertedParams = new Object[params.length];
266 for (int i = 0; i < params.length; i++) {
267 if (Iterable.class.isAssignableFrom(methodParamTypes[i])) {
268
269 convertedParams = null;
270 break;
271 }
272 PropertyEditor e = getPropertyEditor(source.getClass(), "p" + i, methodParamTypes[i]);
273 if (e == null) {
274 convertedParams = null;
275 break;
276 }
277
278 e.setAsText((String) params[i]);
279 convertedParams[i] = e.getValue();
280 }
281 if (convertedParams == null) {
282 continue;
283 }
284
285 return convertValue(m.getReturnType(), "returnValue", m.invoke(source, convertedParams), false);
286 }
287
288
289 throw new IllegalArgumentException("Failed to find a matching operation: " + name);
290 } catch (Throwable e) {
291 throwMBeanException(e);
292 }
293
294 throw new IllegalStateException();
295 }
296
297 public final T getSource() {
298 return source;
299 }
300
301 public final MBeanServer getServer() {
302 return server;
303 }
304
305 public final ObjectName getName() {
306 return name;
307 }
308
309 public final MBeanInfo getMBeanInfo() {
310 return info;
311 }
312
313 public final AttributeList getAttributes(String names[]) {
314 AttributeList answer = new AttributeList();
315 for (int i = 0; i < names.length; i++) {
316 try {
317 answer.add(new Attribute(names[i], getAttribute(names[i])));
318 } catch (Exception e) {
319
320 }
321 }
322 return answer;
323 }
324
325 public final AttributeList setAttributes(AttributeList attributes) {
326
327 String names[] = new String[attributes.size()];
328 int n = 0;
329 Iterator<Object> items = attributes.iterator();
330 while (items.hasNext()) {
331 Attribute item = (Attribute) items.next();
332 names[n++] = item.getName();
333 try {
334 setAttribute(item);
335 } catch (Exception e) {
336
337 }
338 }
339
340 return getAttributes(names);
341 }
342
343 public final void setManagedResource(Object resource, String type) throws InstanceNotFoundException,
344 InvalidTargetObjectTypeException, MBeanException {
345 throw new RuntimeOperationsException(new UnsupportedOperationException());
346
347 }
348
349 public final void setModelMBeanInfo(ModelMBeanInfo info) throws MBeanException {
350 throw new RuntimeOperationsException(new UnsupportedOperationException());
351 }
352
353 @Override
354 public final String toString() {
355 return (source == null ? "" : source.toString());
356 }
357
358 public void addAttributeChangeNotificationListener(NotificationListener listener, String name, Object handback) {
359
360 }
361
362 public void removeAttributeChangeNotificationListener(NotificationListener listener, String name)
363 throws ListenerNotFoundException {
364
365 }
366
367 public void sendAttributeChangeNotification(AttributeChangeNotification notification) throws MBeanException {
368 throw new RuntimeOperationsException(new UnsupportedOperationException());
369 }
370
371 public void sendAttributeChangeNotification(Attribute oldValue, Attribute newValue) throws MBeanException {
372 throw new RuntimeOperationsException(new UnsupportedOperationException());
373 }
374
375 public void sendNotification(Notification notification) throws MBeanException {
376 throw new RuntimeOperationsException(new UnsupportedOperationException());
377 }
378
379 public void sendNotification(String message) throws MBeanException {
380 throw new RuntimeOperationsException(new UnsupportedOperationException());
381
382 }
383
384 public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback)
385 throws IllegalArgumentException {
386
387 }
388
389 public MBeanNotificationInfo[] getNotificationInfo() {
390 return new MBeanNotificationInfo[0];
391 }
392
393 public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException {
394
395 }
396
397 public void load() throws InstanceNotFoundException, MBeanException, RuntimeOperationsException {
398 throw new RuntimeOperationsException(new UnsupportedOperationException());
399 }
400
401 public void store() throws InstanceNotFoundException, MBeanException, RuntimeOperationsException {
402 throw new RuntimeOperationsException(new UnsupportedOperationException());
403 }
404
405 public final ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception {
406 this.server = server;
407 this.name = name;
408 return name;
409 }
410
411 public final void postRegister(Boolean registrationDone) {
412 if (registrationDone) {
413 sources.put(name, source);
414 }
415 }
416
417 public final void preDeregister() throws Exception {
418
419 }
420
421 public final void postDeregister() {
422 sources.remove(name);
423 this.server = null;
424 this.name = null;
425 }
426
427 private MBeanInfo createModelMBeanInfo(T source) {
428 String className = source.getClass().getName();
429 String description = "";
430
431 ModelMBeanConstructorInfo[] constructors = new ModelMBeanConstructorInfo[0];
432 ModelMBeanNotificationInfo[] notifications = new ModelMBeanNotificationInfo[0];
433
434 List<ModelMBeanAttributeInfo> attributes = new ArrayList<ModelMBeanAttributeInfo>();
435 List<ModelMBeanOperationInfo> operations = new ArrayList<ModelMBeanOperationInfo>();
436
437 addAttributes(attributes, source);
438 addExtraAttributes(attributes);
439
440 addOperations(operations, source);
441 addExtraOperations(operations);
442 operations.add(new ModelMBeanOperationInfo("unregisterMBean", "unregisterMBean", new MBeanParameterInfo[0],
443 void.class.getName(), ModelMBeanOperationInfo.ACTION));
444
445 return new ModelMBeanInfoSupport(className, description,
446 attributes.toArray(new ModelMBeanAttributeInfo[attributes.size()]), constructors,
447 operations.toArray(new ModelMBeanOperationInfo[operations.size()]), notifications);
448 }
449
450 private void addAttributes(List<ModelMBeanAttributeInfo> attributes, Object object) {
451 addAttributes(attributes, object, object.getClass(), "");
452 }
453
454 private void addAttributes(List<ModelMBeanAttributeInfo> attributes, Object object, Class<?> type, String prefix) {
455
456 PropertyDescriptor[] pdescs;
457 try {
458 pdescs = Introspector.getBeanInfo(type).getPropertyDescriptors();
459 } catch (IntrospectionException e) {
460 return;
461 }
462
463 for (PropertyDescriptor pdesc : pdescs) {
464
465 if (pdesc.getReadMethod() == null) {
466 continue;
467 }
468
469
470 String attrName = pdesc.getName();
471 Class<?> attrType = pdesc.getPropertyType();
472 if (attrName.equals("class")) {
473 continue;
474 }
475 if (!isReadable(type, attrName)) {
476 continue;
477 }
478
479
480 if (isExpandable(type, attrName)) {
481 expandAttribute(attributes, object, prefix, pdesc);
482 continue;
483 }
484
485
486 String fqan = prefix + attrName;
487 boolean writable = isWritable(type, pdesc);
488 attributes.add(new ModelMBeanAttributeInfo(fqan, convertType(object.getClass(), attrName, attrType,
489 writable).getName(), pdesc.getShortDescription(), true, writable, false));
490
491 propertyDescriptors.put(fqan, pdesc);
492 }
493 }
494
495 private boolean isWritable(Class<?> type, PropertyDescriptor pdesc) {
496 if (type == null) {
497 throw new IllegalArgumentException("type");
498 }
499 if (pdesc == null) {
500 return false;
501 }
502 String attrName = pdesc.getName();
503 Class<?> attrType = pdesc.getPropertyType();
504 boolean writable = (pdesc.getWriteMethod() != null) || isWritable(type, attrName);
505 if (getPropertyEditor(type, attrName, attrType) == null) {
506 writable = false;
507 }
508 return writable;
509 }
510
511 private void expandAttribute(List<ModelMBeanAttributeInfo> attributes, Object object, String prefix,
512 PropertyDescriptor pdesc) {
513 Object property;
514 String attrName = pdesc.getName();
515 try {
516 property = getAttribute(object, attrName, pdesc.getPropertyType());
517 } catch (Exception e) {
518 LOGGER.debug("Unexpected exception.", e);
519 return;
520 }
521
522 if (property == null) {
523 return;
524 }
525
526 addAttributes(attributes, property, property.getClass(), prefix + attrName + '.');
527 }
528
529 private void addOperations(List<ModelMBeanOperationInfo> operations, Object object) {
530
531 for (Method m : object.getClass().getMethods()) {
532 String mname = m.getName();
533
534
535 if (mname.startsWith("is") || mname.startsWith("get") || mname.startsWith("set")) {
536 continue;
537 }
538
539
540 if (mname.matches("(wait|notify|notifyAll|toString|equals|compareTo|hashCode|clone)")) {
541 continue;
542 }
543
544
545 if (!isOperation(mname, m.getParameterTypes())) {
546 continue;
547 }
548
549 List<MBeanParameterInfo> signature = new ArrayList<MBeanParameterInfo>();
550 int i = 1;
551 for (Class<?> paramType : m.getParameterTypes()) {
552 String paramName = "p" + (i++);
553 if (getPropertyEditor(source.getClass(), paramName, paramType) == null) {
554 continue;
555 }
556 signature.add(new MBeanParameterInfo(paramName, convertType(null, null, paramType, true).getName(),
557 paramName));
558 }
559
560 Class<?> returnType = convertType(null, null, m.getReturnType(), false);
561 operations.add(new ModelMBeanOperationInfo(m.getName(), m.getName(), signature
562 .toArray(new MBeanParameterInfo[signature.size()]), returnType.getName(),
563 ModelMBeanOperationInfo.ACTION));
564 }
565 }
566
567 private Object getParent(String fqan) throws OgnlException {
568 Object parent;
569 int dotIndex = fqan.lastIndexOf('.');
570 if (dotIndex < 0) {
571 parent = source;
572 } else {
573 parent = getAttribute(source, fqan.substring(0, dotIndex), null);
574 }
575 return parent;
576 }
577
578 private String getLeafAttributeName(String fqan) {
579 int dotIndex = fqan.lastIndexOf('.');
580 if (dotIndex < 0) {
581 return fqan;
582 }
583 return fqan.substring(dotIndex + 1);
584 }
585
586 private Class<?> getAttributeClass(String signature) throws ClassNotFoundException {
587 if (signature.equals(Boolean.TYPE.getName())) {
588 return Boolean.TYPE;
589 }
590 if (signature.equals(Byte.TYPE.getName())) {
591 return Byte.TYPE;
592 }
593 if (signature.equals(Character.TYPE.getName())) {
594 return Character.TYPE;
595 }
596 if (signature.equals(Double.TYPE.getName())) {
597 return Double.TYPE;
598 }
599 if (signature.equals(Float.TYPE.getName())) {
600 return Float.TYPE;
601 }
602 if (signature.equals(Integer.TYPE.getName())) {
603 return Integer.TYPE;
604 }
605 if (signature.equals(Long.TYPE.getName())) {
606 return Long.TYPE;
607 }
608 if (signature.equals(Short.TYPE.getName())) {
609 return Short.TYPE;
610 }
611
612 try {
613 ClassLoader cl = Thread.currentThread().getContextClassLoader();
614 if (cl != null) {
615 return cl.loadClass(signature);
616 }
617 } catch (ClassNotFoundException e) {
618
619 }
620
621 return Class.forName(signature);
622 }
623
624 private Object getAttribute(Object object, String fqan, Class<?> attrType) throws OgnlException {
625 Object property;
626 OgnlContext ctx = (OgnlContext) Ognl.createDefaultContext(object);
627 ctx.setTypeConverter(new OgnlTypeConverter());
628 if (attrType == null) {
629 property = Ognl.getValue(fqan, ctx, object);
630 } else {
631 property = Ognl.getValue(fqan, ctx, object, attrType);
632 }
633 return property;
634 }
635
636 private Class<?> convertType(Class<?> type, String attrName, Class<?> attrType, boolean writable) {
637 if ((attrName != null) && ((attrType == Long.class) || (attrType == long.class))) {
638 if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0)
639 && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0)
640 && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) {
641 return Date.class;
642 }
643 }
644
645 if (IoFilterChain.class.isAssignableFrom(attrType)) {
646 return Map.class;
647 }
648
649 if (IoFilterChainBuilder.class.isAssignableFrom(attrType)) {
650 return Map.class;
651 }
652
653 if (!writable) {
654 if (Collection.class.isAssignableFrom(attrType) || Map.class.isAssignableFrom(attrType)) {
655 if (List.class.isAssignableFrom(attrType)) {
656 return List.class;
657 }
658 if (Set.class.isAssignableFrom(attrType)) {
659 return Set.class;
660 }
661 if (Map.class.isAssignableFrom(attrType)) {
662 return Map.class;
663 }
664 return Collection.class;
665 }
666
667 if (attrType.isPrimitive() || Date.class.isAssignableFrom(attrType)
668 || Boolean.class.isAssignableFrom(attrType) || Character.class.isAssignableFrom(attrType)
669 || Number.class.isAssignableFrom(attrType)) {
670 if ((attrName == null) || !attrName.endsWith("InMillis")
671 || !propertyDescriptors.containsKey(attrName.substring(0, attrName.length() - 8))) {
672 return attrType;
673 }
674 }
675 }
676
677 return String.class;
678 }
679
680 private Object convertValue(Class<?> type, String attrName, Object v, boolean writable) {
681 if (v == null) {
682 return null;
683 }
684
685 if ((attrName != null) && (v instanceof Long)) {
686 if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0)
687 && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0)
688 && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) {
689 long time = (Long) v;
690 if (time <= 0) {
691 return null;
692 }
693
694 return new Date((Long) v);
695 }
696 }
697
698 if ((v instanceof IoSessionDataStructureFactory) || (v instanceof IoHandler)) {
699 return v.getClass().getName();
700 }
701
702 if (v instanceof IoFilterChainBuilder) {
703 Map<String, String> filterMapping = new LinkedHashMap<String, String>();
704 if (v instanceof DefaultIoFilterChainBuilder) {
705 for (IoFilterChain.Entry e : ((DefaultIoFilterChainBuilder) v).getAll()) {
706 filterMapping.put(e.getName(), e.getFilter().getClass().getName());
707 }
708 } else {
709 filterMapping.put("Unknown builder type", v.getClass().getName());
710 }
711 return filterMapping;
712 }
713
714 if (v instanceof IoFilterChain) {
715 Map<String, String> filterMapping = new LinkedHashMap<String, String>();
716 for (IoFilterChain.Entry e : ((IoFilterChain) v).getAll()) {
717 filterMapping.put(e.getName(), e.getFilter().getClass().getName());
718 }
719 return filterMapping;
720 }
721
722 if (!writable) {
723 if ((v instanceof Collection) || (v instanceof Map)) {
724 if (v instanceof List) {
725 return convertCollection(v, new ArrayList<Object>());
726 }
727 if (v instanceof Set) {
728 return convertCollection(v, new LinkedHashSet<Object>());
729 }
730 if (v instanceof Map) {
731 return convertCollection(v, new LinkedHashMap<Object, Object>());
732 }
733 return convertCollection(v, new ArrayList<Object>());
734 }
735
736 if ((v instanceof Date) || (v instanceof Boolean) || (v instanceof Character) || (v instanceof Number)) {
737 if ((attrName == null) || !attrName.endsWith("InMillis")
738 || !propertyDescriptors.containsKey(attrName.substring(0, attrName.length() - 8))) {
739 return v;
740 }
741 }
742 }
743
744 PropertyEditor editor = getPropertyEditor(type, attrName, v.getClass());
745 if (editor != null) {
746 editor.setValue(v);
747 return editor.getAsText();
748 }
749
750 return v.toString();
751 }
752
753 private Object convertCollection(Object src, Collection<Object> dst) {
754 Collection<?> srcCol = (Collection<?>) src;
755 for (Object e : srcCol) {
756 Object convertedValue = convertValue(dst.getClass(), "element", e, false);
757 if ((e != null) && (convertedValue == null)) {
758 convertedValue = (e == null ? "" : e.toString());
759 }
760 dst.add(convertedValue);
761 }
762 return dst;
763 }
764
765 private Object convertCollection(Object src, Map<Object, Object> dst) {
766 Map<?, ?> srcCol = (Map<?, ?>) src;
767 for (Map.Entry<?, ?> e : srcCol.entrySet()) {
768 Object convertedKey = convertValue(dst.getClass(), "key", e.getKey(), false);
769 Object convertedValue = convertValue(dst.getClass(), "value", e.getValue(), false);
770 if ((e.getKey() != null) && (convertedKey == null)) {
771 convertedKey = e.getKey().toString();
772 }
773 if ((e.getValue() != null) && (convertedValue == null)) {
774 convertedKey = e.getValue().toString();
775 }
776 dst.put(convertedKey, convertedValue);
777 }
778 return dst;
779 }
780
781 private void throwMBeanException(Throwable e) throws MBeanException {
782 if (e instanceof OgnlException) {
783 OgnlException ognle = (OgnlException) e;
784 if (ognle.getReason() != null) {
785 throwMBeanException(ognle.getReason());
786 } else {
787 String message = ognle.getMessage();
788 if (e instanceof NoSuchPropertyException) {
789 message = "No such property: " + message;
790 } else if (e instanceof ExpressionSyntaxException) {
791 message = "Illegal expression syntax: " + message;
792 } else if (e instanceof InappropriateExpressionException) {
793 message = "Inappropriate expression: " + message;
794 }
795 e = new IllegalArgumentException(ognle.getMessage());
796 e.setStackTrace(ognle.getStackTrace());
797 }
798 }
799 if (e instanceof InvocationTargetException) {
800 throwMBeanException(e.getCause());
801 }
802
803 LOGGER.warn("Unexpected exception.", e);
804 if (e.getClass().getPackage().getName().matches("javax?\\..+")) {
805 if (e instanceof Exception) {
806 throw new MBeanException((Exception) e, e.getMessage());
807 }
808
809 throw new MBeanException(new RuntimeException(e), e.getMessage());
810 }
811
812 throw new MBeanException(new RuntimeException(e.getClass().getName() + ": " + e.getMessage()), e.getMessage());
813 }
814
815 protected Object getAttribute0(String fqan) throws Exception {
816 throw new AttributeNotFoundException(fqan);
817 }
818
819 protected void setAttribute0(String attrName, Object attrValue) throws Exception {
820 throw new AttributeNotFoundException(attrName);
821 }
822
823 protected Object invoke0(String name, Object params[], String signature[]) throws Exception {
824 throw new NoSuchMethodException();
825 }
826
827 protected boolean isReadable(Class<?> type, String attrName) {
828 if (IoService.class.isAssignableFrom(type) && attrName.equals("filterChain")) {
829 return false;
830 }
831 if (IoService.class.isAssignableFrom(type) && attrName.equals("localAddress")) {
832 return false;
833 }
834 if (IoService.class.isAssignableFrom(type) && attrName.equals("defaultLocalAddress")) {
835 return false;
836 }
837 if (IoSession.class.isAssignableFrom(type) && attrName.equals("attachment")) {
838 return false;
839 }
840 if (IoSession.class.isAssignableFrom(type) && attrName.equals("attributeKeys")) {
841 return false;
842 }
843 if (IoSession.class.isAssignableFrom(type) && attrName.equals("closeFuture")) {
844 return false;
845 }
846
847 if (ThreadPoolExecutor.class.isAssignableFrom(type) && attrName.equals("queue")) {
848 return false;
849 }
850
851 return true;
852 }
853
854 protected boolean isWritable(Class<?> type, String attrName) {
855 if (IoService.class.isAssignableFrom(type) && attrName.startsWith("defaultLocalAddress")) {
856 return true;
857 }
858 return false;
859 }
860
861 protected Class<?> getElementType(Class<?> type, String attrName) {
862 if ((transportMetadata != null) && IoAcceptor.class.isAssignableFrom(type)
863 && "defaultLocalAddresses".equals(attrName)) {
864 return transportMetadata.getAddressType();
865 }
866 return String.class;
867 }
868
869 protected Class<?> getMapKeyType(Class<?> type, String attrName) {
870 return String.class;
871 }
872
873 protected Class<?> getMapValueType(Class<?> type, String attrName) {
874 return String.class;
875 }
876
877 protected boolean isExpandable(Class<?> type, String attrName) {
878
879 if (IoService.class.isAssignableFrom(type)) {
880 if (attrName.equals("statistics") || attrName.equals("sessionConfig")
881 || attrName.equals("transportMetadata") || attrName.equals("config")
882 || attrName.equals("transportMetadata")) {
883 return true;
884 }
885 }
886
887 if (ExecutorFilter.class.isAssignableFrom(type) && attrName.equals("executor")) {
888 return true;
889 }
890
891 if (ThreadPoolExecutor.class.isAssignableFrom(type) && attrName.equals("queueHandler")) {
892 return true;
893 }
894
895 return false;
896 }
897
898 protected boolean isOperation(String methodName, Class<?>[] paramTypes) {
899 return true;
900 }
901
902 protected void addExtraAttributes(List<ModelMBeanAttributeInfo> attributes) {
903
904 }
905
906 protected void addExtraOperations(List<ModelMBeanOperationInfo> operations) {
907
908 }
909
910 protected PropertyEditor getPropertyEditor(Class<?> type, String attrName, Class<?> attrType) {
911 if (type == null) {
912 throw new IllegalArgumentException("type");
913 }
914
915 if (attrName == null) {
916 throw new IllegalArgumentException("attrName");
917 }
918
919 if ((transportMetadata != null) && (attrType == SocketAddress.class)) {
920 attrType = transportMetadata.getAddressType();
921 }
922
923 if (((attrType == Long.class) || (attrType == long.class))) {
924 if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0)
925 && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0)
926 && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) {
927 return PropertyEditorFactory.getInstance(Date.class);
928 }
929
930 if (attrName.equals("id")) {
931 return PropertyEditorFactory.getInstance(String.class);
932 }
933 }
934
935 if (List.class.isAssignableFrom(attrType)) {
936 return new ListEditor(getElementType(type, attrName));
937 }
938
939 if (Set.class.isAssignableFrom(attrType)) {
940 return new SetEditor(getElementType(type, attrName));
941 }
942
943 if (Collection.class.isAssignableFrom(attrType)) {
944 return new CollectionEditor(getElementType(type, attrName));
945 }
946
947 if (Map.class.isAssignableFrom(attrType)) {
948 return new MapEditor(getMapKeyType(type, attrName), getMapValueType(type, attrName));
949 }
950
951 return PropertyEditorFactory.getInstance(attrType);
952 }
953
954 private class OgnlTypeConverter extends PropertyTypeConverter {
955 @Override
956 protected PropertyEditor getPropertyEditor(Class<?> type, String attrName, Class<?> attrType) {
957 return ObjectMBean.this.getPropertyEditor(type, attrName, attrType);
958 }
959 }
960 }