| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.mina.integration.jmx; |
| |
| import java.beans.IntrospectionException; |
| import java.beans.Introspector; |
| import java.beans.PropertyDescriptor; |
| import java.beans.PropertyEditor; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.net.SocketAddress; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.concurrent.ThreadPoolExecutor; |
| |
| import javax.management.Attribute; |
| import javax.management.AttributeChangeNotification; |
| import javax.management.AttributeList; |
| import javax.management.AttributeNotFoundException; |
| import javax.management.InstanceNotFoundException; |
| import javax.management.ListenerNotFoundException; |
| import javax.management.MBeanException; |
| import javax.management.MBeanInfo; |
| import javax.management.MBeanNotificationInfo; |
| import javax.management.MBeanParameterInfo; |
| import javax.management.MBeanRegistration; |
| import javax.management.MBeanServer; |
| import javax.management.Notification; |
| import javax.management.NotificationFilter; |
| import javax.management.NotificationListener; |
| import javax.management.ObjectName; |
| import javax.management.ReflectionException; |
| import javax.management.RuntimeOperationsException; |
| import javax.management.modelmbean.InvalidTargetObjectTypeException; |
| import javax.management.modelmbean.ModelMBean; |
| import javax.management.modelmbean.ModelMBeanAttributeInfo; |
| import javax.management.modelmbean.ModelMBeanConstructorInfo; |
| import javax.management.modelmbean.ModelMBeanInfo; |
| import javax.management.modelmbean.ModelMBeanInfoSupport; |
| import javax.management.modelmbean.ModelMBeanNotificationInfo; |
| import javax.management.modelmbean.ModelMBeanOperationInfo; |
| |
| import ognl.ExpressionSyntaxException; |
| import ognl.InappropriateExpressionException; |
| import ognl.NoSuchPropertyException; |
| import ognl.Ognl; |
| import ognl.OgnlContext; |
| import ognl.OgnlException; |
| import ognl.OgnlRuntime; |
| import ognl.TypeConverter; |
| |
| import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder; |
| import org.apache.mina.core.filterchain.IoFilter; |
| import org.apache.mina.core.filterchain.IoFilterChain; |
| import org.apache.mina.core.filterchain.IoFilterChainBuilder; |
| import org.apache.mina.core.service.IoAcceptor; |
| import org.apache.mina.core.service.IoHandler; |
| import org.apache.mina.core.service.IoService; |
| import org.apache.mina.core.service.TransportMetadata; |
| import org.apache.mina.core.session.IoSession; |
| import org.apache.mina.core.session.IoSessionDataStructureFactory; |
| import org.apache.mina.filter.executor.ExecutorFilter; |
| import org.apache.mina.integration.beans.CollectionEditor; |
| import org.apache.mina.integration.beans.ListEditor; |
| import org.apache.mina.integration.beans.MapEditor; |
| import org.apache.mina.integration.beans.PropertyEditorFactory; |
| import org.apache.mina.integration.beans.SetEditor; |
| import org.apache.mina.integration.ognl.IoFilterPropertyAccessor; |
| import org.apache.mina.integration.ognl.IoServicePropertyAccessor; |
| import org.apache.mina.integration.ognl.IoSessionPropertyAccessor; |
| import org.apache.mina.integration.ognl.PropertyTypeConverter; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| /** |
| * A {@link ModelMBean} wrapper implementation for a POJO. |
| * |
| * @author <a href="http://mina.apache.org">Apache MINA Project</a> |
| * |
| * @param <T> the type of the managed object |
| */ |
| public class ObjectMBean<T> implements ModelMBean, MBeanRegistration { |
| |
| private static final Map<ObjectName, Object> sources = new ConcurrentHashMap<ObjectName, Object>(); |
| |
| /** |
| * Get the monitored object |
| * |
| * @param oname The object name |
| * @return The monitored object |
| */ |
| public static Object getSource(ObjectName oname) { |
| return sources.get(oname); |
| } |
| |
| static { |
| OgnlRuntime.setPropertyAccessor(IoService.class, new IoServicePropertyAccessor()); |
| OgnlRuntime.setPropertyAccessor(IoSession.class, new IoSessionPropertyAccessor()); |
| OgnlRuntime.setPropertyAccessor(IoFilter.class, new IoFilterPropertyAccessor()); |
| } |
| |
| protected final static Logger LOGGER = LoggerFactory.getLogger(ObjectMBean.class); |
| |
| private final T source; |
| |
| private final TransportMetadata transportMetadata; |
| |
| private final MBeanInfo info; |
| |
| private final Map<String, PropertyDescriptor> propertyDescriptors = new HashMap<String, PropertyDescriptor>(); |
| |
| private final TypeConverter typeConverter = new OgnlTypeConverter(); |
| |
| private volatile MBeanServer server; |
| |
| private volatile ObjectName name; |
| |
| /** |
| * Creates a new instance with the specified POJO. |
| * |
| * @param source The original POJO |
| */ |
| public ObjectMBean(T source) { |
| if (source == null) { |
| throw new IllegalArgumentException("source"); |
| } |
| |
| this.source = source; |
| |
| if (source instanceof IoService) { |
| transportMetadata = ((IoService) source).getTransportMetadata(); |
| } else if (source instanceof IoSession) { |
| transportMetadata = ((IoSession) source).getTransportMetadata(); |
| } else { |
| transportMetadata = null; |
| } |
| |
| this.info = createModelMBeanInfo(source); |
| } |
| |
| public final Object getAttribute(String fqan) throws AttributeNotFoundException, MBeanException, |
| ReflectionException { |
| try { |
| return convertValue(source.getClass(), fqan, getAttribute0(fqan), false); |
| } catch (AttributeNotFoundException e) { |
| // Do nothing |
| } catch (Exception e) { |
| throwMBeanException(e); |
| } |
| |
| // Check if the attribute exist, if not throw an exception |
| PropertyDescriptor pdesc = propertyDescriptors.get(fqan); |
| if (pdesc == null) { |
| throwMBeanException(new IllegalArgumentException("Unknown attribute: " + fqan)); |
| } |
| |
| try { |
| |
| Object parent = getParent(fqan); |
| boolean writable = isWritable(source.getClass(), pdesc); |
| |
| return convertValue(parent.getClass(), getLeafAttributeName(fqan), |
| getAttribute(source, fqan, pdesc.getPropertyType()), writable); |
| } catch (Exception e) { |
| throwMBeanException(e); |
| } |
| |
| throw new IllegalStateException(); |
| } |
| |
| public final void setAttribute(Attribute attribute) throws AttributeNotFoundException, MBeanException, |
| ReflectionException { |
| String aname = attribute.getName(); |
| Object avalue = attribute.getValue(); |
| |
| try { |
| setAttribute0(aname, avalue); |
| } catch (AttributeNotFoundException e) { |
| // Do nothing |
| } catch (Exception e) { |
| throwMBeanException(e); |
| } |
| |
| PropertyDescriptor pdesc = propertyDescriptors.get(aname); |
| if (pdesc == null) { |
| throwMBeanException(new IllegalArgumentException("Unknown attribute: " + aname)); |
| } |
| |
| try { |
| PropertyEditor e = getPropertyEditor(getParent(aname).getClass(), pdesc.getName(), pdesc.getPropertyType()); |
| e.setAsText((String) avalue); |
| OgnlContext ctx = (OgnlContext) Ognl.createDefaultContext(source); |
| ctx.setTypeConverter(typeConverter); |
| Ognl.setValue(aname, ctx, source, e.getValue()); |
| } catch (Exception e) { |
| throwMBeanException(e); |
| } |
| } |
| |
| public final Object invoke(String name, Object params[], String signature[]) throws MBeanException, |
| ReflectionException { |
| |
| // Handle synthetic operations first. |
| if (name.equals("unregisterMBean")) { |
| try { |
| server.unregisterMBean(this.name); |
| return null; |
| } catch (InstanceNotFoundException e) { |
| throwMBeanException(e); |
| } |
| } |
| |
| try { |
| return convertValue(null, null, invoke0(name, params, signature), false); |
| } catch (NoSuchMethodException e) { |
| // Do nothing |
| } catch (Exception e) { |
| throwMBeanException(e); |
| } |
| |
| // And then try reflection. |
| Class<?>[] paramTypes = new Class[signature.length]; |
| for (int i = 0; i < paramTypes.length; i++) { |
| try { |
| paramTypes[i] = getAttributeClass(signature[i]); |
| } catch (ClassNotFoundException e) { |
| throwMBeanException(e); |
| } |
| |
| PropertyEditor e = getPropertyEditor(source.getClass(), "p" + i, paramTypes[i]); |
| if (e == null) { |
| throwMBeanException(new RuntimeException("Conversion failure: " + params[i])); |
| } |
| |
| e.setValue(params[i]); |
| params[i] = e.getAsText(); |
| } |
| |
| try { |
| // Find the right method. |
| for (Method m : source.getClass().getMethods()) { |
| if (!m.getName().equalsIgnoreCase(name)) { |
| continue; |
| } |
| Class<?>[] methodParamTypes = m.getParameterTypes(); |
| if (methodParamTypes.length != params.length) { |
| continue; |
| } |
| |
| Object[] convertedParams = new Object[params.length]; |
| for (int i = 0; i < params.length; i++) { |
| if (Iterable.class.isAssignableFrom(methodParamTypes[i])) { |
| // Generics are not supported. |
| convertedParams = null; |
| break; |
| } |
| PropertyEditor e = getPropertyEditor(source.getClass(), "p" + i, methodParamTypes[i]); |
| if (e == null) { |
| convertedParams = null; |
| break; |
| } |
| |
| e.setAsText((String) params[i]); |
| convertedParams[i] = e.getValue(); |
| } |
| if (convertedParams == null) { |
| continue; |
| } |
| |
| return convertValue(m.getReturnType(), "returnValue", m.invoke(source, convertedParams), false); |
| } |
| |
| // No methods matched. |
| throw new IllegalArgumentException("Failed to find a matching operation: " + name); |
| } catch (Exception e) { |
| throwMBeanException(e); |
| } |
| |
| throw new IllegalStateException(); |
| } |
| |
| /** |
| * @return The monitored object |
| */ |
| public final T getSource() { |
| return source; |
| } |
| |
| /** |
| * @return The MBrean server |
| */ |
| public final MBeanServer getServer() { |
| return server; |
| } |
| |
| /** |
| * @return The monitored object name |
| */ |
| public final ObjectName getName() { |
| return name; |
| } |
| |
| public final MBeanInfo getMBeanInfo() { |
| return info; |
| } |
| |
| public final AttributeList getAttributes(String names[]) { |
| AttributeList answer = new AttributeList(); |
| for (int i = 0; i < names.length; i++) { |
| try { |
| answer.add(new Attribute(names[i], getAttribute(names[i]))); |
| } catch (Exception e) { |
| // Ignore. |
| } |
| } |
| return answer; |
| } |
| |
| public final AttributeList setAttributes(AttributeList attributes) { |
| // Prepare and return our response, eating all exceptions |
| String names[] = new String[attributes.size()]; |
| int n = 0; |
| Iterator<Object> items = attributes.iterator(); |
| while (items.hasNext()) { |
| Attribute item = (Attribute) items.next(); |
| names[n++] = item.getName(); |
| try { |
| setAttribute(item); |
| } catch (Exception e) { |
| // Ignore all exceptions |
| } |
| } |
| |
| return getAttributes(names); |
| } |
| |
| public final void setManagedResource(Object resource, String type) throws InstanceNotFoundException, |
| InvalidTargetObjectTypeException, MBeanException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| |
| } |
| |
| public final void setModelMBeanInfo(ModelMBeanInfo info) throws MBeanException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| } |
| |
| @Override |
| public final String toString() { |
| return (source == null ? "" : source.toString()); |
| } |
| |
| public void addAttributeChangeNotificationListener(NotificationListener listener, String name, Object handback) { |
| // Do nothing |
| } |
| |
| public void removeAttributeChangeNotificationListener(NotificationListener listener, String name) |
| throws ListenerNotFoundException { |
| // Do nothing |
| } |
| |
| public void sendAttributeChangeNotification(AttributeChangeNotification notification) throws MBeanException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| } |
| |
| public void sendAttributeChangeNotification(Attribute oldValue, Attribute newValue) throws MBeanException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| } |
| |
| public void sendNotification(Notification notification) throws MBeanException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| } |
| |
| public void sendNotification(String message) throws MBeanException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| |
| } |
| |
| public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) |
| throws IllegalArgumentException { |
| // Do nothing |
| } |
| |
| public MBeanNotificationInfo[] getNotificationInfo() { |
| return new MBeanNotificationInfo[0]; |
| } |
| |
| public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { |
| // Do nothing |
| } |
| |
| public void load() throws InstanceNotFoundException, MBeanException, RuntimeOperationsException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| } |
| |
| public void store() throws InstanceNotFoundException, MBeanException, RuntimeOperationsException { |
| throw new RuntimeOperationsException(new UnsupportedOperationException()); |
| } |
| |
| public final ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { |
| this.server = server; |
| this.name = name; |
| return name; |
| } |
| |
| public final void postRegister(Boolean registrationDone) { |
| if (registrationDone) { |
| sources.put(name, source); |
| } |
| } |
| |
| public final void preDeregister() throws Exception { |
| // Do nothing |
| } |
| |
| public final void postDeregister() { |
| sources.remove(name); |
| this.server = null; |
| this.name = null; |
| } |
| |
| private MBeanInfo createModelMBeanInfo(T source) { |
| String className = source.getClass().getName(); |
| String description = ""; |
| |
| ModelMBeanConstructorInfo[] constructors = new ModelMBeanConstructorInfo[0]; |
| ModelMBeanNotificationInfo[] notifications = new ModelMBeanNotificationInfo[0]; |
| |
| List<ModelMBeanAttributeInfo> attributes = new ArrayList<ModelMBeanAttributeInfo>(); |
| List<ModelMBeanOperationInfo> operations = new ArrayList<ModelMBeanOperationInfo>(); |
| |
| addAttributes(attributes, source); |
| addExtraAttributes(attributes); |
| |
| addOperations(operations, source); |
| addExtraOperations(operations); |
| operations.add(new ModelMBeanOperationInfo("unregisterMBean", "unregisterMBean", new MBeanParameterInfo[0], |
| void.class.getName(), ModelMBeanOperationInfo.ACTION)); |
| |
| return new ModelMBeanInfoSupport(className, description, |
| attributes.toArray(new ModelMBeanAttributeInfo[attributes.size()]), constructors, |
| operations.toArray(new ModelMBeanOperationInfo[operations.size()]), notifications); |
| } |
| |
| private void addAttributes(List<ModelMBeanAttributeInfo> attributes, Object object) { |
| addAttributes(attributes, object, object.getClass(), ""); |
| } |
| |
| private void addAttributes(List<ModelMBeanAttributeInfo> attributes, Object object, Class<?> type, String prefix) { |
| |
| PropertyDescriptor[] pdescs; |
| try { |
| pdescs = Introspector.getBeanInfo(type).getPropertyDescriptors(); |
| } catch (IntrospectionException e) { |
| return; |
| } |
| |
| for (PropertyDescriptor pdesc : pdescs) { |
| // Ignore a write-only property. |
| if (pdesc.getReadMethod() == null) { |
| continue; |
| } |
| |
| // Ignore unmanageable property. |
| String attrName = pdesc.getName(); |
| Class<?> attrType = pdesc.getPropertyType(); |
| if (attrName.equals("class")) { |
| continue; |
| } |
| if (!isReadable(type, attrName)) { |
| continue; |
| } |
| |
| // Expand if possible. |
| if (isExpandable(type, attrName)) { |
| expandAttribute(attributes, object, prefix, pdesc); |
| continue; |
| } |
| |
| // Ordinary property. |
| String fqan = prefix + attrName; |
| boolean writable = isWritable(type, pdesc); |
| attributes.add(new ModelMBeanAttributeInfo(fqan, convertType(object.getClass(), attrName, attrType, |
| writable).getName(), pdesc.getShortDescription(), true, writable, false)); |
| |
| propertyDescriptors.put(fqan, pdesc); |
| } |
| } |
| |
| private boolean isWritable(Class<?> type, PropertyDescriptor pdesc) { |
| if (type == null) { |
| throw new IllegalArgumentException("type"); |
| } |
| if (pdesc == null) { |
| return false; |
| } |
| String attrName = pdesc.getName(); |
| Class<?> attrType = pdesc.getPropertyType(); |
| boolean writable = (pdesc.getWriteMethod() != null) || isWritable(type, attrName); |
| if (getPropertyEditor(type, attrName, attrType) == null) { |
| writable = false; |
| } |
| return writable; |
| } |
| |
| private void expandAttribute(List<ModelMBeanAttributeInfo> attributes, Object object, String prefix, |
| PropertyDescriptor pdesc) { |
| Object property; |
| String attrName = pdesc.getName(); |
| try { |
| property = getAttribute(object, attrName, pdesc.getPropertyType()); |
| } catch (Exception e) { |
| if (LOGGER.isDebugEnabled()) { |
| LOGGER.debug("Unexpected exception.", e); |
| } |
| |
| return; |
| } |
| |
| if (property == null) { |
| return; |
| } |
| |
| addAttributes(attributes, property, property.getClass(), prefix + attrName + '.'); |
| } |
| |
| private void addOperations(List<ModelMBeanOperationInfo> operations, Object object) { |
| |
| for (Method m : object.getClass().getMethods()) { |
| String mname = m.getName(); |
| |
| // Ignore getters and setters. |
| if (mname.startsWith("is") || mname.startsWith("get") || mname.startsWith("set")) { |
| continue; |
| } |
| |
| // Ignore Object methods. |
| if (mname.matches("(wait|notify|notifyAll|toString|equals|compareTo|hashCode|clone)")) { |
| continue; |
| } |
| |
| // Ignore other user-defined non-operations. |
| if (!isOperation(mname, m.getParameterTypes())) { |
| continue; |
| } |
| |
| List<MBeanParameterInfo> signature = new ArrayList<MBeanParameterInfo>(); |
| int i = 1; |
| for (Class<?> paramType : m.getParameterTypes()) { |
| String paramName = "p" + (i++); |
| if (getPropertyEditor(source.getClass(), paramName, paramType) == null) { |
| continue; |
| } |
| signature.add(new MBeanParameterInfo(paramName, convertType(null, null, paramType, true).getName(), |
| paramName)); |
| } |
| |
| Class<?> returnType = convertType(null, null, m.getReturnType(), false); |
| operations.add(new ModelMBeanOperationInfo(m.getName(), m.getName(), signature |
| .toArray(new MBeanParameterInfo[signature.size()]), returnType.getName(), |
| ModelMBeanOperationInfo.ACTION)); |
| } |
| } |
| |
| private Object getParent(String fqan) throws OgnlException { |
| Object parent; |
| int dotIndex = fqan.lastIndexOf('.'); |
| if (dotIndex < 0) { |
| parent = source; |
| } else { |
| parent = getAttribute(source, fqan.substring(0, dotIndex), null); |
| } |
| return parent; |
| } |
| |
| private String getLeafAttributeName(String fqan) { |
| int dotIndex = fqan.lastIndexOf('.'); |
| if (dotIndex < 0) { |
| return fqan; |
| } |
| return fqan.substring(dotIndex + 1); |
| } |
| |
| private Class<?> getAttributeClass(String signature) throws ClassNotFoundException { |
| if (signature.equals(Boolean.TYPE.getName())) { |
| return Boolean.TYPE; |
| } |
| if (signature.equals(Byte.TYPE.getName())) { |
| return Byte.TYPE; |
| } |
| if (signature.equals(Character.TYPE.getName())) { |
| return Character.TYPE; |
| } |
| if (signature.equals(Double.TYPE.getName())) { |
| return Double.TYPE; |
| } |
| if (signature.equals(Float.TYPE.getName())) { |
| return Float.TYPE; |
| } |
| if (signature.equals(Integer.TYPE.getName())) { |
| return Integer.TYPE; |
| } |
| if (signature.equals(Long.TYPE.getName())) { |
| return Long.TYPE; |
| } |
| if (signature.equals(Short.TYPE.getName())) { |
| return Short.TYPE; |
| } |
| |
| try { |
| ClassLoader cl = Thread.currentThread().getContextClassLoader(); |
| if (cl != null) { |
| return cl.loadClass(signature); |
| } |
| } catch (ClassNotFoundException e) { |
| // Do nothing |
| } |
| |
| return Class.forName(signature); |
| } |
| |
| private Object getAttribute(Object object, String fqan, Class<?> attrType) throws OgnlException { |
| Object property; |
| OgnlContext ctx = (OgnlContext) Ognl.createDefaultContext(object); |
| ctx.setTypeConverter(new OgnlTypeConverter()); |
| if (attrType == null) { |
| property = Ognl.getValue(fqan, ctx, object); |
| } else { |
| property = Ognl.getValue(fqan, ctx, object, attrType); |
| } |
| return property; |
| } |
| |
| private Class<?> convertType(Class<?> type, String attrName, Class<?> attrType, boolean writable) { |
| if ((attrName != null) && ((attrType == Long.class) || (attrType == long.class))) { |
| if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0) |
| && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0) |
| && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) { |
| return Date.class; |
| } |
| } |
| |
| if (IoFilterChain.class.isAssignableFrom(attrType)) { |
| return Map.class; |
| } |
| |
| if (IoFilterChainBuilder.class.isAssignableFrom(attrType)) { |
| return Map.class; |
| } |
| |
| if (!writable) { |
| if (Collection.class.isAssignableFrom(attrType) || Map.class.isAssignableFrom(attrType)) { |
| if (List.class.isAssignableFrom(attrType)) { |
| return List.class; |
| } |
| if (Set.class.isAssignableFrom(attrType)) { |
| return Set.class; |
| } |
| if (Map.class.isAssignableFrom(attrType)) { |
| return Map.class; |
| } |
| return Collection.class; |
| } |
| |
| if (attrType.isPrimitive() || Date.class.isAssignableFrom(attrType) |
| || Boolean.class.isAssignableFrom(attrType) || Character.class.isAssignableFrom(attrType) |
| || Number.class.isAssignableFrom(attrType)) { |
| if ((attrName == null) || !attrName.endsWith("InMillis") |
| || !propertyDescriptors.containsKey(attrName.substring(0, attrName.length() - 8))) { |
| return attrType; |
| } |
| } |
| } |
| |
| return String.class; |
| } |
| |
| private Object convertValue(Class<?> type, String attrName, Object v, boolean writable) { |
| if (v == null) { |
| return null; |
| } |
| |
| if ((attrName != null) && (v instanceof Long)) { |
| if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0) |
| && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0) |
| && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) { |
| long time = (Long) v; |
| if (time <= 0) { |
| return null; |
| } |
| |
| return new Date((Long) v); |
| } |
| } |
| |
| if ((v instanceof IoSessionDataStructureFactory) || (v instanceof IoHandler)) { |
| return v.getClass().getName(); |
| } |
| |
| if (v instanceof IoFilterChainBuilder) { |
| Map<String, String> filterMapping = new LinkedHashMap<String, String>(); |
| if (v instanceof DefaultIoFilterChainBuilder) { |
| for (IoFilterChain.Entry e : ((DefaultIoFilterChainBuilder) v).getAll()) { |
| filterMapping.put(e.getName(), e.getFilter().getClass().getName()); |
| } |
| } else { |
| filterMapping.put("Unknown builder type", v.getClass().getName()); |
| } |
| return filterMapping; |
| } |
| |
| if (v instanceof IoFilterChain) { |
| Map<String, String> filterMapping = new LinkedHashMap<String, String>(); |
| for (IoFilterChain.Entry e : ((IoFilterChain) v).getAll()) { |
| filterMapping.put(e.getName(), e.getFilter().getClass().getName()); |
| } |
| return filterMapping; |
| } |
| |
| if (!writable) { |
| if ((v instanceof Collection) || (v instanceof Map)) { |
| if (v instanceof List) { |
| return convertCollection(v, new ArrayList<Object>()); |
| } |
| if (v instanceof Set) { |
| return convertCollection(v, new LinkedHashSet<Object>()); |
| } |
| if (v instanceof Map) { |
| return convertCollection(v, new LinkedHashMap<Object, Object>()); |
| } |
| return convertCollection(v, new ArrayList<Object>()); |
| } |
| |
| if ((v instanceof Date) || (v instanceof Boolean) || (v instanceof Character) || (v instanceof Number)) { |
| if ((attrName == null) || !attrName.endsWith("InMillis") |
| || !propertyDescriptors.containsKey(attrName.substring(0, attrName.length() - 8))) { |
| return v; |
| } |
| } |
| } |
| |
| PropertyEditor editor = getPropertyEditor(type, attrName, v.getClass()); |
| if (editor != null) { |
| editor.setValue(v); |
| return editor.getAsText(); |
| } |
| |
| return v.toString(); |
| } |
| |
| private Object convertCollection(Object src, Collection<Object> dst) { |
| Collection<?> srcCol = (Collection<?>) src; |
| for (Object e : srcCol) { |
| Object convertedValue = convertValue(dst.getClass(), "element", e, false); |
| if ((e != null) && (convertedValue == null)) { |
| convertedValue = e.toString(); |
| } |
| dst.add(convertedValue); |
| } |
| return dst; |
| } |
| |
| private Object convertCollection(Object src, Map<Object, Object> dst) { |
| Map<?, ?> srcCol = (Map<?, ?>) src; |
| for (Map.Entry<?, ?> e : srcCol.entrySet()) { |
| Object convertedKey = convertValue(dst.getClass(), "key", e.getKey(), false); |
| Object convertedValue = convertValue(dst.getClass(), "value", e.getValue(), false); |
| if ((e.getKey() != null) && (convertedKey == null)) { |
| convertedKey = e.getKey().toString(); |
| } |
| if ((e.getValue() != null) && (convertedValue == null)) { |
| convertedKey = e.getValue().toString(); |
| } |
| dst.put(convertedKey, convertedValue); |
| } |
| return dst; |
| } |
| |
| private void throwMBeanException(Throwable e) throws MBeanException { |
| if (e instanceof OgnlException) { |
| OgnlException ognle = (OgnlException) e; |
| |
| if (ognle.getReason() != null) { |
| throwMBeanException(ognle.getReason()); |
| } else { |
| String message = ognle.getMessage(); |
| |
| if (e instanceof NoSuchPropertyException) { |
| message = "No such property: " + message; |
| } else if (e instanceof ExpressionSyntaxException) { |
| message = "Illegal expression syntax: " + message; |
| } else if (e instanceof InappropriateExpressionException) { |
| message = "Inappropriate expression: " + message; |
| } |
| |
| e = new IllegalArgumentException(message); |
| e.setStackTrace(ognle.getStackTrace()); |
| } |
| } |
| if (e instanceof InvocationTargetException) { |
| throwMBeanException(e.getCause()); |
| } |
| |
| LOGGER.warn("Unexpected exception.", e); |
| if (e.getClass().getPackage().getName().matches("javax?\\..+")) { |
| if (e instanceof Exception) { |
| throw new MBeanException((Exception) e, e.getMessage()); |
| } |
| |
| throw new MBeanException(new RuntimeException(e), e.getMessage()); |
| } |
| |
| throw new MBeanException(new RuntimeException(e.getClass().getName() + ": " + e.getMessage()), e.getMessage()); |
| } |
| |
| protected Object getAttribute0(String fqan) throws Exception { |
| throw new AttributeNotFoundException(fqan); |
| } |
| |
| protected void setAttribute0(String attrName, Object attrValue) throws Exception { |
| throw new AttributeNotFoundException(attrName); |
| } |
| |
| protected Object invoke0(String name, Object params[], String signature[]) throws Exception { |
| throw new NoSuchMethodException(); |
| } |
| |
| protected boolean isReadable(Class<?> type, String attrName) { |
| if (IoService.class.isAssignableFrom(type) && attrName.equals("filterChain")) { |
| return false; |
| } |
| if (IoService.class.isAssignableFrom(type) && attrName.equals("localAddress")) { |
| return false; |
| } |
| if (IoService.class.isAssignableFrom(type) && attrName.equals("defaultLocalAddress")) { |
| return false; |
| } |
| if (IoSession.class.isAssignableFrom(type) && attrName.equals("attachment")) { |
| return false; |
| } |
| if (IoSession.class.isAssignableFrom(type) && attrName.equals("attributeKeys")) { |
| return false; |
| } |
| if (IoSession.class.isAssignableFrom(type) && attrName.equals("closeFuture")) { |
| return false; |
| } |
| |
| if (ThreadPoolExecutor.class.isAssignableFrom(type) && attrName.equals("queue")) { |
| return false; |
| } |
| |
| return true; |
| } |
| |
| protected boolean isWritable(Class<?> type, String attrName) { |
| if (IoService.class.isAssignableFrom(type) && attrName.startsWith("defaultLocalAddress")) { |
| return true; |
| } |
| return false; |
| } |
| |
| protected Class<?> getElementType(Class<?> type, String attrName) { |
| if ((transportMetadata != null) && IoAcceptor.class.isAssignableFrom(type) |
| && "defaultLocalAddresses".equals(attrName)) { |
| return transportMetadata.getAddressType(); |
| } |
| return String.class; |
| } |
| |
| protected Class<?> getMapKeyType(Class<?> type, String attrName) { |
| return String.class; |
| } |
| |
| protected Class<?> getMapValueType(Class<?> type, String attrName) { |
| return String.class; |
| } |
| |
| protected boolean isExpandable(Class<?> type, String attrName) { |
| |
| if (IoService.class.isAssignableFrom(type)) { |
| if (attrName.equals("statistics") || attrName.equals("sessionConfig") |
| || attrName.equals("transportMetadata") || attrName.equals("config") |
| || attrName.equals("transportMetadata")) { |
| return true; |
| } |
| } |
| |
| if (ExecutorFilter.class.isAssignableFrom(type) && attrName.equals("executor")) { |
| return true; |
| } |
| |
| if (ThreadPoolExecutor.class.isAssignableFrom(type) && attrName.equals("queueHandler")) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| protected boolean isOperation(String methodName, Class<?>[] paramTypes) { |
| return true; |
| } |
| |
| protected void addExtraAttributes(List<ModelMBeanAttributeInfo> attributes) { |
| // Do nothing |
| } |
| |
| protected void addExtraOperations(List<ModelMBeanOperationInfo> operations) { |
| // Do nothing |
| } |
| |
| protected PropertyEditor getPropertyEditor(Class<?> type, String attrName, Class<?> attrType) { |
| if (type == null) { |
| throw new IllegalArgumentException("type"); |
| } |
| |
| if (attrName == null) { |
| throw new IllegalArgumentException("attrName"); |
| } |
| |
| if ((transportMetadata != null) && (attrType == SocketAddress.class)) { |
| attrType = transportMetadata.getAddressType(); |
| } |
| |
| if (((attrType == Long.class) || (attrType == long.class))) { |
| if (attrName.endsWith("Time") && (attrName.indexOf("Total") < 0) && (attrName.indexOf("Min") < 0) |
| && (attrName.indexOf("Max") < 0) && (attrName.indexOf("Avg") < 0) |
| && (attrName.indexOf("Average") < 0) && !propertyDescriptors.containsKey(attrName + "InMillis")) { |
| return PropertyEditorFactory.getInstance(Date.class); |
| } |
| |
| if (attrName.equals("id")) { |
| return PropertyEditorFactory.getInstance(String.class); |
| } |
| } |
| |
| if (List.class.isAssignableFrom(attrType)) { |
| return new ListEditor(getElementType(type, attrName)); |
| } |
| |
| if (Set.class.isAssignableFrom(attrType)) { |
| return new SetEditor(getElementType(type, attrName)); |
| } |
| |
| if (Collection.class.isAssignableFrom(attrType)) { |
| return new CollectionEditor(getElementType(type, attrName)); |
| } |
| |
| if (Map.class.isAssignableFrom(attrType)) { |
| return new MapEditor(getMapKeyType(type, attrName), getMapValueType(type, attrName)); |
| } |
| |
| return PropertyEditorFactory.getInstance(attrType); |
| } |
| |
| private class OgnlTypeConverter extends PropertyTypeConverter { |
| @Override |
| protected PropertyEditor getPropertyEditor(Class<?> type, String attrName, Class<?> attrType) { |
| return ObjectMBean.this.getPropertyEditor(type, attrName, attrType); |
| } |
| } |
| } |