View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j.jmx;
    19
    20  import java.lang.reflect.Constructor;
    21  import org.apache.log4j.*;
    22  import org.apache.log4j.helpers.OptionConverter;
    23  import org.apache.log4j.spi.OptionHandler;
    24
    25  import java.util.Vector;
    26  import java.util.Hashtable;
    27  import java.lang.reflect.Method;
    28  import javax.management.MBeanAttributeInfo;
    29  import javax.management.MBeanConstructorInfo;
    30  import javax.management.MBeanNotificationInfo;
    31  import javax.management.ObjectName;
    32  import javax.management.MBeanInfo;
    33  import javax.management.Attribute;
    34  import javax.management.MBeanServer;
    35
    36  import javax.management.MBeanException;
    37  import javax.management.AttributeNotFoundException;
    38  import javax.management.RuntimeOperationsException;
    39  import javax.management.ReflectionException;
    40  import javax.management.InvalidAttributeValueException;
    41  import javax.management.MBeanOperationInfo;
    42  import javax.management.MBeanParameterInfo;
    43
    44  import java.beans.Introspector;
    45  import java.beans.BeanInfo;
    46  import java.beans.PropertyDescriptor;
    47  import java.beans.IntrospectionException;
    48
    49  public class AppenderDynamicMBean extends AbstractDynamicMBean {
    50
    51    private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
    52    private Vector dAttributes = new Vector();
    53    private String dClassName = this.getClass().getName();
    54
    55    private Hashtable dynamicProps = new Hashtable(5);
    56    private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[2];
    57    private String dDescription =
    58       "This MBean acts as a management facade for log4j appenders.";
    59
    60    // This category instance is for logging.
    61    private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
    62
    63    // We wrap this appender instance.
    64    private Appender appender;
    65
    66    public  AppenderDynamicMBean(Appender appender) throws IntrospectionException {
    67      this.appender = appender;
    68      buildDynamicMBeanInfo();
    69    }
    70
    71    private
    72    void buildDynamicMBeanInfo() throws IntrospectionException {
    73      Constructor[] constructors = this.getClass().getConstructors();
    74      dConstructors[0] = new MBeanConstructorInfo(
    75               "AppenderDynamicMBean(): Constructs a AppenderDynamicMBean instance",
    76  	     constructors[0]);
    77
    78
    79      BeanInfo bi = Introspector.getBeanInfo(appender.getClass());
    80      PropertyDescriptor[] pd = bi.getPropertyDescriptors();
    81
    82      int size = pd.length;
    83
    84      for(int i = 0; i < size; i++) {
    85        String name = pd[i].getName();
    86        Method readMethod =  pd[i].getReadMethod();
    87        Method writeMethod =  pd[i].getWriteMethod();
    88        if(readMethod != null) {
    89  	Class returnClass = readMethod.getReturnType();
    90  	if(isSupportedType(returnClass)) {
    91  	  String returnClassName;
    92  	  if(returnClass.isAssignableFrom(Priority.class)) {
    93  	    returnClassName = "java.lang.String";
    94  	  } else {
    95  	    returnClassName = returnClass.getName();
    96  	  }
    97
    98  	  dAttributes.add(new MBeanAttributeInfo(name,
    99  						 returnClassName,
    100 						 "Dynamic",
    101 						 true,
    102 						 writeMethod != null,
    103 						 false));
    104 	  dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
    105 	}
    106       }
    107     }
    108
    109     MBeanParameterInfo[] params = new MBeanParameterInfo[0];
    110
    111     dOperations[0] = new MBeanOperationInfo("activateOptions",
    112 					    "activateOptions(): add an appender",
    113 					    params,
    114 					    "void",
    115 					    MBeanOperationInfo.ACTION);
    116
    117     params = new MBeanParameterInfo[1];
    118     params[0] = new MBeanParameterInfo("layout class", "java.lang.String",
    119 				       "layout class");
    120
    121     dOperations[1] = new MBeanOperationInfo("setLayout",
    122 					    "setLayout(): add a layout",
    123 					    params,
    124 					    "void",
    125 					    MBeanOperationInfo.ACTION);
    126   }
    127
    128   private
    129   boolean isSupportedType(Class clazz) {
    130     if(clazz.isPrimitive()) {
    131       return true;
    132     }
    133
    134     if(clazz == String.class) {
    135       return true;
    136     }
    137
    138
    139     if(clazz.isAssignableFrom(Priority.class)) {
    140       return true;
    141     }
    142
    143     return false;
    144
    145
    146   }
    147
    148
    149
    150   public
    151   MBeanInfo getMBeanInfo() {
    152     cat.debug("getMBeanInfo called.");
    153
    154     MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
    155     dAttributes.toArray(attribs);
    156
    157     return new MBeanInfo(dClassName,
    158 			 dDescription,
    159 			 attribs,
    160 			 dConstructors,
    161 			 dOperations,
    162 			 new MBeanNotificationInfo[0]);
    163   }
    164
    165   public
    166   Object invoke(String operationName, Object params[], String signature[])
    167     throws MBeanException,
    168     ReflectionException {
    169
    170     if(operationName.equals("activateOptions") &&
    171                      appender instanceof OptionHandler) {
    172       OptionHandler oh = (OptionHandler) appender;
    173       oh.activateOptions();
    174       return "Options activated.";
    175     } else if (operationName.equals("setLayout")) {
    176       Layout layout = (Layout) OptionConverter.instantiateByClassName((String)
    177 								      params[0],
    178 								      Layout.class,
    179 								      null);
    180       appender.setLayout(layout);
    181       registerLayoutMBean(layout);
    182     }
    183     return null;
    184   }
    185
    186   void registerLayoutMBean(Layout layout) {
    187     if(layout == null)
    188       return;
    189
    190     String name = appender.getName()+",layout="+layout.getClass().getName();
    191     cat.debug("Adding LayoutMBean:"+name);
    192     ObjectName objectName = null;
    193     try {
    194       LayoutDynamicMBean appenderMBean = new LayoutDynamicMBean(layout);
    195       objectName = new ObjectName("log4j:appender="+name);
    196       if (!server.isRegistered(objectName)) {
    197         server.registerMBean(appenderMBean, objectName);
    198         dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
    199                 "The " + name + " layout.", true, true, false));
    200       }
    201
    202     } catch(Exception e) {
    203       cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
    204     }
    205   }
    206
    207   protected
    208   Logger getLogger() {
    209     return cat;
    210   }
    211
    212
    213   public
    214   Object getAttribute(String attributeName) throws AttributeNotFoundException,
    215                                                    MBeanException,
    216                                                    ReflectionException {
    217
    218        // Check attributeName is not null to avoid NullPointerException later on
    219     if (attributeName == null) {
    220       throw new RuntimeOperationsException(new IllegalArgumentException(
    221 			"Attribute name cannot be null"),
    222        "Cannot invoke a getter of " + dClassName + " with null attribute name");
    223     }
    224
    225     cat.debug("getAttribute called with ["+attributeName+"].");
    226     if(attributeName.startsWith("appender="+appender.getName()+",layout")) {
    227       try {
    228 	return new ObjectName("log4j:"+attributeName );
    229       } catch(Exception e) {
    230 	cat.error("attributeName", e);
    231       }
    232     }
    233
    234     MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
    235
    236     //cat.debug("----name="+attributeName+", b="+b);
    237
    238     if(mu != null && mu.readMethod != null) {
    239       try {
    240 	return mu.readMethod.invoke(appender, null);
    241       } catch(Exception e) {
    242 	return null;
    243       }
    244     }
    245
    246
    247
    248     // If attributeName has not been recognized throw an AttributeNotFoundException
    249     throw(new AttributeNotFoundException("Cannot find " + attributeName +
    250 					 " attribute in " + dClassName));
    251
    252   }
    253
    254
    255   public
    256   void setAttribute(Attribute attribute) throws AttributeNotFoundException,
    257                                                 InvalidAttributeValueException,
    258                                                 MBeanException,
    259                                                 ReflectionException {
    260
    261     // Check attribute is not null to avoid NullPointerException later on
    262     if (attribute == null) {
    263       throw new RuntimeOperationsException(
    264                   new IllegalArgumentException("Attribute cannot be null"),
    265 		  "Cannot invoke a setter of " + dClassName +
    266 		  " with null attribute");
    267     }
    268     String name = attribute.getName();
    269     Object value = attribute.getValue();
    270
    271     if (name == null) {
    272       throw new RuntimeOperationsException(
    273                     new IllegalArgumentException("Attribute name cannot be null"),
    274 		    "Cannot invoke the setter of "+dClassName+
    275 		    " with null attribute name");
    276     }
    277
    278
    279
    280     MethodUnion mu = (MethodUnion) dynamicProps.get(name);
    281
    282     if(mu != null && mu.writeMethod != null) {
    283       Object[] o = new Object[1];
    284
    285       Class[] params = mu.writeMethod.getParameterTypes();
    286       if(params[0] == org.apache.log4j.Priority.class) {
    287 	value = OptionConverter.toLevel((String) value,
    288 					(Level) getAttribute(name));
    289       }
    290       o[0] = value;
    291
    292       try {
    293 	mu.writeMethod.invoke(appender,  o);
    294
    295       } catch(Exception e) {
    296 	cat.error("FIXME", e);
    297       }
    298     } else if(name.endsWith(".layout")) {
    299
    300     } else {
    301       throw(new AttributeNotFoundException("Attribute " + name +
    302 					   " not found in " +
    303 					   this.getClass().getName()));
    304     }
    305   }
    306
    307   public
    308   ObjectName preRegister(MBeanServer server, ObjectName name) {
    309     cat.debug("preRegister called. Server="+server+ ", name="+name);
    310     this.server = server;
    311     registerLayoutMBean(appender.getLayout());
    312
    313     return name;
    314   }
    315
    316
    317 }
    318