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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org.apache.log4j.jmx;
20 import org.apache.log4j.Appender;
21 import org.apache.log4j.Layout;
22 import org.apache.log4j.Level;
23 import org.apache.log4j.Logger;
24 import org.apache.log4j.Priority;
25 import org.apache.log4j.helpers.OptionConverter;
26 import org.apache.log4j.spi.OptionHandler;
28 import javax.management.Attribute;
29 import javax.management.AttributeNotFoundException;
30 import javax.management.InvalidAttributeValueException;
31 import javax.management.JMException;
32 import javax.management.MBeanAttributeInfo;
33 import javax.management.MBeanConstructorInfo;
34 import javax.management.MBeanException;
35 import javax.management.MBeanInfo;
36 import javax.management.MBeanNotificationInfo;
37 import javax.management.MBeanOperationInfo;
38 import javax.management.MBeanParameterInfo;
39 import javax.management.MBeanServer;
40 import javax.management.MalformedObjectNameException;
41 import javax.management.ObjectName;
42 import javax.management.ReflectionException;
43 import javax.management.RuntimeOperationsException;
44 import java.beans.BeanInfo;
45 import java.beans.IntrospectionException;
46 import java.beans.Introspector;
47 import java.beans.PropertyDescriptor;
48 import java.lang.reflect.Constructor;
49 import java.lang.reflect.InvocationTargetException;
50 import java.lang.reflect.Method;
51 import java.util.Hashtable;
52 import java.util.Vector;
53 import java.io.InterruptedIOException;
55 public class AppenderDynamicMBean extends AbstractDynamicMBean {
57 private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
58 private Vector dAttributes = new Vector();
59 private String dClassName = this.getClass().getName();
61 private Hashtable dynamicProps = new Hashtable(5);
62 private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[2];
63 private String dDescription =
64 "This MBean acts as a management facade for log4j appenders.";
66 // This category instance is for logging.
67 private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
69 // We wrap this appender instance.
70 private Appender appender;
72 public AppenderDynamicMBean(Appender appender) throws IntrospectionException {
73 this.appender = appender;
74 buildDynamicMBeanInfo();
78 void buildDynamicMBeanInfo() throws IntrospectionException {
79 Constructor[] constructors = this.getClass().getConstructors();
80 dConstructors[0] = new MBeanConstructorInfo(
81 "AppenderDynamicMBean(): Constructs a AppenderDynamicMBean instance",
85 BeanInfo bi = Introspector.getBeanInfo(appender.getClass());
86 PropertyDescriptor[] pd = bi.getPropertyDescriptors();
90 for(int i = 0; i < size; i++) {
91 String name = pd[i].getName();
92 Method readMethod = pd[i].getReadMethod();
93 Method writeMethod = pd[i].getWriteMethod();
94 if(readMethod != null) {
95 Class returnClass = readMethod.getReturnType();
96 if(isSupportedType(returnClass)) {
97 String returnClassName;
98 if(returnClass.isAssignableFrom(Priority.class)) {
99 returnClassName = "java.lang.String";
101 returnClassName = returnClass.getName();
104 dAttributes.add(new MBeanAttributeInfo(name,
110 dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
115 MBeanParameterInfo[] params = new MBeanParameterInfo[0];
117 dOperations[0] = new MBeanOperationInfo("activateOptions",
118 "activateOptions(): add an appender",
121 MBeanOperationInfo.ACTION);
123 params = new MBeanParameterInfo[1];
124 params[0] = new MBeanParameterInfo("layout class", "java.lang.String",
127 dOperations[1] = new MBeanOperationInfo("setLayout",
128 "setLayout(): add a layout",
131 MBeanOperationInfo.ACTION);
135 boolean isSupportedType(Class clazz) {
136 if(clazz.isPrimitive()) {
140 if(clazz == String.class) {
145 if(clazz.isAssignableFrom(Priority.class)) {
157 MBeanInfo getMBeanInfo() {
158 cat.debug("getMBeanInfo called.");
160 MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
161 dAttributes.toArray(attribs);
163 return new MBeanInfo(dClassName,
168 new MBeanNotificationInfo[0]);
172 Object invoke(String operationName, Object params[], String signature[])
173 throws MBeanException,
174 ReflectionException {
176 if(operationName.equals("activateOptions") &&
177 appender instanceof OptionHandler) {
178 OptionHandler oh = (OptionHandler) appender;
179 oh.activateOptions();
180 return "Options activated.";
181 } else if (operationName.equals("setLayout")) {
182 Layout layout = (Layout) OptionConverter.instantiateByClassName((String)
186 appender.setLayout(layout);
187 registerLayoutMBean(layout);
192 void registerLayoutMBean(Layout layout) {
197 String name = getAppenderName(appender)+",layout="+layout.getClass().getName();
198 cat.debug("Adding LayoutMBean:"+name);
199 ObjectName objectName = null;
201 LayoutDynamicMBean appenderMBean = new LayoutDynamicMBean(layout);
202 objectName = new ObjectName("log4j:appender="+name);
203 if (!server.isRegistered(objectName)) {
204 registerMBean(appenderMBean, objectName);
205 dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
206 "The " + name + " layout.", true, true, false));
209 } catch(JMException e) {
210 cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
211 } catch(java.beans.IntrospectionException e) {
212 cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
213 } catch(RuntimeException e) {
214 cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
225 Object getAttribute(String attributeName) throws AttributeNotFoundException,
227 ReflectionException {
229 // Check attributeName is not null to avoid NullPointerException later on
230 if (attributeName == null) {
231 throw new RuntimeOperationsException(new IllegalArgumentException(
232 "Attribute name cannot be null"),
233 "Cannot invoke a getter of " + dClassName + " with null attribute name");
236 cat.debug("getAttribute called with ["+attributeName+"].");
237 if(attributeName.startsWith("appender="+appender.getName()+",layout")) {
239 return new ObjectName("log4j:"+attributeName );
240 } catch(MalformedObjectNameException e) {
241 cat.error("attributeName", e);
242 } catch(RuntimeException e) {
243 cat.error("attributeName", e);
247 MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
249 //cat.debug("----name="+attributeName+", b="+b);
251 if(mu != null && mu.readMethod != null) {
253 return mu.readMethod.invoke(appender, null);
254 } catch(IllegalAccessException e) {
256 } catch(InvocationTargetException e) {
257 if (e.getTargetException() instanceof InterruptedException
258 || e.getTargetException() instanceof InterruptedIOException) {
259 Thread.currentThread().interrupt();
262 } catch(RuntimeException e) {
269 // If attributeName has not been recognized throw an AttributeNotFoundException
270 throw(new AttributeNotFoundException("Cannot find " + attributeName +
271 " attribute in " + dClassName));
277 void setAttribute(Attribute attribute) throws AttributeNotFoundException,
278 InvalidAttributeValueException,
280 ReflectionException {
282 // Check attribute is not null to avoid NullPointerException later on
283 if (attribute == null) {
284 throw new RuntimeOperationsException(
285 new IllegalArgumentException("Attribute cannot be null"),
286 "Cannot invoke a setter of " + dClassName +
287 " with null attribute");
289 String name = attribute.getName();
290 Object value = attribute.getValue();
293 throw new RuntimeOperationsException(
294 new IllegalArgumentException("Attribute name cannot be null"),
295 "Cannot invoke the setter of "+dClassName+
296 " with null attribute name");
301 MethodUnion mu = (MethodUnion) dynamicProps.get(name);
303 if(mu != null && mu.writeMethod != null) {
304 Object[] o = new Object[1];
306 Class[] params = mu.writeMethod.getParameterTypes();
307 if(params[0] == org.apache.log4j.Priority.class) {
308 value = OptionConverter.toLevel((String) value,
309 (Level) getAttribute(name));
314 mu.writeMethod.invoke(appender, o);
316 } catch(InvocationTargetException e) {
317 if (e.getTargetException() instanceof InterruptedException
318 || e.getTargetException() instanceof InterruptedIOException) {
319 Thread.currentThread().interrupt();
321 cat.error("FIXME", e);
322 } catch(IllegalAccessException e) {
323 cat.error("FIXME", e);
324 } catch(RuntimeException e) {
325 cat.error("FIXME", e);
327 } else if(name.endsWith(".layout")) {
330 throw(new AttributeNotFoundException("Attribute " + name +
332 this.getClass().getName()));
337 ObjectName preRegister(MBeanServer server, ObjectName name) {
338 cat.debug("preRegister called. Server="+server+ ", name="+name);
339 this.server = server;
340 registerLayoutMBean(appender.getLayout());