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 }