View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2010 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.services.monitoring.jmx;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  
22  import javax.management.Attribute;
23  import javax.management.AttributeList;
24  import javax.management.AttributeNotFoundException;
25  import javax.management.DynamicMBean;
26  import javax.management.InvalidAttributeValueException;
27  import javax.management.MBeanException;
28  import javax.management.MBeanInfo;
29  import javax.management.MBeanNotificationInfo;
30  import javax.management.MBeanOperationInfo;
31  import javax.management.ReflectionException;
32  import javax.management.openmbean.CompositeData;
33  import javax.management.openmbean.CompositeDataSupport;
34  import javax.management.openmbean.CompositeType;
35  import javax.management.openmbean.OpenDataException;
36  import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
37  import javax.management.openmbean.OpenMBeanConstructorInfoSupport;
38  import javax.management.openmbean.OpenMBeanInfoSupport;
39  import javax.management.openmbean.OpenMBeanOperationInfoSupport;
40  import javax.management.openmbean.OpenMBeanParameterInfoSupport;
41  import javax.management.openmbean.OpenType;
42  import javax.management.openmbean.SimpleType;
43  import javax.management.openmbean.TabularData;
44  import javax.management.openmbean.TabularDataSupport;
45  import javax.management.openmbean.TabularType;
46  
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  /**
51   * 
52   * Provides functionality to investigate the ClassLoaders and Classpaths in use.
53   *
54   * @svnLink $Revision: 4253 $;$Date: 2010-12-21 11:08:04 +0100 (Di, 21. Dez 2010) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/jmx/src/main/java/ch/elca/el4j/services/monitoring/jmx/ClassLoaderMBean.java $
55   *
56   * @author Simon Stelling (SST)
57   */
58  public class ClassLoaderMBean implements DynamicMBean {
59  
60  	/**
61  	 * private logger.
62  	 */
63  	private static Logger s_logger = LoggerFactory.getLogger(ClassLoaderMBean.class);
64  	
65  	/**
66  	 * type of the return value of inspectClass(). initialized in static block.
67  	 */
68  	private static CompositeType s_propertiesType = null;
69  
70  	/**
71  	 * type of the return value of getClassLoadersComplexType(). initialized in static block.
72  	 */
73  	private static TabularType s_tabularType = null;
74  	
75  	/**
76  	 * type of a tabular data row. initialized in static block.
77  	 */
78  	private static CompositeType s_itemType = null;
79  	
80  	/**
81  	 * property identifier for the classloader hierarchy.
82  	 */
83  	private static final String CLASSLOADER_HIERARCHY = "classloader hierarchy";
84  	
85  	/**
86  	 * property identifier for the classpath.
87  	 */
88  	private static final String CLASSPATH = "classpath";
89  	
90  	/**
91  	 * property identifier for the classpath found using the investigated class' classloader.
92  	 */
93  	private static final String CLASSPATH_USING_CLASSLOADER = "classpath using investigated class' ClassLoader";
94  	
95  	/**
96  	 * Lists all property names.
97  	 */
98  	private static String[] s_names 
99  		= {CLASSLOADER_HIERARCHY, CLASSPATH, CLASSPATH_USING_CLASSLOADER };
100 	
101 	/**
102 	 * initialized in static block.
103 	 */
104 	@SuppressWarnings("unchecked")
105 	private static OpenType[] s_types = null; 
106 	
107 	/**
108 	 * Lists all property descriptions.
109 	 */
110 	private static String[] s_descriptions 
111 		= {CLASSLOADER_HIERARCHY, CLASSPATH, CLASSPATH_USING_CLASSLOADER };
112 	
113 	/**
114 	 * OMBInfo used by JMX to interpret the return value of inspectClass() correctly.
115 	 */
116 	private OpenMBeanInfoSupport ombInfo;
117 	
118 	/**
119 	 * Initialzies s_itemType.
120 	 */
121 	static {
122 		try {
123 			
124 			s_itemType = new CompositeType("classloader", "classloader name", new String[] {"classloader"}, 
125 				new String[] {"classloader"}, new OpenType[] {SimpleType.STRING});
126 			s_tabularType = new TabularType(
127 				"classloader", "the classloader's name", s_itemType, new String[] {"classloader"});
128 			
129 			s_types = new OpenType[] {s_tabularType, SimpleType.STRING, SimpleType.STRING };
130 			
131 			s_propertiesType = new CompositeType(
132 				"properties", "a list of classloader-specific property", s_names, s_descriptions, s_types);
133 			
134 		} catch (OpenDataException e) {
135 			throw new RuntimeException(e);
136 		}
137 		
138 	}
139 	
140 	/**
141 	 * Default Constructor.
142 	 */
143 	public ClassLoaderMBean() {
144 		// build OMBInfo
145 		OpenMBeanAttributeInfoSupport[] attributes = new OpenMBeanAttributeInfoSupport[0]; 
146 		OpenMBeanConstructorInfoSupport[] constructors = new OpenMBeanConstructorInfoSupport[1]; 
147 		OpenMBeanOperationInfoSupport[] operations = new OpenMBeanOperationInfoSupport[1];
148 		MBeanNotificationInfo[] notifications = new MBeanNotificationInfo[0];
149 		
150 		constructors[0] = new OpenMBeanConstructorInfoSupport("ClassLoaderMBean", "constructs a ClassLoaderMBean", 
151 			new OpenMBeanParameterInfoSupport[0]);
152 		
153 		
154 		OpenMBeanParameterInfoSupport[] params = new OpenMBeanParameterInfoSupport[1]; 
155 		params[0] = new OpenMBeanParameterInfoSupport(
156 			"classname", "the name of the class to investigate", SimpleType.STRING);
157 		operations[0] = new OpenMBeanOperationInfoSupport(
158 			"inspectClass", "inspects the given class", params, s_propertiesType, MBeanOperationInfo.INFO);
159 		ombInfo = new OpenMBeanInfoSupport(this.getClass().getName(), 
160 			"ClassLoader Inspector", attributes, constructors, operations, notifications);
161 	}
162 	
163 	/**
164 	 * Method available via JMX interface.
165 	 * <p>
166 	 * <em>Notes:</em>
167 	 * As this method takes a class<b>name</b>, it has to load the class object of the class first.
168 	 * This is done by invoking the ClassLoaderMBean's ClassLoader and asking it to load the the
169 	 * class for the given name. If you are experiencing ClassLoader issues and the class where you
170 	 * observe them was not loaded by the same classloader hierarchy as the ClassLoaderMBean, the
171 	 * information returned by this method is probably not of much use to you.
172 	 * 
173 	 * @param className the name of the class to investigate
174 	 * @return a CompositeData object containing all investigation information.
175 	 * @throws ClassNotFoundException 
176 	 */
177 	private CompositeData inspectClass(String className) throws ClassNotFoundException {
178 		ClassLoaderInvestigator helper = new ClassLoaderInvestigator(className);
179 		
180 		Map<String, Object> items = new HashMap<String, Object>();
181 		
182 		items.put(CLASSLOADER_HIERARCHY, getClassLoadersComplexType(helper.getClassLoaderHierarchy()));
183 		items.put(CLASSPATH, helper.getClassPathForInspectedClass());
184 		items.put(CLASSPATH_USING_CLASSLOADER, helper.getClassPathForInspectedClassUsingItsLoader());
185 		
186 		try {
187 			return new CompositeDataSupport(s_propertiesType, items);
188 		} catch (OpenDataException e) {
189 			throw new RuntimeException(e);
190 		}
191 	}
192 
193 	/**
194 	 * @param classLoaderHierarchy the string array containing all classloader names
195 	 * @return the TabularData containing the same information
196 	 */
197 	private TabularData getClassLoadersComplexType(String[] classLoaderHierarchy) {
198 		TabularDataSupport t = new TabularDataSupport(s_tabularType);
199 		for (String classloader : classLoaderHierarchy) {
200 			Map<String, String> item = new HashMap<String, String>();
201 			item.put("classloader", classloader);
202 			try {
203 				t.put(new CompositeDataSupport(s_itemType, item));
204 			} catch (OpenDataException e) {
205 				// won't happen
206 				s_logger.error("Unexpected OpenDataException: ", e);
207 			}
208 		}
209 		
210 		return t;
211 	}
212 
213 	/**
214 	 * {@inheritDoc}
215 	 */
216 	@Override
217 	public Object getAttribute(String attribute) 
218 		throws AttributeNotFoundException, MBeanException, ReflectionException {
219 		return null;
220 	}
221 
222 	/**
223 	 * {@inheritDoc}
224 	 */
225 	@Override
226 	public AttributeList getAttributes(String[] attributes) {
227 		return null;
228 	}
229 	
230 	/**
231 	 * {@inheritDoc}
232 	 */
233 	@Override
234 	public MBeanInfo getMBeanInfo() {
235 		return ombInfo;
236 	}
237 
238 	/**
239 	 * {@inheritDoc}
240 	 */
241 	@Override
242 	public Object invoke(String actionName, Object[] params, String[] signature) throws MBeanException,
243 		ReflectionException {
244 		try {
245 			if ("inspectClass".equals(actionName)) {
246 				if ((params.length == 1 && params[0] instanceof String)) {
247 					try {
248 						return inspectClass((String) params[0]);
249 					} catch (ClassNotFoundException e) {
250 						s_logger.error("exception occurred: ", e);
251 						throw new MBeanException(e);
252 					}
253 				}
254 			}
255 			throw new RuntimeException("method not found");
256 		} catch (NullPointerException e) {
257 			s_logger.error("exception occurred: ", e);
258 			throw e;
259 		}
260 	}
261 
262 	/**
263 	 * {@inheritDoc}
264 	 */
265 	@Override
266 	public void setAttribute(Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException,
267 		MBeanException, ReflectionException {
268 	}
269 
270 	/**
271 	 * {@inheritDoc}
272 	 */
273 	@Override
274 	public AttributeList setAttributes(AttributeList attributes) {
275 		return null;
276 	}
277 	
278 }