Author: robbie Date: Sun Aug 16 20:32:47 2009 New Revision: 804765 URL: http://svn.apache.org/viewvc?rev=804765&view=rev Log: QPID-2051: Update startup scripts to disable the Log4J default initialisation process. Add QpidLog4JConfigurator that validates the XML file before allowing it to be applied. Alter startup behaviour to shut the broker down if the specified log4j XML file is present present but invalid. Uses the -Damqj.logging.level(defaults to info) with the log4j.properties file in the broker jar if the XML file is not found.
Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/log4j/xml/ qpid/trunk/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/ qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/xml/ qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java Modified: qpid/trunk/qpid/java/broker/bin/qpid-server qpid/trunk/qpid/java/broker/bin/qpid-server.bat (contents, props changed) qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java Modified: qpid/trunk/qpid/java/broker/bin/qpid-server URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/bin/qpid-server?rev=804765&r1=804764&r2=804765&view=diff ============================================================================== --- qpid/trunk/qpid/java/broker/bin/qpid-server (original) +++ qpid/trunk/qpid/java/broker/bin/qpid-server Sun Aug 16 20:32:47 2009 @@ -23,6 +23,12 @@ export PATH=${PATH}:${QPID_HOME}/bin fi +if [ -z "$QPID_LOG4J_SETTINGS" ]; then + # Disable the Log4J default initialization process, allowing the broker to + # perform the configuration using etc/log4j.xml + QPID_LOG4J_SETTINGS="-Dlog4j.defaultInitOverride=true" +fi + # Set classpath to include Qpid jar with all required jars in manifest QPID_LIBS=$QPID_HOME/lib/qpid-all.jar:$QPID_HOME/lib/bdbstore-launch.jar @@ -34,6 +40,6 @@ QPID_CLASSPATH=$QPID_LIBS \ QPID_RUN_LOG=2 -QPID_OPTS="$QPID_OPTS -Damqj.read_write_pool_size=32" +QPID_OPTS="$QPID_OPTS $QPID_LOG4J_SETTINGS -Damqj.read_write_pool_size=32" . qpid-run org.apache.qpid.server.Main "$@" Modified: qpid/trunk/qpid/java/broker/bin/qpid-server.bat URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/bin/qpid-server.bat?rev=804765&r1=804764&r2=804765&view=diff ============================================================================== --- qpid/trunk/qpid/java/broker/bin/qpid-server.bat (original) +++ qpid/trunk/qpid/java/broker/bin/qpid-server.bat Sun Aug 16 20:32:47 2009 @@ -20,6 +20,9 @@ @echo off REM Script to run the Qpid Java Broker +rem stop the Log4J default initialisation, let the broker do it using etc/log4j.xml +if "%QPID_LOG4J_SETTINGS%" == "" set QPID_LOG4J_SETTINGS=-Dlog4j.defaultInitOverride=true + rem Guess QPID_HOME if not defined set CURRENT_DIR=%cd% if not "%QPID_HOME%" == "" goto gotHome @@ -194,7 +197,7 @@ rem user must enclose any value for QPID_OPTS in double quotes :runCommand set MODULE_JARS=%QPID_MODULE_JARS% -set COMMAND="%JAVA_HOME%\bin\java" %JAVA_VM% %JAVA_MEM% %JAVA_GC% %QPID_OPTS% %SYSTEM_PROPS% -cp "%CLASSPATH%;%MODULE_JARS%" org.apache.qpid.server.Main %QPID_ARGS% +set COMMAND="%JAVA_HOME%\bin\java" %JAVA_VM% %JAVA_MEM% %JAVA_GC% %QPID_OPTS% %QPID_LOG4J_SETTINGS% %SYSTEM_PROPS% -cp "%CLASSPATH%;%MODULE_JARS%" org.apache.qpid.server.Main %QPID_ARGS% if "%debug%" == "true" echo %CLASSPATH%;%LAUNCH_JAR%;%MODULE_JARS% if "%debug%" == "true" echo %COMMAND% Propchange: qpid/trunk/qpid/java/broker/bin/qpid-server.bat ('svn:executable' removed) Added: qpid/trunk/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java?rev=804765&view=auto ============================================================================== --- qpid/trunk/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java (added) +++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/log4j/xml/QpidLog4JConfigurator.java Sun Aug 16 20:32:47 2009 @@ -0,0 +1,250 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.log4j.xml; + +import java.io.File; +import java.io.IOException; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.management.LoggingManagementMBean; +import org.apache.qpid.server.logging.management.LoggingManagementMBean.QpidLog4JSaxErrorHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; + +/** + * Substitute for the Log4J XMLWatchdog (as used by DOMConfigurator.configureAndWatch) + * + * Extends the default behaviour with a strict parser check on the XML file before allowing the reconfiguration to proceed, + * ensuring that any parser error or warning prevents initiation of a configuration update by Log4J, which aborts mid-update + * upon fatal errors from the parser and proceeds in the event of 'regular' parser errors and warnings, in all cases allowing + * startup to proceed with whatever half-baked configuration then exists. + */ +public class QpidLog4JConfigurator +{ + //lock to protect access to the configuration file + private static final ReentrantLock LOCK = new ReentrantLock(); + private static Logger _logger; + + private QpidLog4JConfigurator() + { + //no instances + } + + public static void configure(String filename) throws IOException, ParserConfigurationException, + SAXException, IllegalLoggerLevelException + { + try + { + LOCK.lock(); + + strictlyParseXMLConfigFile(filename); + checkLoggerLevels(filename); + + DOMConfigurator.configure(filename); + } + finally + { + LOCK.unlock(); + } + } + + public static void configureAndWatch(String filename, long delay) throws IOException, ParserConfigurationException, + SAXException, IllegalLoggerLevelException + { + strictlyParseXMLConfigFile(filename); + checkLoggerLevels(filename); + + QpidLog4JXMLWatchdog watchdog = new QpidLog4JXMLWatchdog(filename); + watchdog.setDelay(delay); + watchdog.start(); + } + + private static void strictlyParseXMLConfigFile(String fileName) throws IOException, SAXException, + ParserConfigurationException + { + try + { + LOCK.lock(); + + //check file was specified, exists, and is readable + if(fileName == null) + { + throw new IOException("Provided log4j XML configuration filename was null"); + } + + File configFile = new File(fileName); + + if (!configFile.exists()) + { + throw new IOException("The log4j XML configuration file does not exist: " + fileName); + } + else if (!configFile.canRead()) + { + throw new IOException("The log4j XML configuration file is not readable: " + fileName); + } + + //parse it + DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder; + + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); + + docFactory.setValidating(true); + docBuilder = docFactory.newDocumentBuilder(); + docBuilder.setErrorHandler(errHandler); + docBuilder.setEntityResolver(new Log4jEntityResolver()); + docBuilder.parse(fileName); + } + finally + { + LOCK.unlock(); + } + } + + private static class QpidLog4JXMLWatchdog extends XMLWatchdog + { + public QpidLog4JXMLWatchdog(String filename) + { + super(filename); + } + + public void doOnChange() + { + try + { + LOCK.lock(); + + try + { + strictlyParseXMLConfigFile(filename); + } + catch (Exception e) + { + //logger will be instantiated following first configuration success, which has been pre-validated + //and so the null check should never actually be required. + if(_logger != null) + { + _logger.warn("Parsing the log4j XML configuration file generated errors/warnings. " + + "The new configuration was not applied. Correct the issues to prompt " + + "another update attempt: " + e.getMessage()); + } + return; + } + + try + { + checkLoggerLevels(filename); + } + catch (Exception e) + { + //logger will be instantiated following first configuration success, which has been pre-validated + //and so the null check should never actually be required. + if(_logger != null) + { + _logger.warn("Errors were found when validating the logger level values in the " + + "log4j XML configuration file. The new configuration was not applied. " + + "Correct the issues to prompt another update attempt: " + e.getMessage()); + } + return; + } + + //everything checked was ok, let the normal update process proceed + super.doOnChange(); + + //a configuration has now been applied, enable logging for future attempts + if(_logger == null) + { + _logger = Logger.getLogger(QpidLog4JConfigurator.class); + } + + _logger.info("Applied log4j configuration from: " + filename); + } + finally + { + LOCK.unlock(); + } + + } + } + + protected static void checkLoggerLevels(String filename) throws IllegalLoggerLevelException, IOException + { + //check that the logger levels specified in the XML are actually valid + + try + { + LOCK.lock(); + + Map<String, String> loggersLevels; + loggersLevels = LoggingManagementMBean.retrieveConfigFileLoggersLevels(filename); + + for (String loggerName : loggersLevels.keySet()) + { + String levelString = loggersLevels.get(loggerName); + checkLevel(loggerName,levelString); + } + + //check the root logger level + String rootLoggerlevelString = LoggingManagementMBean.retrieveConfigFileRootLoggerLevel(filename); + checkLevel("Root", rootLoggerlevelString); + } + finally + { + LOCK.unlock(); + } + } + + private static void checkLevel(String loggerName, String levelString) throws IllegalLoggerLevelException + { + if("null".equalsIgnoreCase(levelString) || "inherited".equalsIgnoreCase(levelString)) + { + //the string "null" signals to inherit from a parent logger + return; + } + + Level level = Level.toLevel(levelString); + + //above Level.toLevel call returns a DEBUG Level if the request fails. Check the result. + if (level.equals(Level.DEBUG) && !(levelString.equalsIgnoreCase("debug"))) + { + //received DEBUG but we did not ask for it, the Level request failed. + throw new IllegalLoggerLevelException("Level '" + levelString + "' specified for Logger '" + loggerName + "' is invalid"); + } + } + + public static class IllegalLoggerLevelException extends Exception + { + private static final long serialVersionUID = 1L; + + public IllegalLoggerLevelException(String msg) + { + super(msg); + } + } +} + Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java?rev=804765&r1=804764&r2=804765&view=diff ============================================================================== --- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java (original) +++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/Main.java Sun Aug 16 20:32:47 2009 @@ -27,9 +27,9 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.apache.commons.cli.PosixParser; -import org.apache.log4j.BasicConfigurator; import org.apache.log4j.Logger; -import org.apache.log4j.xml.DOMConfigurator; +import org.apache.log4j.PropertyConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator; import org.apache.mina.common.ByteBuffer; import org.apache.mina.common.FixedSizeByteBufferAllocator; import org.apache.mina.common.IoAcceptor; @@ -56,9 +56,11 @@ import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.BindException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.util.Properties; /** * Main entry point for AMQPD. @@ -200,7 +202,7 @@ } catch (InitException e) { - System.out.println(e.getMessage()); + System.out.println("Initialisation Error : " + e.getMessage()); _brokerLogger.error("Initialisation Error : " + e.getMessage()); shutdown(1); } @@ -498,7 +500,7 @@ return ip; } - private void configureLogging(File logConfigFile, int logWatchTime) + private void configureLogging(File logConfigFile, int logWatchTime) throws InitException, IOException { if (logConfigFile.exists() && logConfigFile.canRead()) { @@ -509,18 +511,43 @@ System.out.println("log file " + logConfigFile.getAbsolutePath() + " will be checked for changes every " + logWatchTime + " seconds"); // log4j expects the watch interval in milliseconds - DOMConfigurator.configureAndWatch(logConfigFile.getAbsolutePath(), logWatchTime * 1000); + try + { + QpidLog4JConfigurator.configureAndWatch(logConfigFile.getPath(), logWatchTime * 1000); + } + catch (Exception e) + { + throw new InitException(e.getMessage(),e); + } } else { - DOMConfigurator.configure(logConfigFile.getAbsolutePath()); + try + { + QpidLog4JConfigurator.configure(logConfigFile.getPath()); + } + catch (Exception e) + { + throw new InitException(e.getMessage(),e); + } } } else { System.err.println("Logging configuration error: unable to read file " + logConfigFile.getAbsolutePath()); - System.err.println("Using basic log4j configuration"); - BasicConfigurator.configure(); + System.err.println("Using the fallback internal log4j.properties configuration"); + + InputStream propsFile = this.getClass().getResourceAsStream("/log4j.properties"); + if(propsFile == null) + { + throw new IOException("Unable to load the fallback internal log4j.properties configuration file"); + } + else + { + Properties fallbackProps = new Properties(); + fallbackProps.load(propsFile); + PropertyConfigurator.configure(fallbackProps); + } } } Modified: qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java?rev=804765&r1=804764&r2=804765&view=diff ============================================================================== --- qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java (original) +++ qpid/trunk/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/management/LoggingManagementMBean.java Sun Aug 16 20:32:47 2009 @@ -24,7 +24,9 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; @@ -34,6 +36,8 @@ import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.apache.log4j.xml.Log4jEntityResolver; +import org.apache.log4j.xml.QpidLog4JConfigurator; +import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -244,46 +248,50 @@ } //handler to catch errors signalled by the JAXP parser and throw an appropriate exception - private class SaxErrorHandler implements ErrorHandler + public static class QpidLog4JSaxErrorHandler implements ErrorHandler { - public void error(SAXParseException e) throws SAXException { - throw new SAXException("Error parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Error parsing XML file", e)); } public void fatalError(SAXParseException e) throws SAXException { - throw new SAXException("Fatal error parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Fatal error parsing XML file", e)); } public void warning(SAXParseException e) throws SAXException { - throw new SAXException("Warning parsing XML file: " + e.getMessage()); + throw new SAXException(constructMessage("Warning parsing XML file", e)); + } + + private static String constructMessage(final String msg, final SAXParseException ex) + { + return new String(msg + ": Line " + ex.getLineNumber()+" column " +ex.getColumnNumber() + ": " + ex.getMessage()); } } //method to parse the XML configuration file, validating it in the process, and returning a DOM Document of the content. - private synchronized Document parseConfigFile(String fileName) throws IOException + private static synchronized Document parseConfigFile(String fileName) throws IOException { //check file was specified, exists, and is readable if(fileName == null) { - _logger.warn("No log4j XML configuration file has been set"); - throw new IOException("No log4j XML configuration file has been set"); + _logger.warn("Provided log4j XML configuration filename is null"); + throw new IOException("Provided log4j XML configuration filename is null"); } File configFile = new File(fileName); if (!configFile.exists()) { - _logger.warn("Specified log4j XML configuration file does not exist: " + fileName); - throw new IOException("Specified log4j XML configuration file does not exist"); + _logger.warn("The log4j XML configuration file could not be found: " + fileName); + throw new IOException("The log4j XML configuration file could not be found"); } else if (!configFile.canRead()) { - _logger.warn("Specified log4j XML configuration file is not readable: " + fileName); - throw new IOException("Specified log4j XML configuration file is not readable"); + _logger.warn("The log4j XML configuration file is not readable: " + fileName); + throw new IOException("The log4j XML configuration file is not readable"); } //parse it @@ -291,7 +299,7 @@ DocumentBuilder docBuilder; Document doc; - ErrorHandler errHandler = new SaxErrorHandler(); + ErrorHandler errHandler = new QpidLog4JSaxErrorHandler(); try { docFactory.setValidating(true); @@ -315,14 +323,14 @@ catch (IOException e) { _logger.warn("Unable to parse the specified log4j XML file" + e); - throw new IOException("Unable to parse the specified log4j XML file", e); + throw new IOException("Unable to parse the specified log4j XML file: " + e.getMessage()); } return doc; } - private synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException + private static synchronized boolean writeUpdatedConfigFile(String log4jConfigFileName, Document doc) throws IOException { File log4jConfigFile = new File(log4jConfigFileName); @@ -389,20 +397,11 @@ * and not the only possible child element. */ - - public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + public static synchronized Map<String,String> retrieveConfigFileLoggersLevels(String fileName) throws IOException { - if (_loggerLevelTabularType == null) - { - _logger.warn("TabluarData type not set up correctly"); - return null; - } - - _logger.info("Getting logger levels from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); + Document doc = parseConfigFile(fileName); - TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + HashMap<String,String> loggerLevelList = new HashMap<String,String>(); //retrieve the 'category' element nodes NodeList categoryElements = doc.getElementsByTagName("category"); @@ -436,17 +435,7 @@ continue; } - try - { - Object[] itemData = {categoryName, priority}; - CompositeData loggerData = new CompositeDataSupport(_loggerLevelCompositeType, COMPOSITE_ITEM_NAMES, itemData); - loggerLevelList.put(loggerData); - } - catch (OpenDataException e) - { - _logger.warn("Unable to create logger level list due to :" + e); - return null; - } + loggerLevelList.put(categoryName, priority); } //retrieve the 'logger' element nodes @@ -467,6 +456,30 @@ Element levelElement = (Element) levelElements.item(0); level = levelElement.getAttribute("value").toUpperCase(); + loggerLevelList.put(loggerName, level); + } + + return loggerLevelList; + } + + public synchronized TabularData viewConfigFileLoggerLevels() throws IOException + { + if (_loggerLevelTabularType == null) + { + _logger.warn("TabluarData type not set up correctly"); + return null; + } + + _logger.info("Getting logger levels from log4j configuration file"); + + TabularData loggerLevelList = new TabularDataSupport(_loggerLevelTabularType); + + Map<String,String> levels = retrieveConfigFileLoggersLevels(_log4jConfigFileName); + + for (String loggerName : levels.keySet()) + { + String level = levels.get(loggerName); + try { Object[] itemData = {loggerName, level}; @@ -574,19 +587,17 @@ * and not the only possible child element. */ - public synchronized String getConfigFileRootLoggerLevel() throws IOException + public static synchronized String retrieveConfigFileRootLoggerLevel(String fileName) throws IOException { - _logger.info("Getting root logger level from log4j configuration file"); - - Document doc = parseConfigFile(_log4jConfigFileName); + Document doc = parseConfigFile(fileName); //retrieve the optional 'root' element node NodeList rootElements = doc.getElementsByTagName("root"); if (rootElements.getLength() == 0) { - //there is not root logger definition - return null; + //there is no root logger definition + return "N/A"; } Element rootElement = (Element) rootElements.item(0); @@ -618,6 +629,11 @@ } } + public synchronized String getConfigFileRootLoggerLevel() throws IOException + { + return retrieveConfigFileRootLoggerLevel(_log4jConfigFileName); + } + public synchronized boolean setConfigFileRootLoggerLevel(String level) throws IOException { //check that the specified level is a valid log4j Level Added: qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java?rev=804765&view=auto ============================================================================== --- qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java (added) +++ qpid/trunk/qpid/java/broker/src/test/java/org/apache/log4j/xml/QpidLog4JConfiguratorTest.java Sun Aug 16 20:32:47 2009 @@ -0,0 +1,396 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + * + */ +package org.apache.log4j.xml; + + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.apache.log4j.xml.QpidLog4JConfigurator.IllegalLoggerLevelException; + +import junit.framework.TestCase; + +public class QpidLog4JConfiguratorTest extends TestCase +{ + private static final String NEWLINE = System.getProperty("line.separator"); + + private File _testConfigFile; + + private File createTempTestLog4JConfig(String loggerLevel,String rootLoggerLevel, boolean missingTagClose, boolean incorrectAttribute) + { + File tmpFile = null; + try + { + tmpFile = File.createTempFile("LogManMBeanTestLog4jConfig", ".tmp"); + tmpFile.deleteOnExit(); + + FileWriter fstream = new FileWriter(tmpFile); + BufferedWriter writer = new BufferedWriter(fstream); + + writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+NEWLINE); + writer.write("<!DOCTYPE log4j:configuration SYSTEM \"log4j.dtd\">"+NEWLINE); + + writer.write("<log4j:configuration xmlns:log4j=\"http://jakarta.apache.org/log4j/\" debug=\"null\" " + + "threshold=\"null\">"+NEWLINE); + + writer.write(" <appender class=\"org.apache.log4j.ConsoleAppender\" name=\"STDOUT\">"+NEWLINE); + writer.write(" <layout class=\"org.apache.log4j.PatternLayout\">"+NEWLINE); + writer.write(" <param name=\"ConversionPattern\" value=\"%d %-5p [%t] %C{2} (%F:%L) - %m%n\"/>"+NEWLINE); + writer.write(" </layout>"+NEWLINE); + writer.write(" </appender>"+NEWLINE); + + String closeTag="/"; + if(missingTagClose) + { + closeTag=""; + } + + //Example of a 'category' with a 'priority' + writer.write(" <category additivity=\"true\" name=\"logger1\">"+NEWLINE); + writer.write(" <priority value=\"" + loggerLevel+ "\"" + closeTag + ">"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </category>"+NEWLINE); + + String attributeName="value"; + if(incorrectAttribute) + { + attributeName="values"; + } + + //Example of a 'category' with a 'level' + writer.write(" <category additivity=\"true\" name=\"logger2\">"+NEWLINE); + writer.write(" <level " + attributeName + "=\"" + loggerLevel+ "\"/>"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </category>"+NEWLINE); + + //Example of a 'logger' with a 'level' + writer.write(" <logger additivity=\"true\" name=\"logger3\">"+NEWLINE); + writer.write(" <level value=\"" + loggerLevel+ "\"/>"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </logger>"+NEWLINE); + + //'root' logger + writer.write(" <root>"+NEWLINE); + writer.write(" <priority value=\"" + rootLoggerLevel+ "\"/>"+NEWLINE); + writer.write(" <appender-ref ref=\"STDOUT\"/>"+NEWLINE); + writer.write(" </root>"+NEWLINE); + + writer.write("</log4j:configuration>"+NEWLINE); + + writer.flush(); + writer.close(); + } + catch (IOException e) + { + fail("Unable to create temporary test log4j configuration"); + } + + return tmpFile; + } + + + + //******* Test Methods ******* // + + public void testCheckLevelsAndStrictParser() + { + //try the valid logger levels + _testConfigFile = createTempTestLog4JConfig("all", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("trace", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("debug", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("warn", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("error", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("fatal", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("off", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("null", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("inherited", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + //now try an invalid logger level + _testConfigFile = createTempTestLog4JConfig("madeup", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IllegalLoggerLevelException expected, invalid levels used"); + } + catch (IllegalLoggerLevelException e) + { + //expected, ignore + } + catch (IOException e) + { + fail("Incorrect Exception, expected an IllegalLoggerLevelException"); + } + + + + //now try the valid rootLogger levels + _testConfigFile = createTempTestLog4JConfig("info", "all", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "trace", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "info", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "warn", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "error", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "fatal", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "off", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "null", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "inherited", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + _testConfigFile = createTempTestLog4JConfig("info", "debug", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + } + catch (Exception e) + { + fail("No exception expected, valid levels and xml were used"); + } + + //now try an invalid logger level + _testConfigFile = createTempTestLog4JConfig("info", "madeup", false, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IllegalLoggerLevelException expected, invalid levels used"); + } + catch (IllegalLoggerLevelException e) + { + //expected, ignore + } + catch (IOException e) + { + fail("Incorrect Exception, expected an IllegalLoggerLevelException"); + } + + + + //now try invalid xml + _testConfigFile = createTempTestLog4JConfig("info", "info", true, false); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IOException expected, malformed XML used"); + } + catch (IllegalLoggerLevelException e) + { + fail("Incorrect Exception, expected an IOException"); + } + catch (IOException e) + { + //expected, ignore + } + + _testConfigFile = createTempTestLog4JConfig("info", "info", false, true); + try + { + QpidLog4JConfigurator.checkLoggerLevels(_testConfigFile.getAbsolutePath()); + fail("IOException expected, malformed XML used"); + } + catch (IllegalLoggerLevelException e) + { + fail("Incorrect Exception, expected an IOException"); + } + catch (IOException e) + { + //expected, ignore + } + } +} --------------------------------------------------------------------- Apache Qpid - AMQP Messaging Implementation Project: http://qpid.apache.org Use/Interact: mailto:commits-subscr...@qpid.apache.org