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) 2006 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.net.MalformedURLException;
20  import java.net.URL;
21  import java.util.Enumeration;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.LinkedList;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  
29  import javax.management.InstanceAlreadyExistsException;
30  import javax.management.MBeanRegistrationException;
31  import javax.management.MBeanServer;
32  import javax.management.MalformedObjectNameException;
33  import javax.management.NotCompliantMBeanException;
34  import javax.management.ObjectName;
35  
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  //Checkstyle: UseLogger off
39  import org.apache.log4j.Appender;
40  import org.apache.log4j.Level;
41  import org.apache.log4j.LogManager;
42  import org.apache.log4j.helpers.Loader;
43  import org.apache.log4j.helpers.OptionConverter;
44  //Checkstyle: UseLogger on
45  import org.springframework.beans.factory.BeanFactory;
46  import org.springframework.context.ApplicationContext;
47  import org.springframework.context.support.StaticApplicationContext;
48  
49  import ch.elca.el4j.core.exceptions.BaseException;
50  import ch.elca.el4j.core.exceptions.BaseRTException;
51  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
52  
53  /**
54   * The logging proxy class, for setting logging properties via JMX.
55   *
56   * @svnLink $Revision: 4093 $;$Date: 2010-01-15 14:26:34 +0100 (Fr, 15. Jan 2010) $;$Author: jonasha $;$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/Log4jConfig.java $
57   *
58   * @author Rashid Waraich (RWA)
59   */
60  public class Log4jConfig implements Log4jConfigMBean {
61  	/**
62  	 * The domain of the Logger bean proxy as it will be registered at the MBean
63  	 * Server.
64  	 */
65  	public static final String JVM_DOMAIN = "JVM";
66  
67  	/**
68  	 * The name of the 'log4jJmxLoader' bean.
69  	 */
70  	public static final String LOG4J_JMX_LOADER = "log4jJmxLoader";
71  	
72  	/**
73  	 * The counter on the number of JVMs.
74  	 */
75  	private static int s_counter = 1;
76  	
77  	/**
78  	 * Private logger of this class.
79  	 */
80  	private static Logger s_logger = LoggerFactory.getLogger(SpringBeanMB.class);
81  
82  	/**
83  	 * The Application Context where this Spring Bean is registered at.
84  	 */
85  	protected ApplicationContext m_applicationContext;
86  
87  	/**
88  	 * The Application Context proxy for the real Application Context.
89  	 */
90  	protected ApplicationContextMB m_applicationContextMB;
91  
92  	/**
93  	 * The class name of this class.
94  	 */
95  	protected Class m_class;
96  
97  	/**
98  	 * The Bean Factory belonging to the referenced Application Context.
99  	 */
100 	protected BeanFactory m_beanFactory;
101 
102 	/**
103 	 * The instance counter of this object.
104 	 */
105 	private int m_instanceCounter;
106 	
107 	/**
108 	 * The MBean Server where this Spring Bean is registered at.
109 	 */
110 	private MBeanServer m_mBeanServer;
111 
112 	/**
113 	 * The bean definition name of this Spring Bean.
114 	 */
115 	private String m_name;
116 
117 	/**
118 	 * The object name of this Spring Bean proxy.
119 	 */
120 	private ObjectName m_objectName;
121 
122 	/**
123 	 * Contains all appenders, which are currently loaded.
124 	 */
125 	private Map m_appendersPool;
126 
127 	/**
128 	 * All logging level changes are stored here.
129 	 */
130 	private Map<String, String> m_loggingLevelCache
131 		= new HashMap<String, String>();
132 
133 	/**
134 	 * True, if the RootLevel was changed through the setRootLoggerLevel method.
135 	 */
136 	private boolean m_hasRootLevelChanged = false;
137 
138 	/**
139 	 * Constructor.
140 	 *
141 	 * @param name
142 	 *            The bean definition name of this Spring Bean
143 	 * @param acMB
144 	 *            The Application Context proxy
145 	 * @param ac
146 	 *            The real Application Context
147 	 * @param beanFactory
148 	 *            The Bean Factory belonging to this Application Context
149 	 * @param mBeanServer
150 	 *            The MBean Server where this Spring Bean is registered at
151 	 */
152 	public Log4jConfig(String name, ApplicationContextMB acMB,
153 		ApplicationContext ac, BeanFactory beanFactory,
154 		MBeanServer mBeanServer) {
155 
156 		this.m_name = name;
157 		this.m_applicationContextMB = acMB;
158 		this.m_applicationContext = ac;
159 		this.m_mBeanServer = mBeanServer;
160 		this.m_beanFactory = beanFactory;
161 		this.m_class = this.getClass();
162 
163 		StaticApplicationContext appContext = new StaticApplicationContext(
164 			m_applicationContext);
165 
166 		// register the Log4jConfig bean with the spring appContext
167 		appContext.getBeanFactory().registerSingleton(m_name, this);
168 
169 		// read-out the appenders list from the DeafultLog4jJmxLoader bean.
170 		setAppendersPool(((Log4jJmxLoader) appContext
171 			.getBean(LOG4J_JMX_LOADER)).getAppenders());
172 	}
173 
174 	/**
175 	 * {@inheritDoc}
176 	 */
177 	public void init() throws BaseException {
178 		
179 		// Set the instanceCounter.
180 		setInstanceCounter();
181 		
182 		// Set the object name of this object.
183 		setObjectName();
184 
185 		// Register the Spring Bean at the MBean Server.
186 		registerSpringBean();
187 	}
188 
189 	/**
190 	 * Register this SpringBean at the MBean Server.
191 	 *
192 	 * @throws BaseException
193 	 *             in case the registration at the MBean Server failed
194 	 */
195 	protected void registerSpringBean() throws BaseException {
196 
197 		if (getObjectName() == null) {
198 			String message = "The object name of the SpringBeanMB '"
199 				+ this.toString() + "' should not be null.";
200 			s_logger.error(message);
201 			throw new BaseRTException(message, (Object[]) null);
202 		} else {
203 			try {
204 				m_mBeanServer.registerMBean(this, getObjectName());
205 			} catch (InstanceAlreadyExistsException e) {
206 				String message = "The MBean is already under the "
207 					+ "control of the MBean server.";
208 				s_logger.error(message);
209 				throw new BaseException(message, e);
210 			} catch (MBeanRegistrationException e) {
211 				String message = "The MBean will not be registered.";
212 				s_logger.error(message);
213 				throw new BaseException(message, e);
214 			} catch (NotCompliantMBeanException e) {
215 				String message = "This object is not a JMX compliant"
216 					+ " MBean.";
217 				s_logger.error(message);
218 				throw new BaseException(message, e);
219 			}
220 		}
221 	}
222 
223 	/**
224 	 * Getter method for the objectName member variable.
225 	 *
226 	 * @return The objectName
227 	 */
228 	public ObjectName getObjectName() {
229 		return m_objectName;
230 	}
231 
232 	/**
233 	 * Sets the objectName to of this object.
234 	 */
235 	public void setObjectName() {
236 
237 		String name = JVM_DOMAIN + ":name=log4jConfig " + getInstanceCounter();
238 		// String name = JVM_DOMAIN + ":name="+ getName() + " " +
239 		// getInstanceCounter();
240 
241 		try {
242 			m_objectName = new ObjectName(name);
243 		} catch (MalformedObjectNameException e) {
244 			CoreNotificationHelper
245 				.notifyMisconfiguration("The string passed as a parameter"
246 					+ "does not have the right format.");
247 		}
248 	}
249 
250 	/**
251 	 * {@inheritDoc}
252 	 */
253 	public String getName() {
254 		return m_name;
255 	}
256 
257 	/**
258 	 * @param appenders
259 	 *            The appeenders list.
260 	 */
261 	public void setAppendersPool(HashMap appenders) {
262 		this.m_appendersPool = appenders;
263 	}
264 
265 	/**
266 	 * {@inheritDoc}
267 	 */
268 	public void addAppender(String category, String appenderName) {
269 		LogManager.getLogger(category).addAppender(
270 			(Appender) m_appendersPool.get(appenderName));
271 	}
272 
273 	/**
274 	 * {@inheritDoc}
275 	 */
276 	public void removeAppender(String category, String appenderName) {
277 		LogManager.getLogger(category).removeAppender(
278 			(Appender) m_appendersPool.get(appenderName));
279 	}
280 
281 	/**
282 	 * {@inheritDoc}
283 	 */
284 	public String[] getAvailableAppendersList() {
285 		String[] result = null;
286 		Set appKeySet = m_appendersPool.keySet();
287 		Iterator i = appKeySet.iterator();
288 		String appKey;
289 		LinkedList<String> queue = new LinkedList<String>();
290 		while (i.hasNext()) {
291 			appKey = (String) i.next();
292 			queue.add("appenderName=" + appKey + "; appenderObject="
293 				+ m_appendersPool.get(appKey).toString());
294 		}
295 
296 		Object[] array = queue.toArray();
297 		result = new String[array.length];
298 		for (int j = 0; j < array.length; j++) {
299 			result[j] = array[j].toString();
300 		}
301 
302 		return result;
303 	}
304 
305 	/**
306 	 * {@inheritDoc}
307 	 */
308 	public void changeLogLevel(String category, String level) {
309 		LogManager.getLogger(category).setLevel(Level.toLevel(level));
310 		m_loggingLevelCache.put(category, level);
311 	}
312 
313 	/**
314 	 * {@inheritDoc}
315 	 */
316 	public Level showLogLevel(String category) {
317 		return LogManager.getLogger(category).getLevel();
318 	}
319 
320 	/**
321 	 * {@inheritDoc}
322 	 */
323 	public Appender[] showAppenders(String category) {
324 		Enumeration enumerator = LogManager.getLogger(category)
325 			.getAllAppenders();
326 
327 		List<Appender> queue = new LinkedList<Appender>();
328 
329 		while (enumerator.hasMoreElements()) {
330 			queue.add((Appender) enumerator.nextElement());
331 		}
332 	 
333 		if (queue.size() > 0) {
334 			return queue.toArray(new Appender[queue.size()]);
335 		} else {
336 			return null;
337 		}
338 	}
339 
340 	/**
341 	 * {@inheritDoc}
342 	 */
343 	public void setRootLoggerLevel(String level) {
344 		LogManager.getRootLogger().setLevel(Level.toLevel(level));
345 		m_hasRootLevelChanged = true;
346 	}
347 
348 	/**
349 	 * {@inheritDoc}
350 	 */
351 	public String getRootLoggerLevel() {
352 		return LogManager.getRootLogger().getLevel().toString();
353 	}
354 
355 	/**
356 	 * {@inheritDoc}
357 	 */
358 	public String showLogLevelCache() {
359 		String result = "";
360 
361 		Iterator iter = m_loggingLevelCache.keySet().iterator();
362 		String category;
363 		while (iter.hasNext()) {
364 			category = (String) iter.next();
365 			result = result.concat(JmxHtmlFormatter.getXmlLog4jConfigString(
366 				category, (String) m_loggingLevelCache.get(category)));
367 		}
368 
369 		if (m_hasRootLevelChanged) {
370 			result = result.concat(JmxHtmlFormatter
371 				.getXMLLog4jRootTag(getRootLoggerLevel()));
372 		}
373 
374 		return result;
375 	}
376 
377 	/**
378 	 * {@inheritDoc}
379 	 */
380 	public String getInitialConfigurationPath() {
381 		String defaultConfigurationFile = "log4j.properties";
382 		String defaultXMLConfigurationFile = "log4j.xml";
383 		String defaultConfigurationKey = "log4j.configuration";
384 		String defaultInitOverrideKey = "log4j.defaultInitOverride";
385 		URL url = null;
386 
387 		// Search for the properties file log4j.properties in the CLASSPATH.
388 		String override = OptionConverter.getSystemProperty(
389 			defaultInitOverrideKey, null);
390 
391 		// if there is no default init override, then get the resource
392 		// specified by the user or the default config file.
393 		if (override == null || "false".equalsIgnoreCase(override)) {
394 			String configurationOptionStr = OptionConverter.getSystemProperty(
395 				defaultConfigurationKey, null);
396 
397 			// if the user has not specified the log4j.configuration
398 			// property, we search first for the file "log4j.xml" and then
399 			// "log4j.properties"
400 			if (configurationOptionStr == null) {
401 				url = Loader.getResource(defaultXMLConfigurationFile);
402 				if (url == null) {
403 					url = Loader.getResource(defaultConfigurationFile);
404 				}
405 			} else {
406 				try {
407 					url = new URL(configurationOptionStr);
408 				} catch (MalformedURLException ex) {
409 					// so, resource is not a URL:
410 					// attempt to get the resource from the class path
411 					url = Loader.getResource(configurationOptionStr);
412 				}
413 			}
414 		}
415 		
416 		if (url != null) {
417 			return url.getPath();
418 		} else {
419 			return null;
420 		}
421 	}
422 	
423 	/**
424 	 * The getter method for the instanceCounter member.
425 	 *
426 	 * @return The instanceCounter member
427 	 */
428 	public int getInstanceCounter() {
429 		return m_instanceCounter;
430 	}
431 
432 	/**
433 	 * Save the class variable s_counter to an instance member and increment the
434 	 * class variable by 1.
435 	 *
436 	 */
437 	public void setInstanceCounter() {
438 
439 		synchronized (Log4jConfig.class) {
440 			m_instanceCounter = s_counter;
441 			s_counter++;
442 		}
443 
444 	}
445 }