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
    21  import org.apache.log4j.Appender;
    22  import org.apache.log4j.Category;
    23  import org.apache.log4j.Level;
    24  import org.apache.log4j.LogManager;
    25  import org.apache.log4j.Logger;
    26  import org.apache.log4j.helpers.OptionConverter;
    27  import org.apache.log4j.spi.HierarchyEventListener;
    28  import org.apache.log4j.spi.LoggerRepository;
    29
    30  import javax.management.Attribute;
    31  import javax.management.AttributeNotFoundException;
    32  import javax.management.InvalidAttributeValueException;
    33  import javax.management.JMException;
    34  import javax.management.ListenerNotFoundException;
    35  import javax.management.MBeanAttributeInfo;
    36  import javax.management.MBeanConstructorInfo;
    37  import javax.management.MBeanException;
    38  import javax.management.MBeanInfo;
    39  import javax.management.MBeanNotificationInfo;
    40  import javax.management.MBeanOperationInfo;
    41  import javax.management.MBeanParameterInfo;
    42  import javax.management.Notification;
    43  import javax.management.NotificationBroadcaster;
    44  import javax.management.NotificationBroadcasterSupport;
    45  import javax.management.NotificationFilter;
    46  import javax.management.NotificationFilterSupport;
    47  import javax.management.NotificationListener;
    48  import javax.management.ObjectName;
    49  import javax.management.ReflectionException;
    50  import javax.management.RuntimeOperationsException;
    51  import java.lang.reflect.Constructor;
    52  import java.util.Vector;
    53
    54  public class HierarchyDynamicMBean extends AbstractDynamicMBean
    55                                     implements HierarchyEventListener,
    56                                                NotificationBroadcaster {
    57
    58    static final String ADD_APPENDER = "addAppender.";
    59    static final String THRESHOLD = "threshold";
    60
    61    private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
    62    private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
    63
    64    private Vector vAttributes = new Vector();
    65    private String dClassName = this.getClass().getName();
    66    private String dDescription =
    67       "This MBean acts as a management facade for org.apache.log4j.Hierarchy.";
    68
    69    private NotificationBroadcasterSupport nbs = new NotificationBroadcasterSupport();
    70
    71
    72    private LoggerRepository hierarchy;
    73
    74    private static Logger log = Logger.getLogger(HierarchyDynamicMBean.class);
    75
    76    public HierarchyDynamicMBean() {
    77      hierarchy = LogManager.getLoggerRepository();
    78      buildDynamicMBeanInfo();
    79    }
    80
    81    private
    82    void buildDynamicMBeanInfo() {
    83      Constructor[] constructors = this.getClass().getConstructors();
    84      dConstructors[0] = new MBeanConstructorInfo(
    85           "HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
    86  	 constructors[0]);
    87
    88      vAttributes.add(new MBeanAttributeInfo(THRESHOLD,
    89  					   "java.lang.String",
    90  					   "The \"threshold\" state of the hiearchy.",
    91  					   true,
    92  					   true,
    93  					   false));
    94
    95      MBeanParameterInfo[] params = new MBeanParameterInfo[1];
    96      params[0] = new MBeanParameterInfo("name", "java.lang.String",
    97  				       "Create a logger MBean" );
    98      dOperations[0] = new MBeanOperationInfo("addLoggerMBean",
    99  				    "addLoggerMBean(): add a loggerMBean",
    100 				    params ,
    101 				    "javax.management.ObjectName",
    102 				    MBeanOperationInfo.ACTION);
    103   }
    104
    105
    106   public
    107   ObjectName addLoggerMBean(String name) {
    108     Logger cat = LogManager.exists(name);
    109
    110     if(cat != null) {
    111       return addLoggerMBean(cat);
    112     } else {
    113       return null;
    114     }
    115   }
    116
    117   ObjectName addLoggerMBean(Logger logger) {
    118     String name = logger.getName();
    119     ObjectName objectName = null;
    120     try {
    121       LoggerDynamicMBean loggerMBean = new LoggerDynamicMBean(logger);
    122       objectName = new ObjectName("log4j", "logger", name);
    123
    124       if (!server.isRegistered(objectName)) {
    125         registerMBean(loggerMBean, objectName);
    126         NotificationFilterSupport nfs = new NotificationFilterSupport();
    127         nfs.enableType(ADD_APPENDER + logger.getName());
    128         log.debug("---Adding logger [" + name + "] as listener.");
    129         nbs.addNotificationListener(loggerMBean, nfs, null);
    130         vAttributes.add(new MBeanAttributeInfo("logger=" + name, "javax.management.ObjectName",
    131                 "The " + name + " logger.", true, true, // this makes the object
    132                 // clickable
    133                 false));
    134
    135       }
    136
    137     } catch(JMException e) {
    138       log.error("Could not add loggerMBean for ["+name+"].", e);
    139     } catch(RuntimeException e) {
    140       log.error("Could not add loggerMBean for ["+name+"].", e);
    141     }
    142     return objectName;
    143   }
    144
    145   public
    146   void addNotificationListener(NotificationListener listener,
    147 			       NotificationFilter filter,
    148 			       java.lang.Object handback) {
    149     nbs.addNotificationListener(listener, filter, handback);
    150   }
    151
    152   protected
    153   Logger getLogger() {
    154     return log;
    155   }
    156
    157   public
    158   MBeanInfo getMBeanInfo() {
    159     //cat.debug("getMBeanInfo called.");
    160
    161     MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[vAttributes.size()];
    162     vAttributes.toArray(attribs);
    163
    164     return new MBeanInfo(dClassName,
    165 			 dDescription,
    166 			 attribs,
    167 			 dConstructors,
    168 			 dOperations,
    169 			 new MBeanNotificationInfo[0]);
    170   }
    171
    172   public
    173   MBeanNotificationInfo[] getNotificationInfo(){
    174     return nbs.getNotificationInfo();
    175   }
    176
    177   public
    178   Object invoke(String operationName,
    179 		Object params[],
    180 		String signature[]) throws MBeanException,
    181                                            ReflectionException {
    182
    183     if (operationName == null) {
    184       throw new RuntimeOperationsException(
    185         new IllegalArgumentException("Operation name cannot be null"),
    186 	"Cannot invoke a null operation in " + dClassName);
    187     }
    188     // Check for a recognized operation name and call the corresponding operation
    189
    190     if(operationName.equals("addLoggerMBean")) {
    191       return addLoggerMBean((String)params[0]);
    192     } else {
    193       throw new ReflectionException(
    194 	    new NoSuchMethodException(operationName),
    195 	    "Cannot find the operation " + operationName + " in " + dClassName);
    196     }
    197
    198   }
    199
    200
    201   public
    202   Object getAttribute(String attributeName) throws AttributeNotFoundException,
    203                                                     MBeanException,
    204                                                     ReflectionException {
    205
    206     // Check attributeName is not null to avoid NullPointerException later on
    207     if (attributeName == null) {
    208       throw new RuntimeOperationsException(new IllegalArgumentException(
    209 			"Attribute name cannot be null"),
    210        "Cannot invoke a getter of " + dClassName + " with null attribute name");
    211     }
    212
    213     log.debug("Called getAttribute with ["+attributeName+"].");
    214
    215     // Check for a recognized attributeName and call the corresponding getter
    216     if (attributeName.equals(THRESHOLD)) {
    217       return hierarchy.getThreshold();
    218     } else if(attributeName.startsWith("logger")) {
    219       int k = attributeName.indexOf("%3D");
    220       String val = attributeName;
    221       if(k > 0) {
    222 	val = attributeName.substring(0, k)+'='+ attributeName.substring(k+3);
    223       }
    224       try {
    225 	return new ObjectName("log4j:"+val);
    226       } catch(JMException e) {
    227 	    log.error("Could not create ObjectName" + val);
    228       } catch(RuntimeException e) {
    229 	    log.error("Could not create ObjectName" + val);
    230       }
    231     }
    232
    233
    234
    235     // If attributeName has not been recognized throw an AttributeNotFoundException
    236     throw(new AttributeNotFoundException("Cannot find " + attributeName +
    237 					 " attribute in " + dClassName));
    238
    239   }
    240
    241
    242   public
    243   void addAppenderEvent(Category logger, Appender appender) {
    244     log.debug("addAppenderEvent called: logger="+logger.getName()+
    245 	      ", appender="+appender.getName());
    246     Notification n = new Notification(ADD_APPENDER+logger.getName(), this, 0);
    247     n.setUserData(appender);
    248     log.debug("sending notification.");
    249     nbs.sendNotification(n);
    250   }
    251
    252  public
    253   void removeAppenderEvent(Category cat, Appender appender) {
    254     log.debug("removeAppenderCalled: logger="+cat.getName()+
    255 	      ", appender="+appender.getName());
    256   }
    257
    258   public
    259   void postRegister(java.lang.Boolean registrationDone) {
    260     log.debug("postRegister is called.");
    261     hierarchy.addHierarchyEventListener(this);
    262     Logger root = hierarchy.getRootLogger();
    263     addLoggerMBean(root);
    264   }
    265
    266   public
    267   void removeNotificationListener(NotificationListener listener)
    268                                          throws ListenerNotFoundException {
    269     nbs.removeNotificationListener(listener);
    270   }
    271
    272   public
    273   void setAttribute(Attribute attribute) throws AttributeNotFoundException,
    274                                                 InvalidAttributeValueException,
    275                                                 MBeanException,
    276                                                 ReflectionException {
    277
    278     // Check attribute is not null to avoid NullPointerException later on
    279     if (attribute == null) {
    280       throw new RuntimeOperationsException(
    281                   new IllegalArgumentException("Attribute cannot be null"),
    282 	  "Cannot invoke a setter of "+dClassName+" with null attribute");
    283     }
    284     String name = attribute.getName();
    285     Object value = attribute.getValue();
    286
    287     if (name == null) {
    288       throw new RuntimeOperationsException(
    289                new IllegalArgumentException("Attribute name cannot be null"),
    290 	       "Cannot invoke the setter of "+dClassName+
    291 	       " with null attribute name");
    292     }
    293
    294     if(name.equals(THRESHOLD)) {
    295       Level l = OptionConverter.toLevel((String) value,
    296 					   hierarchy.getThreshold());
    297       hierarchy.setThreshold(l);
    298     }
    299
    300
    301   }
    302 }