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 }