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 java.lang.reflect.Constructor;
22  import org.apache.log4j.*;
23  
24  import org.apache.log4j.spi.HierarchyEventListener;
25  import org.apache.log4j.spi.LoggerRepository;
26  import org.apache.log4j.helpers.OptionConverter;
27  
28  import java.util.Vector;
29  import javax.management.MBeanAttributeInfo;
30  import javax.management.MBeanConstructorInfo;
31  import javax.management.MBeanNotificationInfo;
32  import javax.management.MBeanOperationInfo;
33  import javax.management.MBeanParameterInfo;
34  
35  import javax.management.ObjectName;
36  import javax.management.MBeanInfo;
37  import javax.management.Attribute;
38  
39  import javax.management.MBeanException;
40  import javax.management.AttributeNotFoundException;
41  import javax.management.RuntimeOperationsException;
42  import javax.management.ReflectionException;
43  import javax.management.InvalidAttributeValueException;
44  import javax.management.NotificationBroadcasterSupport;
45  import javax.management.NotificationBroadcaster;
46  import javax.management.Notification;
47  import javax.management.NotificationListener;
48  import javax.management.NotificationFilter;
49  import javax.management.NotificationFilterSupport;
50  import javax.management.ListenerNotFoundException;
51  
52  public class HierarchyDynamicMBean extends AbstractDynamicMBean
53                                     implements HierarchyEventListener,
54                                                NotificationBroadcaster {
55  
56    static final String ADD_APPENDER = "addAppender.";
57    static final String THRESHOLD = "threshold";
58  
59    private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1];
60    private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1];
61  
62    private Vector vAttributes = new Vector();
63    private String dClassName = this.getClass().getName();
64    private String dDescription =
65       "This MBean acts as a management facade for org.apache.log4j.Hierarchy.";
66  
67    private NotificationBroadcasterSupport nbs = new NotificationBroadcasterSupport();
68  
69  
70    private LoggerRepository hierarchy;
71  
72    private static Logger log = Logger.getLogger(HierarchyDynamicMBean.class);
73  
74    public HierarchyDynamicMBean() {
75      hierarchy = LogManager.getLoggerRepository();
76      buildDynamicMBeanInfo();
77    }
78  
79    private
80    void buildDynamicMBeanInfo() {
81      Constructor[] constructors = this.getClass().getConstructors();
82      dConstructors[0] = new MBeanConstructorInfo(
83           "HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance",
84  	 constructors[0]);
85  
86      vAttributes.add(new MBeanAttributeInfo(THRESHOLD,
87  					   "java.lang.String",
88  					   "The \"threshold\" state of the hiearchy.",
89  					   true,
90  					   true,
91  					   false));
92  
93      MBeanParameterInfo[] params = new MBeanParameterInfo[1];
94      params[0] = new MBeanParameterInfo("name", "java.lang.String",
95  				       "Create a logger MBean" );
96      dOperations[0] = new MBeanOperationInfo("addLoggerMBean",
97  				    "addLoggerMBean(): add a loggerMBean",
98  				    params ,
99  				    "javax.management.ObjectName",
100 				    MBeanOperationInfo.ACTION);
101   }
102 
103 
104   public
105   ObjectName addLoggerMBean(String name) {
106     Logger cat = LogManager.exists(name);
107 
108     if(cat != null) {
109       return addLoggerMBean(cat);
110     } else {
111       return null;
112     }
113   }
114 
115   ObjectName addLoggerMBean(Logger logger) {
116     String name = logger.getName();
117     ObjectName objectName = null;
118     try {
119       LoggerDynamicMBean loggerMBean = new LoggerDynamicMBean(logger);
120       objectName = new ObjectName("log4j", "logger", name);
121       
122       if (!server.isRegistered(objectName)) {
123         server.registerMBean(loggerMBean, objectName);
124         NotificationFilterSupport nfs = new NotificationFilterSupport();
125         nfs.enableType(ADD_APPENDER + logger.getName());
126         log.debug("---Adding logger [" + name + "] as listener.");
127         nbs.addNotificationListener(loggerMBean, nfs, null);
128         vAttributes.add(new MBeanAttributeInfo("logger=" + name, "javax.management.ObjectName",
129                 "The " + name + " logger.", true, true, // this makes the object
130                 // clickable
131                 false));
132         
133       }
134 
135     } catch(Exception e) {
136       log.error("Could not add loggerMBean for ["+name+"].", e);
137     }
138     return objectName;
139   }
140 
141   public
142   void addNotificationListener(NotificationListener listener,
143 			       NotificationFilter filter,
144 			       java.lang.Object handback) {
145     nbs.addNotificationListener(listener, filter, handback);
146   }
147 
148   protected
149   Logger getLogger() {
150     return log;
151   }
152 
153   public
154   MBeanInfo getMBeanInfo() {
155     //cat.debug("getMBeanInfo called.");
156 
157     MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[vAttributes.size()];
158     vAttributes.toArray(attribs);
159 
160     return new MBeanInfo(dClassName,
161 			 dDescription,
162 			 attribs,
163 			 dConstructors,
164 			 dOperations,
165 			 new MBeanNotificationInfo[0]);
166   }
167 
168   public
169   MBeanNotificationInfo[] getNotificationInfo(){
170     return nbs.getNotificationInfo();
171   }
172 
173   public
174   Object invoke(String operationName,
175 		Object params[],
176 		String signature[]) throws MBeanException,
177                                            ReflectionException {
178 
179     if (operationName == null) {
180       throw new RuntimeOperationsException(
181         new IllegalArgumentException("Operation name cannot be null"),
182 	"Cannot invoke a null operation in " + dClassName);
183     }
184     // Check for a recognized operation name and call the corresponding operation
185 
186     if(operationName.equals("addLoggerMBean")) {
187       return addLoggerMBean((String)params[0]);
188     } else {
189       throw new ReflectionException(
190 	    new NoSuchMethodException(operationName),
191 	    "Cannot find the operation " + operationName + " in " + dClassName);
192     }
193 
194   }
195 
196 
197   public
198   Object getAttribute(String attributeName) throws AttributeNotFoundException,
199                                                     MBeanException,
200                                                     ReflectionException {
201 
202     // Check attributeName is not null to avoid NullPointerException later on
203     if (attributeName == null) {
204       throw new RuntimeOperationsException(new IllegalArgumentException(
205 			"Attribute name cannot be null"),
206        "Cannot invoke a getter of " + dClassName + " with null attribute name");
207     }
208 
209     log.debug("Called getAttribute with ["+attributeName+"].");
210 
211     // Check for a recognized attributeName and call the corresponding getter
212     if (attributeName.equals(THRESHOLD)) {
213       return hierarchy.getThreshold();
214     } else if(attributeName.startsWith("logger")) {
215       int k = attributeName.indexOf("%3D");
216       String val = attributeName;
217       if(k > 0) {
218 	val = attributeName.substring(0, k)+'='+ attributeName.substring(k+3);
219       }
220       try {
221 	return new ObjectName("log4j:"+val);
222       } catch(Exception e) {
223 	log.error("Could not create ObjectName" + val);
224       }
225     }
226 
227 
228 
229     // If attributeName has not been recognized throw an AttributeNotFoundException
230     throw(new AttributeNotFoundException("Cannot find " + attributeName +
231 					 " attribute in " + dClassName));
232 
233   }
234 
235 
236   public
237   void addAppenderEvent(Category logger, Appender appender) {
238     log.debug("addAppenderEvent called: logger="+logger.getName()+
239 	      ", appender="+appender.getName());
240     Notification n = new Notification(ADD_APPENDER+logger.getName(), this, 0);
241     n.setUserData(appender);
242     log.debug("sending notification.");
243     nbs.sendNotification(n);
244   }
245 
246  public
247   void removeAppenderEvent(Category cat, Appender appender) {
248     log.debug("removeAppenderCalled: logger="+cat.getName()+
249 	      ", appender="+appender.getName());
250   }
251 
252   public
253   void postRegister(java.lang.Boolean registrationDone) {
254     log.debug("postRegister is called.");
255     hierarchy.addHierarchyEventListener(this);
256     Logger root = hierarchy.getRootLogger();
257     addLoggerMBean(root);
258   }
259 
260   public
261   void removeNotificationListener(NotificationListener listener)
262                                          throws ListenerNotFoundException {
263     nbs.removeNotificationListener(listener);
264   }
265 
266   public
267   void setAttribute(Attribute attribute) throws AttributeNotFoundException,
268                                                 InvalidAttributeValueException,
269                                                 MBeanException,
270                                                 ReflectionException {
271 
272     // Check attribute is not null to avoid NullPointerException later on
273     if (attribute == null) {
274       throw new RuntimeOperationsException(
275                   new IllegalArgumentException("Attribute cannot be null"),
276 	  "Cannot invoke a setter of "+dClassName+" with null attribute");
277     }
278     String name = attribute.getName();
279     Object value = attribute.getValue();
280 
281     if (name == null) {
282       throw new RuntimeOperationsException(
283                new IllegalArgumentException("Attribute name cannot be null"),
284 	       "Cannot invoke the setter of "+dClassName+
285 	       " with null attribute name");
286     }
287 
288     if(name.equals(THRESHOLD)) {
289       Level l = OptionConverter.toLevel((String) value,
290 					   hierarchy.getThreshold());
291       hierarchy.setThreshold(l);
292     }
293 
294 
295   }
296 }