- New conversion words can be easily added to PatternLayout using configuration files.
- These conversion words will be shared by all instances of PatternLayout
(work in progress.)
git-svn-id: https://svn.apache.org/repos/asf/logging/log4j/trunk@311134 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/examples/src/pattern/LearnNewWord.java b/examples/src/pattern/LearnNewWord.java
new file mode 100644
index 0000000..3045128
--- /dev/null
+++ b/examples/src/pattern/LearnNewWord.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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 pattern;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.joran.JoranConfigurator;
+
+/**
+ *
+ * Example showing how to extend PatternLayout to recognize additional
+ * conversion words without through a configuration file.
+ *
+ * <p>In this case have PatternLayout recognize %counter conversion word.
+ * It outputs the value of an internal counter which is also incremented at
+ * each call.
+ *
+ * @author Ceki Gülcü
+ */
+
+public class LearnNewWord {
+
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ System.err.println("Usage: java " + LearnNewWord.class.getName() +
+ " configFile");
+
+ }
+
+ JoranConfigurator joran = new JoranConfigurator();
+
+ joran.doConfigure(args[0], LogManager.getLoggerRepository());
+ joran.dumpErrors();
+
+ Logger logger = Logger.getLogger("some.cat");
+ logger.debug("Hello, log");
+ logger.info("Hello again...");
+ }
+}
diff --git a/examples/src/pattern/MyPatternLayout.java b/examples/src/pattern/MyPatternLayout.java
deleted file mode 100644
index 4ff56e7..0000000
--- a/examples/src/pattern/MyPatternLayout.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 1999,2004 The Apache Software Foundation.
- *
- * Licensed 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 pattern;
-
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.PatternLayout;
-import org.apache.log4j.Logger;
-import org.apache.log4j.Layout;
-
-/**
- *
- * Example showing how to extend PatternLayout to recognize additional
- * conversion words without adding.
- *
- * <p>In this case MyPatternLayout recognizes %counter conversion word.
- * It outputs the value of an internal counter which is also incremented at
- * each call.
- *
- * @see org.apache.log4j.PatternLayout
- * @author Anders Kristensen
- * @author Ceki Gülcü
- */
-
-public class MyPatternLayout extends PatternLayout {
- public MyPatternLayout() {
- super();
- }
-
- public MyPatternLayout(String pattern) {
- super(pattern);
- }
-
- /**
- Activates the conversion pattern. Do not forget to call this method after
- you change the parameters of the PatternLayout instance.
- */
- public void activateOptions() {
- this.addConversionRule("counter", CountingPatternConverter.class.getName());
- super.activateOptions();
- }
-
- public static void main(String[] args) {
- Layout layout = new MyPatternLayout("[counter=%.10#] - %m%n");
- Logger logger = Logger.getLogger("some.cat");
- logger.addAppender(new ConsoleAppender(layout, ConsoleAppender.SYSTEM_OUT));
- logger.debug("Hello, log");
- logger.info("Hello again...");
- }
-}
diff --git a/examples/src/pattern/log4j-config.xml b/examples/src/pattern/log4j-config.xml
new file mode 100644
index 0000000..8c1e492
--- /dev/null
+++ b/examples/src/pattern/log4j-config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration>
+
+<configuration xmlns="http://logging.apache.org/">
+
+ <!-- teach log4j a new conversion word -->
+ <conversionRule conversionWord="counter" converterClass="pattern.CountingPatternConverter"/>
+
+ <!-- the new conversion word is available for immediate use -->
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="[%3.10counter] - %m%n"/>
+ </layout>
+ </appender>
+
+ <root>
+ <appender-ref ref="CONSOLE"/>
+ </root>
+</configuration>
\ No newline at end of file
diff --git a/src/java/org/apache/joran/ExecutionContext.java b/src/java/org/apache/joran/ExecutionContext.java
index 3af03cb..6de3611 100644
--- a/src/java/org/apache/joran/ExecutionContext.java
+++ b/src/java/org/apache/joran/ExecutionContext.java
@@ -25,6 +25,7 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Properties;
import java.util.Stack;
import java.util.Vector;
@@ -40,7 +41,7 @@
*/
public class ExecutionContext {
Stack objectStack;
- HashMap objectMap;
+ Map objectMap;
Vector errorList;
Properties substitutionProperties;
Interpreter joranInterpreter;
@@ -107,7 +108,7 @@
return objectStack.get(i);
}
- public HashMap getObjectMap() {
+ public Map getObjectMap() {
return objectMap;
}
diff --git a/src/java/org/apache/log4j/AppenderSkeleton.java b/src/java/org/apache/log4j/AppenderSkeleton.java
index 807a5e9..89f9fc6 100644
--- a/src/java/org/apache/log4j/AppenderSkeleton.java
+++ b/src/java/org/apache/log4j/AppenderSkeleton.java
@@ -334,7 +334,7 @@
if(repository == null) {
throw new IllegalArgumentException("repository argument cannot be null");
}
- if(this.repository != null) {
+ if(this.repository == null) {
this.repository = repository;
} else {
throw new IllegalStateException("Repository has been already set");
diff --git a/src/java/org/apache/log4j/Hierarchy.java b/src/java/org/apache/log4j/Hierarchy.java
index d3ac87f..2ff5a58 100644
--- a/src/java/org/apache/log4j/Hierarchy.java
+++ b/src/java/org/apache/log4j/Hierarchy.java
@@ -36,6 +36,7 @@
import java.util.ArrayList;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
@@ -84,6 +85,10 @@
Map properties;
private Scheduler scheduler;
+ // The repository can also be used as an object store for various objects used
+ // by log4j components
+ private Map objectMap;
+
// the internal logger used by this instance of Hierarchy for its own reporting
private Logger myLogger;
@@ -104,7 +109,7 @@
repositoryEventListeners = new ArrayList(1);
loggerEventListeners = new ArrayList(1);
this.root = root;
-
+ this.objectMap = new HashMap();
// Enable all level levels by default.
setThreshold(Level.ALL);
this.root.setHierarchy(this);
@@ -791,4 +796,13 @@
}
return scheduler;
}
+
+ public void putObject(String key, Object value) {
+ objectMap.put(key, value);
+ }
+
+ public Object getObject(String key) {
+ return objectMap.get(key);
+ }
+
}
diff --git a/src/java/org/apache/log4j/Layout.java b/src/java/org/apache/log4j/Layout.java
index d483ce0..5ce113e 100644
--- a/src/java/org/apache/log4j/Layout.java
+++ b/src/java/org/apache/log4j/Layout.java
@@ -166,7 +166,7 @@
if(repository == null) {
throw new IllegalArgumentException("repository argument cannot be null");
}
- if(this.repository != null) {
+ if(this.repository == null) {
this.repository = repository;
} else {
throw new IllegalStateException("Repository has been already set");
diff --git a/src/java/org/apache/log4j/PatternLayout.java b/src/java/org/apache/log4j/PatternLayout.java
index fe25bf2..de31651 100644
--- a/src/java/org/apache/log4j/PatternLayout.java
+++ b/src/java/org/apache/log4j/PatternLayout.java
@@ -18,7 +18,7 @@
import java.io.IOException;
import java.io.Writer;
-import java.util.HashMap;
+import java.util.Map;
import org.apache.log4j.pattern.PatternConverter;
import org.apache.log4j.pattern.PatternParser;
@@ -415,10 +415,16 @@
public static final String TTCC_CONVERSION_PATTERN =
"%r [%t] %p %c %x - %m%n";
+ /**
+ * Customized pattern conversion rules are stored under this key in the
+ * {@link LoggerRepository} object store.
+ */
+ public static final String PATTERN_RULE_REGISTRY = "PATTERN_RULE_REGISTRY";
+
private String conversionPattern;
private PatternConverter head;
- private HashMap ruleRegistry = null;
+
private boolean handlesExceptions;
/**
@@ -437,30 +443,6 @@
this.conversionPattern = pattern;
activateOptions();
}
-
- /**
- *
- * Add a new conversion word and associate it with a
- * {@link org.apache.log4j.pattern.PatternConverter PatternConverter} class.
- *
- * @param conversionWord New conversion word to accept in conversion patterns
- * @param converterClass The class name associated with the conversion word
- * @since 1.3
- */
- public void addConversionRule(String conversionWord, String converterClass) {
- if(ruleRegistry == null) {
- ruleRegistry = new HashMap(5);
- }
- ruleRegistry.put(conversionWord, converterClass);
- }
-
- /**
- * Returns the rule registry specific for this PatternLayout instance.
- * @since 1.3
- */
- public HashMap getRuleRegistry() {
- return ruleRegistry;
- }
/**
Set the <b>ConversionPattern</b> option. This is the string which
@@ -484,7 +466,9 @@
*/
public void activateOptions() {
PatternParser patternParser = new PatternParser(conversionPattern);
- patternParser.setConverterRegistry(ruleRegistry);
+ if(this.repository != null) {
+ patternParser.setConverterRegistry((Map) this.repository.getObject(PATTERN_RULE_REGISTRY));
+ }
head = patternParser.parse();
handlesExceptions = PatternConverter.chainHandlesThrowable(head);
}
diff --git a/src/java/org/apache/log4j/joran/JoranConfigurator.java b/src/java/org/apache/log4j/joran/JoranConfigurator.java
index ec531d8..6baf724 100644
--- a/src/java/org/apache/log4j/joran/JoranConfigurator.java
+++ b/src/java/org/apache/log4j/joran/JoranConfigurator.java
@@ -56,6 +56,7 @@
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
@@ -194,6 +195,9 @@
rs.addRule(
new Pattern("configuration/repositoryProperty"),
new RepositoryPropertyAction());
+ rs.addRule(
+ new Pattern("configuration/conversionRule"),
+ new ConversionRuleAction());
rs.addRule(new Pattern("configuration/plugin"), new PluginAction());
rs.addRule(new Pattern("configuration/logger"), new LoggerAction());
rs.addRule(
@@ -218,9 +222,6 @@
new AppenderRefAction());
rs.addRule(
new Pattern("configuration/appender/layout"), new LayoutAction());
- rs.addRule(
- new Pattern("configuration/appender/layout/conversionRule"),
- new ConversionRuleAction());
rs.addRule(
new Pattern("configuration/jndiSubstitutionProperty"),
new JndiSubstitutionPropertyAction());
@@ -234,7 +235,7 @@
joranInterpreter.addImplicitAction(new NestComponentIA());
ExecutionContext ec = joranInterpreter.getExecutionContext();
- HashMap omap = ec.getObjectMap();
+ Map omap = ec.getObjectMap();
omap.put(ActionConst.APPENDER_BAG, new HashMap());
}
diff --git a/src/java/org/apache/log4j/joran/action/AppenderAction.java b/src/java/org/apache/log4j/joran/action/AppenderAction.java
index e9c67bc..47b9aea 100644
--- a/src/java/org/apache/log4j/joran/action/AppenderAction.java
+++ b/src/java/org/apache/log4j/joran/action/AppenderAction.java
@@ -22,6 +22,7 @@
import org.apache.log4j.Appender;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorItem;
+import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.OptionHandler;
import org.xml.sax.Attributes;
@@ -53,6 +54,9 @@
className, org.apache.log4j.Appender.class, null);
appender = (Appender) instance;
+ LoggerRepository repo = (LoggerRepository) ec.getObjectStack().get(0);
+ appender.setLoggerRepository(repo);
+
String appenderName = attributes.getValue(NAME_ATTRIBUTE);
if (Option.isEmpty(appenderName)) {
diff --git a/src/java/org/apache/log4j/joran/action/ConversionRuleAction.java b/src/java/org/apache/log4j/joran/action/ConversionRuleAction.java
index 4f4e299..ef9eae9 100644
--- a/src/java/org/apache/log4j/joran/action/ConversionRuleAction.java
+++ b/src/java/org/apache/log4j/joran/action/ConversionRuleAction.java
@@ -16,6 +16,9 @@
package org.apache.log4j.joran.action;
+import java.util.HashMap;
+import java.util.Map;
+
import org.apache.joran.ExecutionContext;
import org.apache.joran.action.Action;
import org.apache.joran.helper.Option;
@@ -23,6 +26,7 @@
import org.apache.log4j.Layout;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.ErrorItem;
+import org.apache.log4j.spi.LoggerRepository;
import org.xml.sax.Attributes;
@@ -66,15 +70,18 @@
try {
getLogger().debug(
- "About to add conversion rule [" + conversionWord + ", "
- + converterClass + "] to layout");
+ "About to add conversion rule [{}, {}] to layout", conversionWord, converterClass);
- Object o = ec.peekObject();
+ LoggerRepository repository = (LoggerRepository) ec.getObjectStack().get(0);
- if (o instanceof PatternLayout) {
- PatternLayout patternLayout = (PatternLayout) o;
- patternLayout.addConversionRule(conversionWord, converterClass);
+ Map ruleRegistry = (Map) repository.getObject(PatternLayout.PATTERN_RULE_REGISTRY);
+ if(ruleRegistry == null) {
+ ruleRegistry = new HashMap();
+ repository.putObject(PatternLayout.PATTERN_RULE_REGISTRY, ruleRegistry);
}
+ // put the new rule into the rule registry
+ ruleRegistry.put(conversionWord, converterClass);
+
} catch (Exception oops) {
inError = true;
errorMsg = "Could not add conversion rule to PatternLayout.";
diff --git a/src/java/org/apache/log4j/joran/action/LayoutAction.java b/src/java/org/apache/log4j/joran/action/LayoutAction.java
index abaf3fd..4cb135f 100644
--- a/src/java/org/apache/log4j/joran/action/LayoutAction.java
+++ b/src/java/org/apache/log4j/joran/action/LayoutAction.java
@@ -23,6 +23,7 @@
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorItem;
+import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.OptionHandler;
import org.xml.sax.Attributes;
@@ -49,7 +50,10 @@
OptionConverter.instantiateByClassName(
className, org.apache.log4j.Layout.class, null);
layout = (Layout) instance;
-
+
+ LoggerRepository repo = (LoggerRepository) ec.getObjectStack().get(0);
+ layout.setLoggerRepository(repo);
+
getLogger().debug("Pushing layout on top of the object stack.");
ec.pushObject(layout);
} catch (Exception oops) {
diff --git a/src/java/org/apache/log4j/spi/LoggerRepository.java b/src/java/org/apache/log4j/spi/LoggerRepository.java
index 8b8eecb..2bf3a7c 100644
--- a/src/java/org/apache/log4j/spi/LoggerRepository.java
+++ b/src/java/org/apache/log4j/spi/LoggerRepository.java
@@ -209,4 +209,21 @@
* @return List
*/
public void addErrorItem(ErrorItem errorItem);
+
+ /**
+ * A LoggerRepository can also act as a store for various objects used
+ * by log4j components.
+ *
+ * @return The object stored under 'key'.
+ * @since 1.3
+ */
+ public Object getObject(String key);
+
+ /**
+ * Store an object under 'key'. If no object can be found, null is returned.
+ *
+ * @param key
+ * @param value
+ */
+ public void putObject(String key, Object value);
}
diff --git a/tests/input/joran/conversionRule.xml b/tests/input/joran/conversionRule.xml
index 7af988c..887b1de 100644
--- a/tests/input/joran/conversionRule.xml
+++ b/tests/input/joran/conversionRule.xml
@@ -2,6 +2,9 @@
<!DOCTYPE log4j:configuration>
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
+
+ <conversionRule conversionWord="toto" converterClass="org.apache.log4j.toto"/>
+
<appender name="A1" class="org.apache.log4j.rolling.RollingFileAppender">
<param name="File" value="output/temp.A1" />
<param name="Append" value="false" />
@@ -14,7 +17,6 @@
</triggeringPolicy>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%-5p %c{2} - %m%n"/>
- <conversionRule conversionWord="toto" converterClass="org.apache.log4j.toto"/>
</layout>
</appender>
</log4j:configuration>
\ No newline at end of file
diff --git a/tests/input/pattern/patternLayout14.properties b/tests/input/pattern/patternLayout14.properties
deleted file mode 100644
index 1eadf98..0000000
--- a/tests/input/pattern/patternLayout14.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-log4j.rootCategory=DEBUG, testAppender
-log4j.appender.testAppender=org.apache.log4j.FileAppender
-log4j.appender.testAppender.File= output/temp
-log4j.appender.testAppender.Append=false
-log4j.appender.testAppender.layout=pattern.MyPatternLayout
-log4j.appender.testAppender.layout.ConversionPattern=%5p %-4counter - %m%n
-
-# Prevent internal log4j DEBUG messages from polluting the output.
-log4j.logger.org.apache.log4j.PropertyConfigurator=INFO
-log4j.logger.org.apache.log4j.config.PropertySetter=INFO
-log4j.logger.org.apache.log4j.FileAppender=INFO
diff --git a/tests/src/java/org/apache/joran/InterpreterTest.java b/tests/src/java/org/apache/joran/InterpreterTest.java
index c99449f..4b85202 100644
--- a/tests/src/java/org/apache/joran/InterpreterTest.java
+++ b/tests/src/java/org/apache/joran/InterpreterTest.java
@@ -52,9 +52,11 @@
import org.apache.log4j.rolling.SizeBasedTriggeringPolicy;
import org.apache.log4j.rolling.FixedWindowRollingPolicy;
import org.apache.log4j.spi.ErrorItem;
+import org.apache.log4j.spi.LoggerRepository;
import org.xml.sax.SAXParseException;
import java.util.HashMap;
+import java.util.Map;
import java.util.Stack;
import javax.xml.parsers.SAXParser;
@@ -175,7 +177,7 @@
Interpreter jp = new Interpreter(rs);
ExecutionContext ec = jp.getExecutionContext();
- HashMap omap = ec.getObjectMap();
+ Map omap = ec.getObjectMap();
omap.put(ActionConst.APPENDER_BAG, new HashMap());
ec.pushObject(LogManager.getLoggerRepository());
SAXParser saxParser = createParser();
@@ -231,7 +233,7 @@
Interpreter jp = new Interpreter(rs);
ExecutionContext ec = jp.getExecutionContext();
- HashMap omap = ec.getObjectMap();
+ Map omap = ec.getObjectMap();
omap.put(ActionConst.APPENDER_BAG, new HashMap());
ec.pushObject(LogManager.getLoggerRepository());
SAXParser saxParser = createParser();
@@ -295,7 +297,7 @@
jp.addImplicitAction(new NestComponentIA());
ExecutionContext ec = jp.getExecutionContext();
- HashMap omap = ec.getObjectMap();
+ Map omap = ec.getObjectMap();
omap.put(ActionConst.APPENDER_BAG, new HashMap());
ec.pushObject(LogManager.getLoggerRepository());
logger.debug("About to parse doc");
@@ -340,9 +342,10 @@
jp.addImplicitAction(new NestComponentIA());
ExecutionContext ec = jp.getExecutionContext();
- HashMap omap = ec.getObjectMap();
+ Map omap = ec.getObjectMap();
omap.put(ActionConst.APPENDER_BAG, new HashMap());
- ec.pushObject(LogManager.getLoggerRepository());
+ LoggerRepository repository = LogManager.getLoggerRepository();
+ ec.pushObject(repository);
SAXParser saxParser = createParser();
saxParser.parse("file:input/joran/conversionRule.xml", jp);
@@ -351,7 +354,9 @@
(HashMap) ec.getObjectMap().get(ActionConst.APPENDER_BAG);
Appender appender = (Appender) appenderBag.get("A1");
PatternLayout pl = (PatternLayout) appender.getLayout();
- assertEquals("org.apache.log4j.toto", pl.getRuleRegistry().get("toto"));
+
+ Map ruleRegistry = (Map) repository.getObject(PatternLayout.PATTERN_RULE_REGISTRY);
+ assertEquals("org.apache.log4j.toto", ruleRegistry.get("toto"));
}
@@ -367,7 +372,7 @@
Interpreter jp = new Interpreter(rs);
ExecutionContext ec = jp.getExecutionContext();
- HashMap omap = ec.getObjectMap();
+ Map omap = ec.getObjectMap();
SAXParser saxParser = createParser();
saxParser.parse("file:input/joran/newRule1.xml", jp);
diff --git a/tests/src/java/org/apache/log4j/PatternLayoutTest.java b/tests/src/java/org/apache/log4j/PatternLayoutTest.java
index 9256a8c..847632d 100644
--- a/tests/src/java/org/apache/log4j/PatternLayoutTest.java
+++ b/tests/src/java/org/apache/log4j/PatternLayoutTest.java
@@ -287,22 +287,6 @@
assertTrue(Compare.compare(FILTERED, "witness/pattern/patternLayout.13"));
}
- public void test14() throws Exception {
- PropertyConfigurator.configure("input/pattern/patternLayout14.properties");
- common();
-
- ControlFilter cf1 =
- new ControlFilter(
- new String[] { PAT14, EXCEPTION1, EXCEPTION2, EXCEPTION3 });
- Transformer.transform(
- TEMP, FILTERED,
- new Filter[] {
- cf1, new LineNumberFilter(), new SunReflectFilter(),
- new JunitTestRunnerFilter()
- });
- assertTrue(Compare.compare(FILTERED, "witness/pattern/patternLayout.14"));
- }
-
public void testMDC1() throws Exception {
PropertyConfigurator.configure("input/pattern/patternLayout.mdc.1.properties");
MDC.put("key1", "va11");