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 020import java.lang.reflect.Constructor; 021import org.apache.log4j.Logger; 022import org.apache.log4j.Level; 023import org.apache.log4j.Layout; 024import org.apache.log4j.helpers.OptionConverter; 025import org.apache.log4j.spi.OptionHandler; 026 027import java.util.Vector; 028import java.util.Hashtable; 029import java.lang.reflect.Method; 030import java.lang.reflect.InvocationTargetException; 031import javax.management.MBeanAttributeInfo; 032import javax.management.MBeanConstructorInfo; 033import javax.management.MBeanNotificationInfo; 034import javax.management.MBeanInfo; 035import javax.management.Attribute; 036 037import javax.management.MBeanException; 038import javax.management.AttributeNotFoundException; 039import javax.management.RuntimeOperationsException; 040import javax.management.ReflectionException; 041import javax.management.InvalidAttributeValueException; 042import javax.management.MBeanOperationInfo; 043import javax.management.MBeanParameterInfo; 044 045import java.beans.Introspector; 046import java.beans.BeanInfo; 047import java.beans.PropertyDescriptor; 048import java.beans.IntrospectionException; 049import java.io.InterruptedIOException; 050 051public class LayoutDynamicMBean extends AbstractDynamicMBean { 052 053 private MBeanConstructorInfo[] dConstructors = new MBeanConstructorInfo[1]; 054 private Vector dAttributes = new Vector(); 055 private String dClassName = this.getClass().getName(); 056 057 private Hashtable dynamicProps = new Hashtable(5); 058 private MBeanOperationInfo[] dOperations = new MBeanOperationInfo[1]; 059 private String dDescription = 060 "This MBean acts as a management facade for log4j layouts."; 061 062 // This category instance is for logging. 063 private static Logger cat = Logger.getLogger(LayoutDynamicMBean.class); 064 065 // We wrap this layout instance. 066 private Layout layout; 067 068 public LayoutDynamicMBean(Layout layout) throws IntrospectionException { 069 this.layout = layout; 070 buildDynamicMBeanInfo(); 071 } 072 073 private 074 void buildDynamicMBeanInfo() throws IntrospectionException { 075 Constructor[] constructors = this.getClass().getConstructors(); 076 dConstructors[0] = new MBeanConstructorInfo( 077 "LayoutDynamicMBean(): Constructs a LayoutDynamicMBean instance", 078 constructors[0]); 079 080 081 BeanInfo bi = Introspector.getBeanInfo(layout.getClass()); 082 PropertyDescriptor[] pd = bi.getPropertyDescriptors(); 083 084 int size = pd.length; 085 086 for(int i = 0; i < size; i++) { 087 String name = pd[i].getName(); 088 Method readMethod = pd[i].getReadMethod(); 089 Method writeMethod = pd[i].getWriteMethod(); 090 if(readMethod != null) { 091 Class returnClass = readMethod.getReturnType(); 092 if(isSupportedType(returnClass)) { 093 String returnClassName; 094 if(returnClass.isAssignableFrom(Level.class)) { 095 returnClassName = "java.lang.String"; 096 } else { 097 returnClassName = returnClass.getName(); 098 } 099 100 dAttributes.add(new MBeanAttributeInfo(name, 101 returnClassName, 102 "Dynamic", 103 true, 104 writeMethod != null, 105 false)); 106 dynamicProps.put(name, new MethodUnion(readMethod, writeMethod)); 107 } 108 } 109 } 110 111 MBeanParameterInfo[] params = new MBeanParameterInfo[0]; 112 113 dOperations[0] = new MBeanOperationInfo("activateOptions", 114 "activateOptions(): add an layout", 115 params, 116 "void", 117 MBeanOperationInfo.ACTION); 118 } 119 120 private 121 boolean isSupportedType(Class clazz) { 122 if(clazz.isPrimitive()) { 123 return true; 124 } 125 126 if(clazz == String.class) { 127 return true; 128 } 129 if(clazz.isAssignableFrom(Level.class)) { 130 return true; 131 } 132 133 return false; 134 } 135 136 137 138 public 139 MBeanInfo getMBeanInfo() { 140 cat.debug("getMBeanInfo called."); 141 142 MBeanAttributeInfo[] attribs = new MBeanAttributeInfo[dAttributes.size()]; 143 dAttributes.toArray(attribs); 144 145 return new MBeanInfo(dClassName, 146 dDescription, 147 attribs, 148 dConstructors, 149 dOperations, 150 new MBeanNotificationInfo[0]); 151 } 152 153 public 154 Object invoke(String operationName, Object params[], String signature[]) 155 throws MBeanException, 156 ReflectionException { 157 158 if(operationName.equals("activateOptions") && 159 layout instanceof OptionHandler) { 160 OptionHandler oh = (OptionHandler) layout; 161 oh.activateOptions(); 162 return "Options activated."; 163 } 164 return null; 165 } 166 167 protected 168 Logger getLogger() { 169 return cat; 170 } 171 172 173 public 174 Object getAttribute(String attributeName) throws AttributeNotFoundException, 175 MBeanException, 176 ReflectionException { 177 178 // Check attributeName is not null to avoid NullPointerException later on 179 if (attributeName == null) { 180 throw new RuntimeOperationsException(new IllegalArgumentException( 181 "Attribute name cannot be null"), 182 "Cannot invoke a getter of " + dClassName + " with null attribute name"); 183 } 184 185 186 MethodUnion mu = (MethodUnion) dynamicProps.get(attributeName); 187 188 cat.debug("----name="+attributeName+", mu="+mu); 189 190 if(mu != null && mu.readMethod != null) { 191 try { 192 return mu.readMethod.invoke(layout, null); 193 } catch(InvocationTargetException e) { 194 if (e.getTargetException() instanceof InterruptedException 195 || e.getTargetException() instanceof InterruptedIOException) { 196 Thread.currentThread().interrupt(); 197 } 198 return null; 199 } catch(IllegalAccessException e) { 200 return null; 201 } catch(RuntimeException e) { 202 return null; 203 } 204 } 205 206 207 208 // If attributeName has not been recognized throw an AttributeNotFoundException 209 throw(new AttributeNotFoundException("Cannot find " + attributeName + 210 " attribute in " + dClassName)); 211 212 } 213 214 215 public 216 void setAttribute(Attribute attribute) throws AttributeNotFoundException, 217 InvalidAttributeValueException, 218 MBeanException, 219 ReflectionException { 220 221 // Check attribute is not null to avoid NullPointerException later on 222 if (attribute == null) { 223 throw new RuntimeOperationsException( 224 new IllegalArgumentException("Attribute cannot be null"), 225 "Cannot invoke a setter of " + dClassName + 226 " with null attribute"); 227 } 228 String name = attribute.getName(); 229 Object value = attribute.getValue(); 230 231 if (name == null) { 232 throw new RuntimeOperationsException( 233 new IllegalArgumentException("Attribute name cannot be null"), 234 "Cannot invoke the setter of "+dClassName+ 235 " with null attribute name"); 236 } 237 238 239 240 MethodUnion mu = (MethodUnion) dynamicProps.get(name); 241 242 if(mu != null && mu.writeMethod != null) { 243 Object[] o = new Object[1]; 244 245 Class[] params = mu.writeMethod.getParameterTypes(); 246 if(params[0] == org.apache.log4j.Priority.class) { 247 value = OptionConverter.toLevel((String) value, 248 (Level) getAttribute(name)); 249 } 250 o[0] = value; 251 252 try { 253 mu.writeMethod.invoke(layout, o); 254 255 } catch(InvocationTargetException e) { 256 if (e.getTargetException() instanceof InterruptedException 257 || e.getTargetException() instanceof InterruptedIOException) { 258 Thread.currentThread().interrupt(); 259 } 260 cat.error("FIXME", e); 261 } catch(IllegalAccessException e) { 262 cat.error("FIXME", e); 263 } catch(RuntimeException e) { 264 cat.error("FIXME", e); 265 } 266 } else { 267 throw(new AttributeNotFoundException("Attribute " + name + 268 " not found in " + 269 this.getClass().getName())); 270 } 271 } 272} 273 274