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 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
61 private static Logger cat = Logger.getLogger(AppenderDynamicMBean.class);
62
63
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
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
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
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
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