1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.log4j.jmx;
19
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;
27
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;
54
55 public class AppenderDynamicMBean extends AbstractDynamicMBean {
56
57 private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
58 private Vector dAttributes = new Vector();
59 private String dClassName = this.getClass().getName();
60
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.";
65
66
67 private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
68
69
70 private Appender appender;
71
72 public AppenderDynamicMBean(Appender appender) throws IntrospectionException {
73 this.appender = appender;
74 buildDynamicMBeanInfo();
75 }
76
77 private
78 void buildDynamicMBeanInfo() throws IntrospectionException {
79 Constructor[] constructors = this.getClass().getConstructors();
80 dConstructors[0] = new MBeanConstructorInfo(
81 "AppenderDynamicMBean(): Constructs a AppenderDynamicMBean instance",
82 constructors[0]);
83
84
85 BeanInfo bi = Introspector.getBeanInfo(appender.getClass());
86 PropertyDescriptor[] pd = bi.getPropertyDescriptors();
87
88 int size = pd.length;
89
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";
100 } else {
101 returnClassName = returnClass.getName();
102 }
103
104 dAttributes.add(new MBeanAttributeInfo(name,
105 returnClassName,
106 "Dynamic",
107 true,
108 writeMethod != null,
109 false));
110 dynamicProps.put(name, new MethodUnion(readMethod, writeMethod));
111 }
112 }
113 }
114
115 MBeanParameterInfo[] params = new MBeanParameterInfo[0];
116
117 dOperations[0] = new MBeanOperationInfo("activateOptions",
118 "activateOptions(): add an appender",
119 params,
120 "void",
121 MBeanOperationInfo.ACTION);
122
123 params = new MBeanParameterInfo[1];
124 params[0] = new MBeanParameterInfo("layout class", "java.lang.String",
125 "layout class");
126
127 dOperations[1] = new MBeanOperationInfo("setLayout",
128 "setLayout(): add a layout",
129 params,
130 "void",
131 MBeanOperationInfo.ACTION);
132 }
133
134 private
135 boolean isSupportedType(Class clazz) {
136 if(clazz.isPrimitive()) {
137 return true;
138 }
139
140 if(clazz == String.class) {
141 return true;
142 }
143
144
145 if(clazz.isAssignableFrom(Priority.class)) {
146 return true;
147 }
148
149 return false;
150
151
152 }
153
154
155
156 public
157 MBeanInfo getMBeanInfo() {
158 cat.debug("getMBeanInfo called.");
159
160 MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()];
161 dAttributes.toArray(attribs);
162
163 return new MBeanInfo(dClassName,
164 dDescription,
165 attribs,
166 dConstructors,
167 dOperations,
168 new MBeanNotificationInfo[0]);
169 }
170
171 public
172 Object invoke(String operationName, Object params[], String signature[])
173 throws MBeanException,
174 ReflectionException {
175
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)
183 params[0],
184 Layout.class,
185 null);
186 appender.setLayout(layout);
187 registerLayoutMBean(layout);
188 }
189 return null;
190 }
191
192 void registerLayoutMBean(Layout layout) {
193 if(layout == null)
194 return;
195
196 String name = getAppenderName(appender)+",layout="+layout.getClass().getName();
197 cat.debug("Adding LayoutMBean:"+name);
198 ObjectName objectName = null;
199 try {
200 LayoutDynamicMBean appenderMBean = new LayoutDynamicMBean(layout);
201 objectName = new ObjectName("log4j:appender="+name);
202 if (!server.isRegistered(objectName)) {
203 registerMBean(appenderMBean, objectName);
204 dAttributes.add(new MBeanAttributeInfo("appender=" + name, "javax.management.ObjectName",
205 "The " + name + " layout.", true, true, false));
206 }
207
208 } catch(JMException e) {
209 cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
210 } catch(java.beans.IntrospectionException e) {
211 cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
212 } catch(RuntimeException e) {
213 cat.error("Could not add DynamicLayoutMBean for ["+name+"].", e);
214 }
215 }
216
217 protected
218 Logger getLogger() {
219 return cat;
220 }
221
222
223 public
224 Object getAttribute(String attributeName) throws AttributeNotFoundException,
225 MBeanException,
226 ReflectionException {
227
228
229 if (attributeName == null) {
230 throw new RuntimeOperationsException(new IllegalArgumentException(
231 "Attribute name cannot be null"),
232 "Cannot invoke a getter of " + dClassName + " with null attribute name");
233 }
234
235 cat.debug("getAttribute called with ["+attributeName+"].");
236 if(attributeName.startsWith("appender="+appender.getName()+",layout")) {
237 try {
238 return new ObjectName("log4j:"+attributeName );
239 } catch(MalformedObjectNameException e) {
240 cat.error("attributeName", e);
241 } catch(RuntimeException e) {
242 cat.error("attributeName", e);
243 }
244 }
245
246 MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName);
247
248
249
250 if(mu != null && mu.readMethod != null) {
251 try {
252 return mu.readMethod.invoke(appender, null);
253 } catch(IllegalAccessException e) {
254 return null;
255 } catch(InvocationTargetException e) {
256 if (e.getTargetException() instanceof InterruptedException
257 || e.getTargetException() instanceof InterruptedIOException) {
258 Thread.currentThread().interrupt();
259 }
260 return null;
261 } catch(RuntimeException e) {
262 return null;
263 }
264 }
265
266
267
268
269 throw(new AttributeNotFoundException("Cannot find " + attributeName +
270 " attribute in " + dClassName));
271
272 }
273
274
275 public
276 void setAttribute(Attribute attribute) throws AttributeNotFoundException,
277 InvalidAttributeValueException,
278 MBeanException,
279 ReflectionException {
280
281
282 if (attribute == null) {
283 throw new RuntimeOperationsException(
284 new IllegalArgumentException("Attribute cannot be null"),
285 "Cannot invoke a setter of " + dClassName +
286 " with null attribute");
287 }
288 String name = attribute.getName();
289 Object value = attribute.getValue();
290
291 if (name == null) {
292 throw new RuntimeOperationsException(
293 new IllegalArgumentException("Attribute name cannot be null"),
294 "Cannot invoke the setter of "+dClassName+
295 " with null attribute name");
296 }
297
298
299
300 MethodUnion mu = (MethodUnion) dynamicProps.get(name);
301
302 if(mu != null && mu.writeMethod != null) {
303 Object[] o = new Object[1];
304
305 Class[] params = mu.writeMethod.getParameterTypes();
306 if(params[0] == org.apache.log4j.Priority.class) {
307 value = OptionConverter.toLevel((String) value,
308 (Level) getAttribute(name));
309 }
310 o[0] = value;
311
312 try {
313 mu.writeMethod.invoke(appender, o);
314
315 } catch(InvocationTargetException e) {
316 if (e.getTargetException() instanceof InterruptedException
317 || e.getTargetException() instanceof InterruptedIOException) {
318 Thread.currentThread().interrupt();
319 }
320 cat.error("FIXME", e);
321 } catch(IllegalAccessException e) {
322 cat.error("FIXME", e);
323 } catch(RuntimeException e) {
324 cat.error("FIXME", e);
325 }
326 } else if(name.endsWith(".layout")) {
327
328 } else {
329 throw(new AttributeNotFoundException("Attribute " + name +
330 " not found in " +
331 this.getClass().getName()));
332 }
333 }
334
335 public
336 ObjectName preRegister(MBeanServer server, ObjectName name) {
337 cat.debug("preRegister called. Server="+server+ ", name="+name);
338 this.server = server;
339 registerLayoutMBean(appender.getLayout());
340
341 return name;
342 }
343
344
345 }
346