001 // Copyright 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.hivemind.management.log4j;
016
017 import java.util.ArrayList;
018 import java.util.Enumeration;
019 import java.util.List;
020
021 import javax.management.Attribute;
022 import javax.management.AttributeNotFoundException;
023 import javax.management.InvalidAttributeValueException;
024 import javax.management.MBeanAttributeInfo;
025 import javax.management.MBeanConstructorInfo;
026 import javax.management.MBeanException;
027 import javax.management.MBeanInfo;
028 import javax.management.MBeanNotificationInfo;
029 import javax.management.MBeanOperationInfo;
030 import javax.management.MBeanParameterInfo;
031 import javax.management.Notification;
032 import javax.management.NotificationListener;
033 import javax.management.ObjectName;
034 import javax.management.ReflectionException;
035 import javax.management.RuntimeOperationsException;
036
037 import org.apache.hivemind.management.mbeans.AbstractDynamicMBean;
038 import org.apache.log4j.Appender;
039 import org.apache.log4j.Level;
040 import org.apache.log4j.Logger;
041 import org.apache.log4j.helpers.OptionConverter;
042 import org.apache.log4j.jmx.AppenderDynamicMBean;
043
044 /**
045 * MBean for the management of a Log4j logger. Allows to change the level and add appenders. This is
046 * a copy of the {@link org.apache.log4j.jmx.LoggerDynamicMBean} from the log4 library. The copy was
047 * made to fix an issue with jboss 3.2.7, that don't accept spaces in attribute names. If somebody
048 * feels that such a copy from one apache project to another is not ok, please tell me.
049 *
050 * @author Achim Huegen
051 */
052 public class LoggerMBean extends AbstractDynamicMBean implements NotificationListener
053 {
054
055 private MBeanConstructorInfo[] _constructors = new MBeanConstructorInfo[0];
056
057 private MBeanOperationInfo[] _operations = new MBeanOperationInfo[1];
058
059 private List _attributes = new ArrayList();
060
061 private String _className = this.getClass().getName();
062
063 private String _description = "This MBean acts as a management facade for a org.apache.log4j.Logger instance.";
064
065 // This Logger instance is for logging.
066 private static Logger _log = Logger.getLogger(LoggerMBean.class);
067
068 // We wrap this Logger instance.
069 private Logger _logger;
070
071 public LoggerMBean(Logger logger)
072 {
073 this._logger = logger;
074 buildDynamicMBeanInfo();
075 }
076
077 public void handleNotification(Notification notification, Object handback)
078 {
079 _log.debug("Received notification: " + notification.getType());
080 registerAppenderMBean((Appender) notification.getUserData());
081
082 }
083
084 private void buildDynamicMBeanInfo()
085 {
086 _attributes.add(new MBeanAttributeInfo("name", "java.lang.String",
087 "The name of this Logger.", true, false, false));
088
089 _attributes.add(new MBeanAttributeInfo("priority", "java.lang.String",
090 "The priority of this logger.", true, true, false));
091
092 MBeanParameterInfo[] params = new MBeanParameterInfo[2];
093 params[0] = new MBeanParameterInfo("class_name", "java.lang.String",
094 "add an appender to this logger");
095 params[1] = new MBeanParameterInfo("appender_name", "java.lang.String",
096 "name of the appender");
097
098 _operations[0] = new MBeanOperationInfo("addAppender", "addAppender(): add an appender",
099 params, "void", MBeanOperationInfo.ACTION);
100 }
101
102 protected Logger getLogger()
103 {
104 return _logger;
105 }
106
107 public MBeanInfo getMBeanInfo()
108 {
109 MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[_attributes.size()];
110 _attributes.toArray(attribs);
111
112 MBeanInfo mb = new MBeanInfo(_className, _description, attribs, _constructors, _operations,
113 new MBeanNotificationInfo[0]);
114 // cat.debug("getMBeanInfo exit.");
115 return mb;
116 }
117
118 public Object invoke(String operationName, Object params[], String signature[])
119 throws MBeanException, ReflectionException
120 {
121
122 if (operationName.equals("addAppender"))
123 {
124 addAppender((String) params[0], (String) params[1]);
125 return "Hello world.";
126 }
127
128 return null;
129 }
130
131 public Object getAttribute(String attributeName) throws AttributeNotFoundException,
132 MBeanException, ReflectionException
133 {
134
135 // Check attributeName is not null to avoid NullPointerException later on
136 if (attributeName == null)
137 {
138 throw new RuntimeOperationsException(new IllegalArgumentException(
139 "Attribute name cannot be null"), "Cannot invoke a getter of " + _className
140 + " with null attribute name");
141 }
142
143 // Check for a recognized attributeName and call the corresponding getter
144 if (attributeName.equals("name"))
145 {
146 return _logger.getName();
147 }
148 else if (attributeName.equals("priority"))
149 {
150 Level l = _logger.getLevel();
151 if (l == null)
152 return null;
153
154 return l.toString();
155 }
156 else if (attributeName.startsWith("appender="))
157 {
158 try
159 {
160 return new ObjectName("log4j:" + attributeName);
161 }
162 catch (Exception e)
163 {
164 _log.error("Could not create ObjectName" + attributeName);
165 }
166 }
167
168 // If attributeName has not been recognized throw an AttributeNotFoundException
169 throw (new AttributeNotFoundException("Cannot find " + attributeName + " attribute in "
170 + _className));
171
172 }
173
174 void addAppender(String appenderClass, String appenderName)
175 {
176 _log.debug("addAppender called with " + appenderClass + ", " + appenderName);
177 Appender appender = (Appender) OptionConverter.instantiateByClassName(
178 appenderClass,
179 org.apache.log4j.Appender.class,
180 null);
181 appender.setName(appenderName);
182 _logger.addAppender(appender);
183
184 }
185
186 public void setAttribute(Attribute attribute) throws AttributeNotFoundException,
187 InvalidAttributeValueException, MBeanException, ReflectionException
188 {
189
190 // Check attribute is not null to avoid NullPointerException later on
191 if (attribute == null)
192 {
193 throw new RuntimeOperationsException(new IllegalArgumentException(
194 "Attribute cannot be null"), "Cannot invoke a setter of " + _className
195 + " with null attribute");
196 }
197 String name = attribute.getName();
198 Object value = attribute.getValue();
199
200 if (name == null)
201 {
202 throw new RuntimeOperationsException(new IllegalArgumentException(
203 "Attribute name cannot be null"), "Cannot invoke the setter of " + _className
204 + " with null attribute name");
205 }
206
207 if (name.equals("priority"))
208 {
209 if (value instanceof String)
210 {
211 String s = (String) value;
212 Level p = _logger.getLevel();
213 if (s.equalsIgnoreCase("NULL"))
214 {
215 p = null;
216 }
217 else
218 {
219 p = OptionConverter.toLevel(s, p);
220 }
221 _logger.setLevel(p);
222 }
223 }
224 else
225 {
226 throw (new AttributeNotFoundException("Attribute " + name + " not found in "
227 + this.getClass().getName()));
228 }
229 }
230
231 void appenderMBeanRegistration()
232 {
233 Enumeration enumeration = _logger.getAllAppenders();
234 while (enumeration.hasMoreElements())
235 {
236 Appender appender = (Appender) enumeration.nextElement();
237 registerAppenderMBean(appender);
238 }
239 }
240
241 /**
242 * Register a mbean for an appender.
243 *
244 * @param appender
245 */
246 void registerAppenderMBean(Appender appender)
247 {
248 String name = appender.getName();
249 _log.debug("Adding AppenderMBean for appender named " + name);
250 ObjectName objectName = null;
251 try
252 {
253 objectName = new ObjectName("log4j", "appender", name);
254 // register appender as mbean if not already existing
255 if (!getMBeanServer().isRegistered(objectName))
256 {
257 AppenderDynamicMBean appenderMBean = new AppenderDynamicMBean(appender);
258 getMBeanServer().registerMBean(appenderMBean, objectName);
259
260 _attributes.add(new MBeanAttributeInfo("appender=" + name,
261 "javax.management.ObjectName", "The " + name + " appender.", true, true,
262 false));
263 }
264
265 }
266 catch (Exception e)
267 {
268 _log.error("Could not add appenderMBean for [" + name + "].", e);
269 }
270 }
271
272 public void postRegister(java.lang.Boolean registrationDone)
273 {
274 appenderMBeanRegistration();
275 }
276 }