001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 * 
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.log4j.jmx;
019
020import org.apache.log4j.Appender;
021import org.apache.log4j.Level;
022import org.apache.log4j.Logger;
023import org.apache.log4j.helpers.OptionConverter;
024
025import javax.management.Attribute;
026import javax.management.AttributeNotFoundException;
027import javax.management.InvalidAttributeValueException;
028import javax.management.JMException;
029import javax.management.MBeanAttributeInfo;
030import javax.management.MBeanConstructorInfo;
031import javax.management.MBeanException;
032import javax.management.MBeanInfo;
033import javax.management.MBeanNotificationInfo;
034import javax.management.MBeanOperationInfo;
035import javax.management.MBeanParameterInfo;
036import javax.management.MalformedObjectNameException;
037import javax.management.Notification;
038import javax.management.NotificationListener;
039import javax.management.ObjectName;
040import javax.management.ReflectionException;
041import javax.management.RuntimeOperationsException;
042import java.lang.reflect.Constructor;
043import java.util.Enumeration;
044import java.util.Vector;
045
046public class LoggerDynamicMBean extends AbstractDynamicMBean
047                                  implements NotificationListener {
048
049  private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
050  private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
051
052  private Vector dAttributes = new Vector();
053  private String dClassName = this.getClass().getName();
054
055  private String dDescription =
056     "This MBean acts as a management facade for a org.apache.log4j.Logger instance.";
057
058  // This Logger instance is for logging.
059  private static Logger cat = Logger.getLogger(LoggerDynamicMBean.class);
060
061  // We wrap this Logger instance.
062  private Logger logger;
063
064  public LoggerDynamicMBean(Logger logger) {
065    this.logger = logger;
066    buildDynamicMBeanInfo();
067  }
068
069  public
070  void handleNotification(Notification notification, Object handback) {
071    cat.debug("Received notification: "+notification.getType());
072    registerAppenderMBean((Appender) notification.getUserData() );
073
074
075  }
076
077  private
078  void buildDynamicMBeanInfo() {
079    Constructor[] constructors = this.getClass().getConstructors();
080    dConstructors[0] = new MBeanConstructorInfo(
081             "HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
082             constructors[0]);
083
084    dAttributes.add(new MBeanAttributeInfo("name",
085                                           "java.lang.String",
086                                           "The name of this Logger.",
087                                           true,
088                                           false,
089                                           false));
090
091    dAttributes.add(new MBeanAttributeInfo("priority",
092                                           "java.lang.String",
093                                           "The priority of this logger.",
094                                           true,
095                                           true,
096                                           false));
097
098
099
100
101
102    MBeanParameterInfo[] params = new MBeanParameterInfo[2];
103    params[0] = new MBeanParameterInfo("class name", "java.lang.String",
104                                       "add an appender to this logger");
105    params[1] = new MBeanParameterInfo("appender name", "java.lang.String",
106                                       "name of the appender");
107
108    dOperations[0] = new MBeanOperationInfo("addAppender",
109                                            "addAppender(): add an appender",
110                                            params,
111                                            "void",
112                                            MBeanOperationInfo.ACTION);
113  }
114
115  protected
116  Logger getLogger() {
117    return logger;
118  }
119
120
121  public
122  MBeanInfo getMBeanInfo() {
123    //cat.debug("getMBeanInfo called.");
124
125    MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
126    dAttributes.toArray(attribs);
127
128    MBeanInfo mb = new MBeanInfo(dClassName,
129                         dDescription,
130                         attribs,
131                         dConstructors,
132                         dOperations,
133                         new MBeanNotificationInfo[0]);
134    //cat.debug("getMBeanInfo exit.");
135    return mb;
136  }
137
138  public
139  Object invoke(String operationName, Object params[], String signature[])
140    throws MBeanException,
141    ReflectionException {
142
143    if(operationName.equals("addAppender")) {
144      addAppender((String) params[0], (String) params[1]);
145      return "Hello world.";
146    }
147
148    return null;
149  }
150
151
152  public
153  Object getAttribute(String attributeName) throws AttributeNotFoundException,
154                                                   MBeanException,
155                                                   ReflectionException {
156
157       // Check attributeName is not null to avoid NullPointerException later on
158    if (attributeName == null) {
159      throw new RuntimeOperationsException(new IllegalArgumentException(
160                        "Attribute name cannot be null"),
161       "Cannot invoke a getter of " + dClassName + " with null attribute name");
162    }
163
164    // Check for a recognized attributeName and call the corresponding getter
165    if (attributeName.equals("name")) {
166      return logger.getName();
167    }  else if(attributeName.equals("priority")) {
168      Level l = logger.getLevel();
169      if(l == null) {
170        return null;
171      } else {
172        return l.toString();
173      }
174    } else if(attributeName.startsWith("appender=")) {
175      try {
176        return new ObjectName("log4j:"+attributeName );
177      } catch(MalformedObjectNameException e) {
178            cat.error("Could not create ObjectName" + attributeName);
179      } catch(RuntimeException e) {
180            cat.error("Could not create ObjectName" + attributeName);
181      }
182    }
183
184
185    // If attributeName has not been recognized throw an AttributeNotFoundException
186    throw(new AttributeNotFoundException("Cannot find " + attributeName +
187                                         " attribute in " + dClassName));
188
189  }
190
191
192  void addAppender(String appenderClass, String appenderName) {
193    cat.debug("addAppender called with "+appenderClass+", "+appenderName);
194    Appender appender = (Appender)
195       OptionConverter.instantiateByClassName(appenderClass,
196                                              org.apache.log4j.Appender.class,
197                                              null);
198    appender.setName(appenderName);
199    logger.addAppender(appender);
200
201    //appenderMBeanRegistration();
202
203  }
204
205
206  public
207  void setAttribute(Attribute attribute) throws AttributeNotFoundException,
208                                                InvalidAttributeValueException,
209                                                MBeanException,
210                                                ReflectionException {
211
212    // Check attribute is not null to avoid NullPointerException later on
213    if (attribute == null) {
214      throw new RuntimeOperationsException(
215                  new IllegalArgumentException("Attribute cannot be null"),
216                  "Cannot invoke a setter of " + dClassName +
217                  " with null attribute");
218    }
219    String name = attribute.getName();
220    Object value = attribute.getValue();
221
222    if (name == null) {
223      throw new RuntimeOperationsException(
224                    new IllegalArgumentException("Attribute name cannot be null"),
225                    "Cannot invoke the setter of "+dClassName+
226                    " with null attribute name");
227    }
228
229
230    if(name.equals("priority")) {
231      if (value instanceof String) {
232        String s = (String) value;
233        Level p = logger.getLevel();
234        if(s.equalsIgnoreCase("NULL")) {
235          p = null;
236        } else {
237          p = OptionConverter.toLevel(s, p);
238        }
239        logger.setLevel(p);
240      }
241    } else {
242      throw(new AttributeNotFoundException("Attribute " + name +
243                                           " not found in " +
244                                           this.getClass().getName()));
245    }
246  }
247
248  void appenderMBeanRegistration() {
249    Enumeration enumeration = logger.getAllAppenders();
250    while(enumeration.hasMoreElements()) {
251      Appender appender = (Appender) enumeration.nextElement();
252      registerAppenderMBean(appender);
253    }
254  }
255
256  void registerAppenderMBean(Appender appender) {
257    String name = getAppenderName(appender);
258    cat.debug("Adding AppenderMBean for appender named "+name);
259    ObjectName objectName = null;
260    try {
261      AppenderDynamicMBean appenderMBean = new AppenderDynamicMBean(appender);
262      objectName = new ObjectName("log4j", "appender", name);
263      if (!server.isRegistered(objectName)) {
264        registerMBean(appenderMBean, objectName);
265        dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
266                "The " + name + " appender.", true, true, false));
267      }
268
269    } catch(JMException e) {
270      cat.error("Could not add appenderMBean for ["+name+"].", e);
271    } catch(java.beans.IntrospectionException e) {
272      cat.error("Could not add appenderMBean for ["+name+"].", e);
273    } catch(RuntimeException e) {
274      cat.error("Could not add appenderMBean for ["+name+"].", e);
275    }
276  }
277
278  public
279  void postRegister(java.lang.Boolean registrationDone) {
280    appenderMBeanRegistration();
281  }
282}