001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.log4j.jmx; 019 020 021import org.apache.log4j.Appender; 022import org.apache.log4j.Category; 023import org.apache.log4j.Level; 024import org.apache.log4j.LogManager; 025import org.apache.log4j.Logger; 026import org.apache.log4j.helpers.OptionConverter; 027import org.apache.log4j.spi.HierarchyEventListener; 028import org.apache.log4j.spi.LoggerRepository; 029 030import javax.management.Attribute; 031import javax.management.AttributeNotFoundException; 032import javax.management.InvalidAttributeValueException; 033import javax.management.JMException; 034import javax.management.ListenerNotFoundException; 035import javax.management.MBeanAttributeInfo; 036import javax.management.MBeanConstructorInfo; 037import javax.management.MBeanException; 038import javax.management.MBeanInfo; 039import javax.management.MBeanNotificationInfo; 040import javax.management.MBeanOperationInfo; 041import javax.management.MBeanParameterInfo; 042import javax.management.Notification; 043import javax.management.NotificationBroadcaster; 044import javax.management.NotificationBroadcasterSupport; 045import javax.management.NotificationFilter; 046import javax.management.NotificationFilterSupport; 047import javax.management.NotificationListener; 048import javax.management.ObjectName; 049import javax.management.ReflectionException; 050import javax.management.RuntimeOperationsException; 051import java.lang.reflect.Constructor; 052import java.util.Vector; 053 054public class HierarchyDynamicMBean extends AbstractDynamicMBean 055 implements HierarchyEventListener, 056 NotificationBroadcaster { 057 058 static final String ADD_APPENDER = "addAppender."; 059 static final String THRESHOLD = "threshold"; 060 061 private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1]; 062 private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1]; 063 064 private Vector vAttributes = new Vector(); 065 private String dClassName = this.getClass().getName(); 066 private String dDescription = 067 "This MBean acts as a management facade for org.apache.log4j.Hierarchy."; 068 069 private NotificationBroadcasterSupport nbs = new NotificationBroadcasterSupport(); 070 071 072 private LoggerRepository hierarchy; 073 074 private static Logger log = Logger.getLogger(HierarchyDynamicMBean.class); 075 076 public HierarchyDynamicMBean() { 077 hierarchy = LogManager.getLoggerRepository(); 078 buildDynamicMBeanInfo(); 079 } 080 081 private 082 void buildDynamicMBeanInfo() { 083 Constructor[] constructors = this.getClass().getConstructors(); 084 dConstructors[0] = new MBeanConstructorInfo( 085 "HierarchyDynamicMBean(): Constructs a HierarchyDynamicMBean instance", 086 constructors[0]); 087 088 vAttributes.add(new MBeanAttributeInfo(THRESHOLD, 089 "java.lang.String", 090 "The \"threshold\" state of the hiearchy.", 091 true, 092 true, 093 false)); 094 095 MBeanParameterInfo[] params = new MBeanParameterInfo[1]; 096 params[0] = new MBeanParameterInfo("name", "java.lang.String", 097 "Create a logger MBean" ); 098 dOperations[0] = new MBeanOperationInfo("addLoggerMBean", 099 "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}