0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017: package org.apache.mina.integration.jmx;
0018:
0019: import java.beans.IntrospectionException;
0020: import java.beans.Introspector;
0021: import java.beans.PropertyDescriptor;
0022: import java.beans.PropertyEditor;
0023: import java.lang.reflect.InvocationTargetException;
0024: import java.lang.reflect.Method;
0025: import java.net.SocketAddress;
0026: import java.util.ArrayList;
0027: import java.util.Collection;
0028: import java.util.Date;
0029: import java.util.HashMap;
0030: import java.util.Iterator;
0031: import java.util.LinkedHashMap;
0032: import java.util.LinkedHashSet;
0033: import java.util.List;
0034: import java.util.Map;
0035: import java.util.Set;
0036: import java.util.concurrent.ConcurrentHashMap;
0037: import java.util.concurrent.ThreadPoolExecutor;
0038:
0039: import javax.management.Attribute;
0040: import javax.management.AttributeChangeNotification;
0041: import javax.management.AttributeList;
0042: import javax.management.AttributeNotFoundException;
0043: import javax.management.InstanceNotFoundException;
0044: import javax.management.ListenerNotFoundException;
0045: import javax.management.MBeanException;
0046: import javax.management.MBeanInfo;
0047: import javax.management.MBeanNotificationInfo;
0048: import javax.management.MBeanParameterInfo;
0049: import javax.management.MBeanRegistration;
0050: import javax.management.MBeanServer;
0051: import javax.management.Notification;
0052: import javax.management.NotificationFilter;
0053: import javax.management.NotificationListener;
0054: import javax.management.ObjectName;
0055: import javax.management.ReflectionException;
0056: import javax.management.RuntimeOperationsException;
0057: import javax.management.modelmbean.InvalidTargetObjectTypeException;
0058: import javax.management.modelmbean.ModelMBean;
0059: import javax.management.modelmbean.ModelMBeanAttributeInfo;
0060: import javax.management.modelmbean.ModelMBeanConstructorInfo;
0061: import javax.management.modelmbean.ModelMBeanInfo;
0062: import javax.management.modelmbean.ModelMBeanInfoSupport;
0063: import javax.management.modelmbean.ModelMBeanNotificationInfo;
0064: import javax.management.modelmbean.ModelMBeanOperationInfo;
0065:
0066: import ognl.ExpressionSyntaxException;
0067: import ognl.InappropriateExpressionException;
0068: import ognl.NoSuchPropertyException;
0069: import ognl.Ognl;
0070: import ognl.OgnlContext;
0071: import ognl.OgnlException;
0072: import ognl.OgnlRuntime;
0073: import ognl.TypeConverter;
0074:
0075: import org.apache.mina.common.DefaultIoFilterChainBuilder;
0076: import org.apache.mina.common.IoAcceptor;
0077: import org.apache.mina.common.IoFilter;
0078: import org.apache.mina.common.IoFilterChain;
0079: import org.apache.mina.common.IoFilterChainBuilder;
0080: import org.apache.mina.common.IoHandler;
0081: import org.apache.mina.common.IoService;
0082: import org.apache.mina.common.IoSession;
0083: import org.apache.mina.common.IoSessionDataStructureFactory;
0084: import org.apache.mina.common.TransportMetadata;
0085: import org.apache.mina.filter.executor.ExecutorFilter;
0086: import org.apache.mina.integration.beans.CollectionEditor;
0087: import org.apache.mina.integration.beans.ListEditor;
0088: import org.apache.mina.integration.beans.MapEditor;
0089: import org.apache.mina.integration.beans.PropertyEditorFactory;
0090: import org.apache.mina.integration.beans.SetEditor;
0091: import org.apache.mina.integration.ognl.IoFilterPropertyAccessor;
0092: import org.apache.mina.integration.ognl.IoServicePropertyAccessor;
0093: import org.apache.mina.integration.ognl.IoSessionPropertyAccessor;
0094: import org.apache.mina.integration.ognl.PropertyTypeConverter;
0095: import org.slf4j.Logger;
0096: import org.slf4j.LoggerFactory;
0097:
0098: /**
0099: * A {@link ModelMBean} wrapper implementation for a POJO.
0100: *
0101: * @author The Apache MINA Project (dev@mina.apache.org)
0102: * @version $Rev: 601236 $, $Date: 2007-12-05 00:53:03 -0700 (Wed, 05 Dec 2007) $
0103: *
0104: * @param <T> the type of the managed object
0105: */
0106: public class ObjectMBean<T> implements ModelMBean, MBeanRegistration {
0107:
0108: private static final Map<ObjectName, Object> sources = new ConcurrentHashMap<ObjectName, Object>();
0109:
0110: public static Object getSource(ObjectName oname) {
0111: return sources.get(oname);
0112: }
0113:
0114: static {
0115: OgnlRuntime.setPropertyAccessor(IoService.class,
0116: new IoServicePropertyAccessor());
0117: OgnlRuntime.setPropertyAccessor(IoSession.class,
0118: new IoSessionPropertyAccessor());
0119: OgnlRuntime.setPropertyAccessor(IoFilter.class,
0120: new IoFilterPropertyAccessor());
0121: }
0122:
0123: protected final Logger logger = LoggerFactory.getLogger(getClass());
0124:
0125: private final T source;
0126: private final TransportMetadata transportMetadata;
0127: private final MBeanInfo info;
0128: private final Map<String, PropertyDescriptor> propertyDescriptors = new HashMap<String, PropertyDescriptor>();
0129: private final TypeConverter typeConverter = new OgnlTypeConverter();
0130:
0131: private volatile MBeanServer server;
0132: private volatile ObjectName name;
0133:
0134: /**
0135: * Creates a new instance with the specified POJO.
0136: */
0137: public ObjectMBean(T source) {
0138: if (source == null) {
0139: throw new NullPointerException("source");
0140: }
0141:
0142: this .source = source;
0143:
0144: if (source instanceof IoService) {
0145: transportMetadata = ((IoService) source)
0146: .getTransportMetadata();
0147: } else if (source instanceof IoSession) {
0148: transportMetadata = ((IoSession) source)
0149: .getTransportMetadata();
0150: } else {
0151: transportMetadata = null;
0152: }
0153:
0154: this .info = createModelMBeanInfo(source);
0155: }
0156:
0157: public final Object getAttribute(String fqan)
0158: throws AttributeNotFoundException, MBeanException,
0159: ReflectionException {
0160: try {
0161: return convertValue(source.getClass(), fqan,
0162: getAttribute0(fqan), false);
0163: } catch (AttributeNotFoundException e) {
0164: } catch (Throwable e) {
0165: throwMBeanException(e);
0166: }
0167:
0168: try {
0169: PropertyDescriptor pdesc = propertyDescriptors.get(fqan);
0170: Object parent = getParent(fqan);
0171: boolean writable = isWritable(source.getClass(), pdesc);
0172:
0173: return convertValue(parent.getClass(),
0174: getLeafAttributeName(fqan), getAttribute(source,
0175: fqan, pdesc.getPropertyType()), writable);
0176: } catch (Throwable e) {
0177: throwMBeanException(e);
0178: }
0179:
0180: throw new IllegalStateException();
0181: }
0182:
0183: public final void setAttribute(Attribute attribute)
0184: throws AttributeNotFoundException, MBeanException,
0185: ReflectionException {
0186: String aname = attribute.getName();
0187: Object avalue = attribute.getValue();
0188:
0189: try {
0190: setAttribute0(aname, avalue);
0191: } catch (AttributeNotFoundException e) {
0192: } catch (Throwable e) {
0193: throwMBeanException(e);
0194: }
0195:
0196: PropertyDescriptor pdesc = propertyDescriptors.get(aname);
0197: if (pdesc == null) {
0198: throwMBeanException(new IllegalArgumentException(
0199: "Unknown attribute: " + aname));
0200: }
0201:
0202: try {
0203: PropertyEditor e = getPropertyEditor(getParent(aname)
0204: .getClass(), pdesc.getName(), pdesc
0205: .getPropertyType());
0206: e.setAsText((String) avalue);
0207: OgnlContext ctx = (OgnlContext) Ognl
0208: .createDefaultContext(source);
0209: ctx.setTypeConverter(typeConverter);
0210: Ognl.setValue(aname, ctx, source, e.getValue());
0211: } catch (Throwable e) {
0212: throwMBeanException(e);
0213: }
0214: }
0215:
0216: public final Object invoke(String name, Object params[],
0217: String signature[]) throws MBeanException,
0218: ReflectionException {
0219:
0220: // Handle synthetic operations first.
0221: if (name.equals("unregisterMBean")) {
0222: try {
0223: server.unregisterMBean(this .name);
0224: return null;
0225: } catch (InstanceNotFoundException e) {
0226: throwMBeanException(e);
0227: }
0228: }
0229:
0230: try {
0231: return convertValue(null, null, invoke0(name, params,
0232: signature), false);
0233: } catch (NoSuchMethodException e) {
0234: } catch (Throwable e) {
0235: throwMBeanException(e);
0236: }
0237:
0238: // And then try reflection.
0239: Class<?>[] paramTypes = new Class[signature.length];
0240: for (int i = 0; i < paramTypes.length; i++) {
0241: try {
0242: paramTypes[i] = getAttributeClass(signature[i]);
0243: } catch (ClassNotFoundException e) {
0244: throwMBeanException(e);
0245: }
0246:
0247: PropertyEditor e = getPropertyEditor(source.getClass(), "p"
0248: + i, paramTypes[i]);
0249: if (e == null) {
0250: throwMBeanException(new RuntimeException(
0251: "Conversion failure: " + params[i]));
0252: }
0253:
0254: e.setValue(params[i]);
0255: params[i] = e.getAsText();
0256: }
0257:
0258: try {
0259: // Find the right method.
0260: for (Method m : source.getClass().getMethods()) {
0261: if (!m.getName().equalsIgnoreCase(name)) {
0262: continue;
0263: }
0264: Class<?>[] methodParamTypes = m.getParameterTypes();
0265: if (methodParamTypes.length != params.length) {
0266: continue;
0267: }
0268:
0269: Object[] convertedParams = new Object[params.length];
0270: for (int i = 0; i < params.length; i++) {
0271: if (Iterable.class
0272: .isAssignableFrom(methodParamTypes[i])) {
0273: // Generics are not supported.
0274: convertedParams = null;
0275: break;
0276: }
0277: PropertyEditor e = getPropertyEditor(source
0278: .getClass(), "p" + i, methodParamTypes[i]);
0279: if (e == null) {
0280: convertedParams = null;
0281: break;
0282: }
0283:
0284: e.setAsText((String) params[i]);
0285: convertedParams[i] = e.getValue();
0286: }
0287: if (convertedParams == null) {
0288: continue;
0289: }
0290:
0291: return convertValue(null, null, m.invoke(source,
0292: convertedParams), false);
0293: }
0294:
0295: // No methods matched.
0296: throw new IllegalArgumentException(
0297: "Failed to find a matching operation: " + name);
0298: } catch (Throwable e) {
0299: throwMBeanException(e);
0300: }
0301:
0302: throw new IllegalStateException();
0303: }
0304:
0305: public final T getSource() {
0306: return source;
0307: }
0308:
0309: public final MBeanServer getServer() {
0310: return server;
0311: }
0312:
0313: public final ObjectName getName() {
0314: return name;
0315: }
0316:
0317: public final MBeanInfo getMBeanInfo() {
0318: return info;
0319: }
0320:
0321: public final AttributeList getAttributes(String names[]) {
0322: AttributeList answer = new AttributeList();
0323: for (int i = 0; i < names.length; i++) {
0324: try {
0325: answer.add(new Attribute(names[i],
0326: getAttribute(names[i])));
0327: } catch (Exception e) {
0328: // Ignore.
0329: }
0330: }
0331: return answer;
0332: }
0333:
0334: public final AttributeList setAttributes(AttributeList attributes) {
0335: // Prepare and return our response, eating all exceptions
0336: String names[] = new String[attributes.size()];
0337: int n = 0;
0338: Iterator<Object> items = attributes.iterator();
0339: while (items.hasNext()) {
0340: Attribute item = (Attribute) items.next();
0341: names[n++] = item.getName();
0342: try {
0343: setAttribute(item);
0344: } catch (Exception e) {
0345: ; // Ignore all exceptions
0346: }
0347: }
0348:
0349: return getAttributes(names);
0350: }
0351:
0352: public final void setManagedResource(Object resource, String type)
0353: throws InstanceNotFoundException,
0354: InvalidTargetObjectTypeException, MBeanException {
0355: throw new RuntimeOperationsException(
0356: new UnsupportedOperationException());
0357:
0358: }
0359:
0360: public final void setModelMBeanInfo(ModelMBeanInfo info)
0361: throws MBeanException {
0362: throw new RuntimeOperationsException(
0363: new UnsupportedOperationException());
0364: }
0365:
0366: @Override
0367: public final String toString() {
0368: return source.toString();
0369: }
0370:
0371: public void addAttributeChangeNotificationListener(
0372: NotificationListener listener, String name, Object handback) {
0373: }
0374:
0375: public void removeAttributeChangeNotificationListener(
0376: NotificationListener listener, String name)
0377: throws ListenerNotFoundException {
0378: }
0379:
0380: public void sendAttributeChangeNotification(
0381: AttributeChangeNotification notification)
0382: throws MBeanException {
0383: throw new RuntimeOperationsException(
0384: new UnsupportedOperationException());
0385: }
0386:
0387: public void sendAttributeChangeNotification(Attribute oldValue,
0388: Attribute newValue) throws MBeanException {
0389: throw new RuntimeOperationsException(
0390: new UnsupportedOperationException());
0391: }
0392:
0393: public void sendNotification(Notification notification)
0394: throws MBeanException {
0395: throw new RuntimeOperationsException(
0396: new UnsupportedOperationException());
0397: }
0398:
0399: public void sendNotification(String message) throws MBeanException {
0400: throw new RuntimeOperationsException(
0401: new UnsupportedOperationException());
0402:
0403: }
0404:
0405: public void addNotificationListener(NotificationListener listener,
0406: NotificationFilter filter, Object handback)
0407: throws IllegalArgumentException {
0408: }
0409:
0410: public MBeanNotificationInfo[] getNotificationInfo() {
0411: return new MBeanNotificationInfo[0];
0412: }
0413:
0414: public void removeNotificationListener(NotificationListener listener)
0415: throws ListenerNotFoundException {
0416: }
0417:
0418: public void load() throws InstanceNotFoundException,
0419: MBeanException, RuntimeOperationsException {
0420: throw new RuntimeOperationsException(
0421: new UnsupportedOperationException());
0422: }
0423:
0424: public void store() throws InstanceNotFoundException,
0425: MBeanException, RuntimeOperationsException {
0426: throw new RuntimeOperationsException(
0427: new UnsupportedOperationException());
0428: }
0429:
0430: public final ObjectName preRegister(MBeanServer server,
0431: ObjectName name) throws Exception {
0432: this .server = server;
0433: this .name = name;
0434: return name;
0435: }
0436:
0437: public final void postRegister(Boolean registrationDone) {
0438: if (registrationDone) {
0439: sources.put(name, source);
0440: }
0441: }
0442:
0443: public final void preDeregister() throws Exception {
0444: }
0445:
0446: public final void postDeregister() {
0447: sources.remove(name);
0448: this .server = null;
0449: this .name = null;
0450: }
0451:
0452: private MBeanInfo createModelMBeanInfo(T source) {
0453: String className = source.getClass().getName();
0454: String description = "";
0455:
0456: ModelMBeanConstructorInfo[] constructors = new ModelMBeanConstructorInfo[0];
0457: ModelMBeanNotificationInfo[] notifications = new ModelMBeanNotificationInfo[0];
0458:
0459: List<ModelMBeanAttributeInfo> attributes = new ArrayList<ModelMBeanAttributeInfo>();
0460: List<ModelMBeanOperationInfo> operations = new ArrayList<ModelMBeanOperationInfo>();
0461:
0462: addAttributes(attributes, source);
0463: addExtraAttributes(attributes);
0464:
0465: addOperations(operations, source);
0466: addExtraOperations(operations);
0467: operations.add(new ModelMBeanOperationInfo("unregisterMBean",
0468: "unregisterMBean", new MBeanParameterInfo[0],
0469: void.class.getName(), ModelMBeanOperationInfo.ACTION));
0470:
0471: return new ModelMBeanInfoSupport(className, description,
0472: attributes
0473: .toArray(new ModelMBeanAttributeInfo[attributes
0474: .size()]), constructors, operations
0475: .toArray(new ModelMBeanOperationInfo[operations
0476: .size()]), notifications);
0477: }
0478:
0479: private void addAttributes(
0480: List<ModelMBeanAttributeInfo> attributes, Object object) {
0481: addAttributes(attributes, object, object.getClass(), "");
0482: }
0483:
0484: private void addAttributes(
0485: List<ModelMBeanAttributeInfo> attributes, Object object,
0486: Class<?> type, String prefix) {
0487:
0488: PropertyDescriptor[] pdescs;
0489: try {
0490: pdescs = Introspector.getBeanInfo(type)
0491: .getPropertyDescriptors();
0492: } catch (IntrospectionException e) {
0493: return;
0494: }
0495:
0496: for (PropertyDescriptor pdesc : pdescs) {
0497: // Ignore a write-only property.
0498: if (pdesc.getReadMethod() == null) {
0499: continue;
0500: }
0501:
0502: // Ignore unmanageable property.
0503: String attrName = pdesc.getName();
0504: Class<?> attrType = pdesc.getPropertyType();
0505: if (attrName.equals("class")) {
0506: continue;
0507: }
0508: if (!isReadable(type, attrName)) {
0509: continue;
0510: }
0511:
0512: // Expand if possible.
0513: if (isExpandable(type, attrName)) {
0514: expandAttribute(attributes, object, prefix, pdesc);
0515: continue;
0516: }
0517:
0518: // Ordinary property.
0519: String fqan = prefix + attrName;
0520: boolean writable = isWritable(type, pdesc);
0521: attributes.add(new ModelMBeanAttributeInfo(fqan,
0522: convertType(object.getClass(), attrName, attrType,
0523: writable).getName(), pdesc
0524: .getShortDescription(), true, writable,
0525: false));
0526:
0527: propertyDescriptors.put(fqan, pdesc);
0528: }
0529: }
0530:
0531: private boolean isWritable(Class<?> type, PropertyDescriptor pdesc) {
0532: if (type == null) {
0533: throw new NullPointerException("type");
0534: }
0535: if (pdesc == null) {
0536: return false;
0537: }
0538: String attrName = pdesc.getName();
0539: Class<?> attrType = pdesc.getPropertyType();
0540: boolean writable = pdesc.getWriteMethod() != null
0541: || isWritable(type, attrName);
0542: if (getPropertyEditor(type, attrName, attrType) == null) {
0543: writable = false;
0544: }
0545: return writable;
0546: }
0547:
0548: private void expandAttribute(
0549: List<ModelMBeanAttributeInfo> attributes, Object object,
0550: String prefix, PropertyDescriptor pdesc) {
0551: Object property;
0552: String attrName = pdesc.getName();
0553: try {
0554: property = getAttribute(object, attrName, pdesc
0555: .getPropertyType());
0556: } catch (Exception e) {
0557: logger.debug("Unexpected exception.", e);
0558: return;
0559: }
0560:
0561: if (property == null) {
0562: return;
0563: }
0564:
0565: addAttributes(attributes, property, property.getClass(), prefix
0566: + attrName + '.');
0567: }
0568:
0569: private void addOperations(
0570: List<ModelMBeanOperationInfo> operations, Object object) {
0571:
0572: for (Method m : object.getClass().getMethods()) {
0573: String mname = m.getName();
0574:
0575: // Ignore getters and setters.
0576: if (mname.startsWith("is") || mname.startsWith("get")
0577: || mname.startsWith("set")) {
0578: continue;
0579: }
0580:
0581: // Ignore Object methods.
0582: if (mname
0583: .matches("(wait|notify|notifyAll|toString|equals|compareTo|hashCode|clone)")) {
0584: continue;
0585: }
0586:
0587: // Ignore other user-defined non-operations.
0588: if (!isOperation(mname, m.getParameterTypes())) {
0589: continue;
0590: }
0591:
0592: List<MBeanParameterInfo> signature = new ArrayList<MBeanParameterInfo>();
0593: int i = 1;
0594: for (Class<?> paramType : m.getParameterTypes()) {
0595: String paramName = "p" + (i++);
0596: if (getPropertyEditor(source.getClass(), paramName,
0597: paramType) == null) {
0598: continue;
0599: }
0600: signature.add(new MBeanParameterInfo(paramName,
0601: convertType(null, null, paramType, true)
0602: .getName(), paramName));
0603: }
0604:
0605: Class<?> returnType = convertType(null, null, m
0606: .getReturnType(), false);
0607: operations.add(new ModelMBeanOperationInfo(m.getName(), m
0608: .getName(), signature
0609: .toArray(new MBeanParameterInfo[signature.size()]),
0610: returnType.getName(),
0611: ModelMBeanOperationInfo.ACTION));
0612: }
0613: }
0614:
0615: private Object getParent(String fqan) throws OgnlException {
0616: Object parent;
0617: int dotIndex = fqan.lastIndexOf('.');
0618: if (dotIndex < 0) {
0619: parent = source;
0620: } else {
0621: parent = getAttribute(source, fqan.substring(0, dotIndex),
0622: null);
0623: }
0624: return parent;
0625: }
0626:
0627: private String getLeafAttributeName(String fqan) {
0628: int dotIndex = fqan.lastIndexOf('.');
0629: if (dotIndex < 0) {
0630: return fqan;
0631: }
0632: return fqan.substring(dotIndex + 1);
0633: }
0634:
0635: private Class<?> getAttributeClass(String signature)
0636: throws ClassNotFoundException {
0637: if (signature.equals(Boolean.TYPE.getName())) {
0638: return Boolean.TYPE;
0639: }
0640: if (signature.equals(Byte.TYPE.getName())) {
0641: return Byte.TYPE;
0642: }
0643: if (signature.equals(Character.TYPE.getName())) {
0644: return Character.TYPE;
0645: }
0646: if (signature.equals(Double.TYPE.getName())) {
0647: return Double.TYPE;
0648: }
0649: if (signature.equals(Float.TYPE.getName())) {
0650: return Float.TYPE;
0651: }
0652: if (signature.equals(Integer.TYPE.getName())) {
0653: return Integer.TYPE;
0654: }
0655: if (signature.equals(Long.TYPE.getName())) {
0656: return Long.TYPE;
0657: }
0658: if (signature.equals(Short.TYPE.getName())) {
0659: return Short.TYPE;
0660: }
0661:
0662: try {
0663: ClassLoader cl = Thread.currentThread()
0664: .getContextClassLoader();
0665: if (cl != null) {
0666: return cl.loadClass(signature);
0667: }
0668: } catch (ClassNotFoundException e) {
0669: }
0670:
0671: return Class.forName(signature);
0672: }
0673:
0674: private Object getAttribute(Object object, String fqan,
0675: Class<?> attrType) throws OgnlException {
0676: Object property;
0677: OgnlContext ctx = (OgnlContext) Ognl
0678: .createDefaultContext(object);
0679: ctx.setTypeConverter(new OgnlTypeConverter());
0680: if (attrType == null) {
0681: property = Ognl.getValue(fqan, ctx, object);
0682: } else {
0683: property = Ognl.getValue(fqan, ctx, object, attrType);
0684: }
0685: return property;
0686: }
0687:
0688: @SuppressWarnings("unused")
0689: private Class<?> convertType(Class<?> type, String attrName,
0690: Class<?> attrType, boolean writable) {
0691: if (attrName != null
0692: && (attrType == Long.class || attrType == long.class)) {
0693: if (attrName.endsWith("Time")
0694: && attrName.indexOf("Total") < 0
0695: && attrName.indexOf("Min") < 0
0696: && attrName.indexOf("Max") < 0
0697: && attrName.indexOf("Avg") < 0
0698: && attrName.indexOf("Average") < 0
0699: && !propertyDescriptors.containsKey(attrName
0700: + "InMillis")) {
0701: return Date.class;
0702: }
0703: }
0704:
0705: if (IoFilterChain.class.isAssignableFrom(attrType)) {
0706: return Map.class;
0707: }
0708:
0709: if (IoFilterChainBuilder.class.isAssignableFrom(attrType)) {
0710: return Map.class;
0711: }
0712:
0713: if (!writable) {
0714: if (Collection.class.isAssignableFrom(attrType)
0715: || Map.class.isAssignableFrom(attrType)) {
0716: if (List.class.isAssignableFrom(attrType)) {
0717: return List.class;
0718: }
0719: if (Set.class.isAssignableFrom(attrType)) {
0720: return Set.class;
0721: }
0722: if (Map.class.isAssignableFrom(attrType)) {
0723: return Map.class;
0724: }
0725: return Collection.class;
0726: }
0727:
0728: if (attrType.isPrimitive()
0729: || Date.class.isAssignableFrom(attrType)
0730: || Boolean.class.isAssignableFrom(attrType)
0731: || Character.class.isAssignableFrom(attrType)
0732: || Number.class.isAssignableFrom(attrType)) {
0733: if (attrName == null
0734: || !attrName.endsWith("InMillis")
0735: || !propertyDescriptors.containsKey(attrName
0736: .substring(0, attrName.length() - 8))) {
0737: return attrType;
0738: }
0739: }
0740: }
0741:
0742: return String.class;
0743: }
0744:
0745: private Object convertValue(Class<?> type, String attrName,
0746: Object v, boolean writable) {
0747: if (v == null) {
0748: return null;
0749: }
0750:
0751: if (attrName != null && v instanceof Long) {
0752: if (attrName.endsWith("Time")
0753: && attrName.indexOf("Total") < 0
0754: && attrName.indexOf("Min") < 0
0755: && attrName.indexOf("Max") < 0
0756: && attrName.indexOf("Avg") < 0
0757: && attrName.indexOf("Average") < 0
0758: && !propertyDescriptors.containsKey(attrName
0759: + "InMillis")) {
0760: long time = (Long) v;
0761: if (time <= 0) {
0762: return null;
0763: }
0764: System.out.println("Converted to date");
0765: return new Date((Long) v);
0766: }
0767: }
0768:
0769: if (v instanceof IoSessionDataStructureFactory
0770: || v instanceof IoHandler) {
0771: return v.getClass().getName();
0772: }
0773:
0774: if (v instanceof IoFilterChainBuilder) {
0775: Map<String, String> filterMapping = new LinkedHashMap<String, String>();
0776: if (v instanceof DefaultIoFilterChainBuilder) {
0777: for (IoFilterChain.Entry e : ((DefaultIoFilterChainBuilder) v)
0778: .getAll()) {
0779: filterMapping.put(e.getName(), e.getFilter()
0780: .getClass().getName());
0781: }
0782: } else {
0783: filterMapping.put("Unknown builder type", v.getClass()
0784: .getName());
0785: }
0786: return filterMapping;
0787: }
0788:
0789: if (v instanceof IoFilterChain) {
0790: Map<String, String> filterMapping = new LinkedHashMap<String, String>();
0791: for (IoFilterChain.Entry e : ((IoFilterChain) v).getAll()) {
0792: filterMapping.put(e.getName(), e.getFilter().getClass()
0793: .getName());
0794: }
0795: return filterMapping;
0796: }
0797:
0798: if (!writable) {
0799: if (v instanceof Collection || v instanceof Map) {
0800: if (v instanceof List) {
0801: return convertCollection(v, new ArrayList<Object>());
0802: }
0803: if (v instanceof Set) {
0804: return convertCollection(v,
0805: new LinkedHashSet<Object>());
0806: }
0807: if (v instanceof Map) {
0808: return convertCollection(v,
0809: new LinkedHashMap<Object, Object>());
0810: }
0811: return convertCollection(v, new ArrayList<Object>());
0812: }
0813:
0814: if (v instanceof Date || v instanceof Boolean
0815: || v instanceof Character || v instanceof Number) {
0816: if (attrName == null
0817: || !attrName.endsWith("InMillis")
0818: || !propertyDescriptors.containsKey(attrName
0819: .substring(0, attrName.length() - 8))) {
0820: return v;
0821: }
0822: }
0823: }
0824:
0825: PropertyEditor editor = getPropertyEditor(type, attrName, v
0826: .getClass());
0827: if (editor != null) {
0828: editor.setValue(v);
0829: return editor.getAsText();
0830: }
0831:
0832: return v.toString();
0833: }
0834:
0835: private Object convertCollection(Object src, Collection<Object> dst) {
0836: Collection<?> srcCol = (Collection<?>) src;
0837: for (Object e : srcCol) {
0838: Object convertedValue = convertValue(dst.getClass(),
0839: "element", e, false);
0840: if (e != null && convertedValue == null) {
0841: convertedValue = e.toString();
0842: }
0843: dst.add(convertedValue);
0844: }
0845: return dst;
0846: }
0847:
0848: private Object convertCollection(Object src, Map<Object, Object> dst) {
0849: Map<?, ?> srcCol = (Map<?, ?>) src;
0850: for (Map.Entry<?, ?> e : srcCol.entrySet()) {
0851: Object convertedKey = convertValue(dst.getClass(), "key", e
0852: .getKey(), false);
0853: Object convertedValue = convertValue(dst.getClass(),
0854: "value", e.getValue(), false);
0855: if (e.getKey() != null && convertedKey == null) {
0856: convertedKey = e.getKey().toString();
0857: }
0858: if (e.getValue() != null && convertedValue == null) {
0859: convertedKey = e.getValue().toString();
0860: }
0861: dst.put(convertedKey, convertedValue);
0862: }
0863: return dst;
0864: }
0865:
0866: private void throwMBeanException(Throwable e) throws MBeanException {
0867: if (e instanceof OgnlException) {
0868: OgnlException ognle = (OgnlException) e;
0869: if (ognle.getReason() != null) {
0870: throwMBeanException(ognle.getReason());
0871: } else {
0872: String message = ognle.getMessage();
0873: if (e instanceof NoSuchPropertyException) {
0874: message = "No such property: " + message;
0875: } else if (e instanceof ExpressionSyntaxException) {
0876: message = "Illegal expression syntax: " + message;
0877: } else if (e instanceof InappropriateExpressionException) {
0878: message = "Inappropriate expression: " + message;
0879: }
0880: e = new IllegalArgumentException(ognle.getMessage());
0881: e.setStackTrace(ognle.getStackTrace());
0882: }
0883: }
0884: if (e instanceof InvocationTargetException) {
0885: throwMBeanException(e.getCause());
0886: }
0887:
0888: logger.warn("Unexpected exception.", e);
0889: if (e.getClass().getPackage().getName().matches("javax?\\..+")) {
0890: if (e instanceof Exception) {
0891: throw new MBeanException((Exception) e, e.getMessage());
0892: } else {
0893: throw new MBeanException(new RuntimeException(e), e
0894: .getMessage());
0895: }
0896: }
0897:
0898: throw new MBeanException(new RuntimeException(e.getClass()
0899: .getName()
0900: + ": " + e.getMessage()), e.getMessage());
0901: }
0902:
0903: protected Object getAttribute0(String fqan) throws Exception {
0904: throw new AttributeNotFoundException(fqan);
0905: }
0906:
0907: @SuppressWarnings("unused")
0908: protected void setAttribute0(String attrName, Object attrValue)
0909: throws Exception {
0910: throw new AttributeNotFoundException(attrName);
0911: }
0912:
0913: @SuppressWarnings("unused")
0914: protected Object invoke0(String name, Object params[],
0915: String signature[]) throws Exception {
0916: throw new NoSuchMethodException();
0917: }
0918:
0919: protected boolean isReadable(Class<?> type, String attrName) {
0920: if (IoService.class.isAssignableFrom(type)
0921: && attrName.equals("filterChain")) {
0922: return false;
0923: }
0924: if (IoService.class.isAssignableFrom(type)
0925: && attrName.equals("localAddress")) {
0926: return false;
0927: }
0928: if (IoService.class.isAssignableFrom(type)
0929: && attrName.equals("defaultLocalAddress")) {
0930: return false;
0931: }
0932: if (IoSession.class.isAssignableFrom(type)
0933: && attrName.equals("attachment")) {
0934: return false;
0935: }
0936: if (IoSession.class.isAssignableFrom(type)
0937: && attrName.equals("attributeKeys")) {
0938: return false;
0939: }
0940: if (IoSession.class.isAssignableFrom(type)
0941: && attrName.equals("closeFuture")) {
0942: return false;
0943: }
0944:
0945: if (ThreadPoolExecutor.class.isAssignableFrom(type)
0946: && attrName.equals("queue")) {
0947: return false;
0948: }
0949:
0950: return true;
0951: }
0952:
0953: protected boolean isWritable(Class<?> type, String attrName) {
0954: if (IoService.class.isAssignableFrom(type)
0955: && attrName.startsWith("defaultLocalAddress")) {
0956: return true;
0957: }
0958: return false;
0959: }
0960:
0961: @SuppressWarnings("unused")
0962: protected Class<?> getElementType(Class<?> type, String attrName) {
0963: if (transportMetadata != null
0964: && IoAcceptor.class.isAssignableFrom(type)
0965: && "defaultLocalAddresses".equals(attrName)) {
0966: return transportMetadata.getAddressType();
0967: }
0968: return String.class;
0969: }
0970:
0971: @SuppressWarnings("unused")
0972: protected Class<?> getMapKeyType(Class<?> type, String attrName) {
0973: return String.class;
0974: }
0975:
0976: @SuppressWarnings("unused")
0977: protected Class<?> getMapValueType(Class<?> type, String attrName) {
0978: return String.class;
0979: }
0980:
0981: protected boolean isExpandable(Class<?> type, String attrName) {
0982: if (IoService.class.isAssignableFrom(type)
0983: && attrName.equals("sessionConfig")) {
0984: return true;
0985: }
0986: if (IoService.class.isAssignableFrom(type)
0987: && attrName.equals("transportMetadata")) {
0988: return true;
0989: }
0990: if (IoSession.class.isAssignableFrom(type)
0991: && attrName.equals("config")) {
0992: return true;
0993: }
0994: if (IoSession.class.isAssignableFrom(type)
0995: && attrName.equals("transportMetadata")) {
0996: return true;
0997: }
0998:
0999: if (ExecutorFilter.class.isAssignableFrom(type)) {
1000: if (attrName.equals("executor")) {
1001: return true;
1002: }
1003: }
1004: if (ThreadPoolExecutor.class.isAssignableFrom(type)) {
1005: if (attrName.equals("queueHandler")) {
1006: return true;
1007: }
1008: }
1009: return false;
1010: }
1011:
1012: @SuppressWarnings("unused")
1013: protected boolean isOperation(String methodName,
1014: Class<?>[] paramTypes) {
1015: return true;
1016: }
1017:
1018: @SuppressWarnings("unused")
1019: protected void addExtraAttributes(
1020: List<ModelMBeanAttributeInfo> attributes) {
1021: }
1022:
1023: @SuppressWarnings("unused")
1024: protected void addExtraOperations(
1025: List<ModelMBeanOperationInfo> operations) {
1026: }
1027:
1028: protected PropertyEditor getPropertyEditor(Class<?> type,
1029: String attrName, Class<?> attrType) {
1030: if (type == null) {
1031: throw new NullPointerException("type");
1032: }
1033: if (attrName == null) {
1034: throw new NullPointerException("attrName");
1035: }
1036:
1037: if (transportMetadata != null
1038: && attrType == SocketAddress.class) {
1039: attrType = transportMetadata.getAddressType();
1040: }
1041:
1042: if (attrName != null
1043: && (attrType == Long.class || attrType == long.class)) {
1044: if (attrName.endsWith("Time")
1045: && attrName.indexOf("Total") < 0
1046: && attrName.indexOf("Min") < 0
1047: && attrName.indexOf("Max") < 0
1048: && attrName.indexOf("Avg") < 0
1049: && attrName.indexOf("Average") < 0
1050: && !propertyDescriptors.containsKey(attrName
1051: + "InMillis")) {
1052: return PropertyEditorFactory.getInstance(Date.class);
1053: }
1054:
1055: if (attrName.equals("id")) {
1056: return PropertyEditorFactory.getInstance(String.class);
1057: }
1058: }
1059:
1060: if (type != null) {
1061: if (List.class.isAssignableFrom(attrType)) {
1062: return new ListEditor(getElementType(type, attrName));
1063: }
1064: if (Set.class.isAssignableFrom(attrType)) {
1065: return new SetEditor(getElementType(type, attrName));
1066: }
1067: if (Collection.class.isAssignableFrom(attrType)) {
1068: return new CollectionEditor(getElementType(type,
1069: attrName));
1070: }
1071: if (Map.class.isAssignableFrom(attrType)) {
1072: return new MapEditor(getMapKeyType(type, attrName),
1073: getMapValueType(type, attrName));
1074: }
1075: }
1076:
1077: return PropertyEditorFactory.getInstance(attrType);
1078: }
1079:
1080: private class OgnlTypeConverter extends PropertyTypeConverter {
1081: @Override
1082: protected PropertyEditor getPropertyEditor(Class<?> type,
1083: String attrName, Class<?> attrType) {
1084: return ObjectMBean.this.getPropertyEditor(type, attrName,
1085: attrType);
1086: }
1087: }
1088: }
|