You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by gg...@apache.org on 2016/12/17 00:24:57 UTC

[2/2] logging-log4j2 git commit: [LOG4J2-1743] CompositeConfiguration does not add filters to appenderRefs.

[LOG4J2-1743] CompositeConfiguration does not add filters to
appenderRefs.

Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d21f7595
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d21f7595
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d21f7595

Branch: refs/heads/master
Commit: d21f759525762a97f310a38997f52c227fcc5617
Parents: d0ba955
Author: Toby Shepheard <sh...@gmail.com>
Authored: Fri Dec 16 16:24:51 2016 -0800
Committer: Gary Gregory <ga...@gmail.com>
Committed: Fri Dec 16 16:24:51 2016 -0800

----------------------------------------------------------------------
 .../config/composite/DefaultMergeStrategy.java  |  545 +-
 .../core/config/CompositeConfigurationTest.java |  461 +-
 .../test/resources/log4j-comp-logger-ref.json   |   18 +
 .../test/resources/log4j-comp-logger-ref.xml    |   32 +
 src/changes/changes.xml                         | 6621 +++++++++---------
 5 files changed, 3880 insertions(+), 3797 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d21f7595/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
index 9eccdf5..1fb7a50 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/composite/DefaultMergeStrategy.java
@@ -1,272 +1,273 @@
-/*
- * 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.logging.log4j.core.config.composite;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.Filter;
-import org.apache.logging.log4j.core.config.AbstractConfiguration;
-import org.apache.logging.log4j.core.config.Node;
-import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
-import org.apache.logging.log4j.core.config.plugins.util.PluginType;
-import org.apache.logging.log4j.core.filter.CompositeFilter;
-
-/**
- * The default merge strategy for composite configurations.
- * <p>
- * The default merge strategy performs the merge according to the following rules:
- * <ol>
- * <li>Aggregates the global configuration attributes with those in later configurations replacing those in previous
- * configurations with the exception that the highest status level and the lowest monitorInterval greater than 0 will
- * be used.</li>
- * <li>Properties from all configurations are aggregated. Duplicate properties replace those in previous
- * configurations.</li>
- * <li>Filters are aggregated under a CompositeFilter if more than one Filter is defined. Since Filters are not named
- * duplicates may be present.</li>
- * <li>Scripts and ScriptFile references are aggregated. Duplicate definiations replace those in previous
- * configurations.</li>
- * <li>Appenders are aggregated. Appenders with the same name are replaced by those in later configurations, including
- * all of the Appender's subcomponents.</li>
- * <li>Loggers are all aggregated. Logger attributes are individually merged with duplicates being replaced by those
- * in later configurations. Appender references on a Logger are aggregated with duplicates being replaced by those in
- * later configurations. Filters on a Logger are aggregated under a CompositeFilter if more than one Filter is defined.
- * Since Filters are not named duplicates may be present. Filters under Appender references included or discarded
- * depending on whether their parent Appender reference is kept or discarded.</li>
- * </ol>
- */
-public class DefaultMergeStrategy implements MergeStrategy {
-
-    private static final String APPENDERS = "appenders";
-    private static final String PROPERTIES = "properties";
-    private static final String LOGGERS = "loggers";
-    private static final String SCRIPTS = "scripts";
-    private static final String FILTERS = "filters";
-    private static final String STATUS = "status";
-    private static final String NAME = "name";
-    private static final String REF = "ref";
-
-    /**
-     * Merge the root properties.
-     * @param rootNode The composite root node.
-     * @param configuration The configuration to merge.
-     */
-    @Override
-    public void mergeRootProperties(final Node rootNode, final AbstractConfiguration configuration) {
-        for (final Map.Entry<String, String> attribute : configuration.getRootNode().getAttributes().entrySet()) {
-            boolean isFound = false;
-            for (final Map.Entry<String, String> targetAttribute : rootNode.getAttributes().entrySet()) {
-                if (targetAttribute.getKey().equalsIgnoreCase(attribute.getKey())) {
-                    if (attribute.getKey().equalsIgnoreCase(STATUS)) {
-                        final Level targetLevel = Level.getLevel(targetAttribute.getValue().toUpperCase());
-                        final Level sourceLevel = Level.getLevel(attribute.getValue().toUpperCase());
-                        if (targetLevel != null && sourceLevel != null) {
-                            if (sourceLevel.isLessSpecificThan(targetLevel)) {
-                                targetAttribute.setValue(attribute.getValue());
-                            }
-                        } else
-                            if (sourceLevel != null) {
-                                targetAttribute.setValue(attribute.getValue());
-                            }
-                    } else {
-                        if (attribute.getKey().equalsIgnoreCase("monitorInterval")) {
-                            final int sourceInterval = Integer.parseInt(attribute.getValue());
-                            final int targetInterval = Integer.parseInt(targetAttribute.getValue());
-                            if (targetInterval == 0 || sourceInterval < targetInterval) {
-                                targetAttribute.setValue(attribute.getValue());
-                            }
-                        } else {
-                            targetAttribute.setValue(attribute.getValue());
-                        }
-                    }
-                    isFound = true;
-                }
-            }
-            if (!isFound) {
-                rootNode.getAttributes().put(attribute.getKey(), attribute.getValue());
-            }
-        }
-    }
-
-    /**
-     * Merge the source Configuration into the target Configuration.
-     *
-     * @param target        The target node to merge into.
-     * @param source        The source node.
-     * @param pluginManager The PluginManager.
-     */
-    @Override
-    public void mergConfigurations(final Node target, final Node source, final PluginManager pluginManager) {
-        for (final Node sourceChildNode : source.getChildren()) {
-            final boolean isFilter = isFilterNode(sourceChildNode);
-            boolean isMerged = false;
-            for (final Node targetChildNode : target.getChildren()) {
-                if (isFilter) {
-                    if (isFilterNode(targetChildNode)) {
-                        updateFilterNode(target, targetChildNode, sourceChildNode, pluginManager);
-                        isMerged = true;
-                        break;
-                    }
-                    continue;
-                }
-
-                if (!targetChildNode.getName().equalsIgnoreCase(sourceChildNode.getName())) {
-                    continue;
-                }
-
-                switch (targetChildNode.getName().toLowerCase()) {
-                    case PROPERTIES:
-                    case SCRIPTS:
-                    case APPENDERS: {
-                        for (final Node node : sourceChildNode.getChildren()) {
-                            for (final Node targetNode : targetChildNode.getChildren()) {
-                                if (targetNode.getAttributes().get(NAME).equals(node.getAttributes().get(NAME))) {
-                                    targetChildNode.getChildren().remove(targetNode);
-                                    break;
-                                }
-                            }
-                            targetChildNode.getChildren().add(node);
-                        }
-                        isMerged = true;
-                        break;
-                    }
-                    case LOGGERS: {
-                        final Map<String, Node> targetLoggers = new HashMap<>();
-                        for (final Node node : targetChildNode.getChildren()) {
-                            targetLoggers.put(node.getName(), node);
-                        }
-                        for (final Node node : sourceChildNode.getChildren()) {
-                            final Node targetNode = getLoggerNode(targetChildNode, node.getAttributes().get(NAME));
-                            final Node loggerNode = new Node(targetChildNode, node.getName(), node.getType());
-                            if (targetNode != null) {
-                                targetNode.getAttributes().putAll(node.getAttributes());
-                                for (final Node sourceLoggerChild : node.getChildren()) {
-                                    if (isFilterNode(sourceLoggerChild)) {
-                                        boolean foundFilter = false;
-                                        for (final Node targetChild : targetNode.getChildren()) {
-                                            if (isFilterNode(targetChild)) {
-                                                updateFilterNode(loggerNode, targetChild, sourceLoggerChild,
-                                                        pluginManager);
-                                                foundFilter = true;
-                                                break;
-                                            }
-                                        }
-                                        if (!foundFilter) {
-                                            final Node childNode = new Node(loggerNode, sourceLoggerChild.getName(),
-                                                    sourceLoggerChild.getType());
-                                            targetNode.getChildren().add(childNode);
-                                        }
-                                    } else {
-                                        final Node childNode = new Node(loggerNode, sourceLoggerChild.getName(),
-                                                sourceLoggerChild.getType());
-                                        childNode.getAttributes().putAll(sourceLoggerChild.getAttributes());
-                                        if (childNode.getName().equalsIgnoreCase("AppenderRef")) {
-                                            for (final Node targetChild : targetNode.getChildren()) {
-                                                if (isSameReference(targetChild, childNode)) {
-                                                    targetNode.getChildren().remove(targetChild);
-                                                    break;
-                                                }
-                                            }
-                                        } else {
-                                            for (final Node targetChild : targetNode.getChildren()) {
-                                                if (isSameName(targetChild, childNode)) {
-                                                    targetNode.getChildren().remove(targetChild);
-                                                    break;
-                                                }
-                                            }
-                                        }
-
-                                        targetNode.getChildren().add(childNode);
-                                    }
-                                }
-                            } else {
-                                loggerNode.getAttributes().putAll(node.getAttributes());
-                                loggerNode.getChildren().addAll(node.getChildren());
-                                targetChildNode.getChildren().add(loggerNode);
-                            }
-                        }
-                        isMerged = true;
-                        break;
-                    }
-                    default: {
-                        targetChildNode.getChildren().addAll(sourceChildNode.getChildren());
-                        isMerged = true;
-                        break;
-                    }
-
-                }
-            }
-            if (!isMerged) {
-                if (sourceChildNode.getName().equalsIgnoreCase("Properties")) {
-                    target.getChildren().add(0, sourceChildNode);
-                } else {
-                    target.getChildren().add(sourceChildNode);
-                }
-            }
-        }
-    }
-
-    private Node getLoggerNode(final Node parentNode, final String name) {
-        for (final Node node : parentNode.getChildren()) {
-            final String nodeName = node.getAttributes().get(NAME);
-            if (name == null && nodeName == null) {
-                return node;
-            }
-            if (nodeName != null && nodeName.equals(name)) {
-                return node;
-            }
-        }
-        return null;
-    }
-
-    private void updateFilterNode(final Node target, final Node targetChildNode, final Node sourceChildNode,
-            final PluginManager pluginManager) {
-        if (CompositeFilter.class.isAssignableFrom(targetChildNode.getType().getPluginClass())) {
-            final Node node = new Node(targetChildNode, sourceChildNode.getName(), sourceChildNode.getType());
-            node.getChildren().addAll(sourceChildNode.getChildren());
-            node.getAttributes().putAll(sourceChildNode.getAttributes());
-            targetChildNode.getChildren().add(node);
-        } else {
-            final PluginType pluginType = pluginManager.getPluginType(FILTERS);
-            final Node filtersNode = new Node(targetChildNode, FILTERS, pluginType);
-            final Node node = new Node(filtersNode, sourceChildNode.getName(), sourceChildNode.getType());
-            node.getAttributes().putAll(sourceChildNode.getAttributes());
-            final List<Node> children = filtersNode.getChildren();
-            children.add(targetChildNode);
-            children.add(node);
-            final List<Node> nodes = target.getChildren();
-            nodes.remove(targetChildNode);
-            nodes.add(filtersNode);
-        }
-    }
-
-    private boolean isFilterNode(final Node node) {
-        return Filter.class.isAssignableFrom(node.getType().getPluginClass());
-    }
-
-    private boolean isSameName(final Node node1, final Node node2) {
-        final String value = node1.getAttributes().get(NAME);
-        return value != null && value.toLowerCase().equals(node2.getAttributes().get(NAME).toLowerCase());
-    }
-
-    private boolean isSameReference(final Node node1, final Node node2) {
-        final String value = node1.getAttributes().get(REF);
-        return value != null && value.toLowerCase().equals(node2.getAttributes().get(REF).toLowerCase());
-    }
-}
+/*
+ * 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.logging.log4j.core.config.composite;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Filter;
+import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
+import org.apache.logging.log4j.core.config.plugins.util.PluginType;
+import org.apache.logging.log4j.core.filter.CompositeFilter;
+
+/**
+ * The default merge strategy for composite configurations.
+ * <p>
+ * The default merge strategy performs the merge according to the following rules:
+ * <ol>
+ * <li>Aggregates the global configuration attributes with those in later configurations replacing those in previous
+ * configurations with the exception that the highest status level and the lowest monitorInterval greater than 0 will
+ * be used.</li>
+ * <li>Properties from all configurations are aggregated. Duplicate properties replace those in previous
+ * configurations.</li>
+ * <li>Filters are aggregated under a CompositeFilter if more than one Filter is defined. Since Filters are not named
+ * duplicates may be present.</li>
+ * <li>Scripts and ScriptFile references are aggregated. Duplicate definiations replace those in previous
+ * configurations.</li>
+ * <li>Appenders are aggregated. Appenders with the same name are replaced by those in later configurations, including
+ * all of the Appender's subcomponents.</li>
+ * <li>Loggers are all aggregated. Logger attributes are individually merged with duplicates being replaced by those
+ * in later configurations. Appender references on a Logger are aggregated with duplicates being replaced by those in
+ * later configurations. Filters on a Logger are aggregated under a CompositeFilter if more than one Filter is defined.
+ * Since Filters are not named duplicates may be present. Filters under Appender references included or discarded
+ * depending on whether their parent Appender reference is kept or discarded.</li>
+ * </ol>
+ */
+public class DefaultMergeStrategy implements MergeStrategy {
+
+    private static final String APPENDERS = "appenders";
+    private static final String PROPERTIES = "properties";
+    private static final String LOGGERS = "loggers";
+    private static final String SCRIPTS = "scripts";
+    private static final String FILTERS = "filters";
+    private static final String STATUS = "status";
+    private static final String NAME = "name";
+    private static final String REF = "ref";
+
+    /**
+     * Merge the root properties.
+     * @param rootNode The composite root node.
+     * @param configuration The configuration to merge.
+     */
+    @Override
+    public void mergeRootProperties(final Node rootNode, final AbstractConfiguration configuration) {
+        for (final Map.Entry<String, String> attribute : configuration.getRootNode().getAttributes().entrySet()) {
+            boolean isFound = false;
+            for (final Map.Entry<String, String> targetAttribute : rootNode.getAttributes().entrySet()) {
+                if (targetAttribute.getKey().equalsIgnoreCase(attribute.getKey())) {
+                    if (attribute.getKey().equalsIgnoreCase(STATUS)) {
+                        final Level targetLevel = Level.getLevel(targetAttribute.getValue().toUpperCase());
+                        final Level sourceLevel = Level.getLevel(attribute.getValue().toUpperCase());
+                        if (targetLevel != null && sourceLevel != null) {
+                            if (sourceLevel.isLessSpecificThan(targetLevel)) {
+                                targetAttribute.setValue(attribute.getValue());
+                            }
+                        } else
+                            if (sourceLevel != null) {
+                                targetAttribute.setValue(attribute.getValue());
+                            }
+                    } else {
+                        if (attribute.getKey().equalsIgnoreCase("monitorInterval")) {
+                            final int sourceInterval = Integer.parseInt(attribute.getValue());
+                            final int targetInterval = Integer.parseInt(targetAttribute.getValue());
+                            if (targetInterval == 0 || sourceInterval < targetInterval) {
+                                targetAttribute.setValue(attribute.getValue());
+                            }
+                        } else {
+                            targetAttribute.setValue(attribute.getValue());
+                        }
+                    }
+                    isFound = true;
+                }
+            }
+            if (!isFound) {
+                rootNode.getAttributes().put(attribute.getKey(), attribute.getValue());
+            }
+        }
+    }
+
+    /**
+     * Merge the source Configuration into the target Configuration.
+     *
+     * @param target        The target node to merge into.
+     * @param source        The source node.
+     * @param pluginManager The PluginManager.
+     */
+    @Override
+    public void mergConfigurations(final Node target, final Node source, final PluginManager pluginManager) {
+        for (final Node sourceChildNode : source.getChildren()) {
+            final boolean isFilter = isFilterNode(sourceChildNode);
+            boolean isMerged = false;
+            for (final Node targetChildNode : target.getChildren()) {
+                if (isFilter) {
+                    if (isFilterNode(targetChildNode)) {
+                        updateFilterNode(target, targetChildNode, sourceChildNode, pluginManager);
+                        isMerged = true;
+                        break;
+                    }
+                    continue;
+                }
+
+                if (!targetChildNode.getName().equalsIgnoreCase(sourceChildNode.getName())) {
+                    continue;
+                }
+
+                switch (targetChildNode.getName().toLowerCase()) {
+                    case PROPERTIES:
+                    case SCRIPTS:
+                    case APPENDERS: {
+                        for (final Node node : sourceChildNode.getChildren()) {
+                            for (final Node targetNode : targetChildNode.getChildren()) {
+                                if (targetNode.getAttributes().get(NAME).equals(node.getAttributes().get(NAME))) {
+                                    targetChildNode.getChildren().remove(targetNode);
+                                    break;
+                                }
+                            }
+                            targetChildNode.getChildren().add(node);
+                        }
+                        isMerged = true;
+                        break;
+                    }
+                    case LOGGERS: {
+                        final Map<String, Node> targetLoggers = new HashMap<>();
+                        for (final Node node : targetChildNode.getChildren()) {
+                            targetLoggers.put(node.getName(), node);
+                        }
+                        for (final Node node : sourceChildNode.getChildren()) {
+                            final Node targetNode = getLoggerNode(targetChildNode, node.getAttributes().get(NAME));
+                            final Node loggerNode = new Node(targetChildNode, node.getName(), node.getType());
+                            if (targetNode != null) {
+                                targetNode.getAttributes().putAll(node.getAttributes());
+                                for (final Node sourceLoggerChild : node.getChildren()) {
+                                    if (isFilterNode(sourceLoggerChild)) {
+                                        boolean foundFilter = false;
+                                        for (final Node targetChild : targetNode.getChildren()) {
+                                            if (isFilterNode(targetChild)) {
+                                                updateFilterNode(loggerNode, targetChild, sourceLoggerChild,
+                                                        pluginManager);
+                                                foundFilter = true;
+                                                break;
+                                            }
+                                        }
+                                        if (!foundFilter) {
+                                            final Node childNode = new Node(loggerNode, sourceLoggerChild.getName(),
+                                                    sourceLoggerChild.getType());
+                                            targetNode.getChildren().add(childNode);
+                                        }
+                                    } else {
+                                        final Node childNode = new Node(loggerNode, sourceLoggerChild.getName(),
+                                                sourceLoggerChild.getType());
+                                        childNode.getAttributes().putAll(sourceLoggerChild.getAttributes());
+                                        childNode.getChildren().addAll(sourceLoggerChild.getChildren());
+                                        if (childNode.getName().equalsIgnoreCase("AppenderRef")) {
+                                            for (final Node targetChild : targetNode.getChildren()) {
+                                                if (isSameReference(targetChild, childNode)) {
+                                                    targetNode.getChildren().remove(targetChild);
+                                                    break;
+                                                }
+                                            }
+                                        } else {
+                                            for (final Node targetChild : targetNode.getChildren()) {
+                                                if (isSameName(targetChild, childNode)) {
+                                                    targetNode.getChildren().remove(targetChild);
+                                                    break;
+                                                }
+                                            }
+                                        }
+
+                                        targetNode.getChildren().add(childNode);
+                                    }
+                                }
+                            } else {
+                                loggerNode.getAttributes().putAll(node.getAttributes());
+                                loggerNode.getChildren().addAll(node.getChildren());
+                                targetChildNode.getChildren().add(loggerNode);
+                            }
+                        }
+                        isMerged = true;
+                        break;
+                    }
+                    default: {
+                        targetChildNode.getChildren().addAll(sourceChildNode.getChildren());
+                        isMerged = true;
+                        break;
+                    }
+
+                }
+            }
+            if (!isMerged) {
+                if (sourceChildNode.getName().equalsIgnoreCase("Properties")) {
+                    target.getChildren().add(0, sourceChildNode);
+                } else {
+                    target.getChildren().add(sourceChildNode);
+                }
+            }
+        }
+    }
+
+    private Node getLoggerNode(final Node parentNode, final String name) {
+        for (final Node node : parentNode.getChildren()) {
+            final String nodeName = node.getAttributes().get(NAME);
+            if (name == null && nodeName == null) {
+                return node;
+            }
+            if (nodeName != null && nodeName.equals(name)) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    private void updateFilterNode(final Node target, final Node targetChildNode, final Node sourceChildNode,
+            final PluginManager pluginManager) {
+        if (CompositeFilter.class.isAssignableFrom(targetChildNode.getType().getPluginClass())) {
+            final Node node = new Node(targetChildNode, sourceChildNode.getName(), sourceChildNode.getType());
+            node.getChildren().addAll(sourceChildNode.getChildren());
+            node.getAttributes().putAll(sourceChildNode.getAttributes());
+            targetChildNode.getChildren().add(node);
+        } else {
+            final PluginType pluginType = pluginManager.getPluginType(FILTERS);
+            final Node filtersNode = new Node(targetChildNode, FILTERS, pluginType);
+            final Node node = new Node(filtersNode, sourceChildNode.getName(), sourceChildNode.getType());
+            node.getAttributes().putAll(sourceChildNode.getAttributes());
+            final List<Node> children = filtersNode.getChildren();
+            children.add(targetChildNode);
+            children.add(node);
+            final List<Node> nodes = target.getChildren();
+            nodes.remove(targetChildNode);
+            nodes.add(filtersNode);
+        }
+    }
+
+    private boolean isFilterNode(final Node node) {
+        return Filter.class.isAssignableFrom(node.getType().getPluginClass());
+    }
+
+    private boolean isSameName(final Node node1, final Node node2) {
+        final String value = node1.getAttributes().get(NAME);
+        return value != null && value.toLowerCase().equals(node2.getAttributes().get(NAME).toLowerCase());
+    }
+
+    private boolean isSameReference(final Node node1, final Node node2) {
+        final String value = node1.getAttributes().get(REF);
+        return value != null && value.toLowerCase().equals(node2.getAttributes().get(REF).toLowerCase());
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d21f7595/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
index bbf842e..6976426 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/CompositeConfigurationTest.java
@@ -1,216 +1,245 @@
-/*
- * 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.logging.log4j.core.config;
-
-import java.util.Map;
-
-import org.apache.logging.log4j.Level;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.appender.ConsoleAppender;
-import org.apache.logging.log4j.core.appender.FileAppender;
-import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
-import org.apache.logging.log4j.core.util.Throwables;
-import org.apache.logging.log4j.junit.LoggerContextRule;
-import org.junit.Assert;
-import org.junit.Test;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
-
-import static org.junit.Assert.*;
-
-public class CompositeConfigurationTest {
-/*
-    @Test
-    public void compositeConfigurationUsed() {
-        final LoggerContextRule lcr = new LoggerContextRule(
-                "classpath:log4j-comp-appender.xml,log4j-comp-appender.json");
-        Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                assertTrue(lcr.getConfiguration() instanceof CompositeConfiguration);
-            }
-        };
-        runTest(lcr, test);
-    }
-
-    @Test
-    public void compositeProperties() {
-        final LoggerContextRule lcr = new LoggerContextRule(
-                "classpath:log4j-comp-properties.xml,log4j-comp-properties.json");
-        Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                assertEquals("json", config.getStrSubstitutor().replace("${propertyShared}"));
-                assertEquals("xml", config.getStrSubstitutor().replace("${propertyXml}"));
-                assertEquals("json", config.getStrSubstitutor().replace("${propertyJson}"));
-            }
-        };
-        runTest(lcr, test);
-    }
-
-    @Test
-    public void compositeAppenders() {
-        final LoggerContextRule lcr = new LoggerContextRule(
-                "classpath:log4j-comp-appender.xml,log4j-comp-appender.json");
-        Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                Map<String, Appender> appender = config.getAppenders();
-                assertEquals(3, appender.size());
-                assertTrue(appender.get("STDOUT") instanceof ConsoleAppender);
-                assertTrue(appender.get("File") instanceof FileAppender);
-                assertTrue(appender.get("Override") instanceof RollingFileAppender);
-            }
-        };
-        runTest(lcr, test);
-    }
-*/
-    @Test
-    public void compositeLogger() {
-        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger.xml,log4j-comp-logger.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                Map<String, Appender> appendersMap = config.getLogger("cat1").getAppenders();
-                assertEquals("Expected 2 Appender references for cat1 but got " + appendersMap.size(), 2,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
-
-                appendersMap = config.getLogger("cat2").getAppenders();
-                assertEquals("Expected 1 Appender reference for cat2 but got " + appendersMap.size(), 1,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("File") instanceof FileAppender);
-
-                appendersMap = config.getLogger("cat3").getAppenders();
-                assertEquals("Expected 1 Appender reference for cat3 but got " + appendersMap.size(), 1,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("File") instanceof FileAppender);
-
-                appendersMap = config.getRootLogger().getAppenders();
-                assertEquals("Expected 2 Appender references for the root logger but got " + appendersMap.size(), 2,
-                        appendersMap.size());
-                assertTrue(appendersMap.get("File") instanceof FileAppender);
-                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
-            }
-        };
-        runTest(lcr, test);
-    }
-
-    @Test
-    public void testAttributeCheckWhenMergingConfigurations() {
-        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-root-loggers.xml,log4j-comp-logger.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                try {
-                    final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                    Assert.assertNotNull(config);
-                } catch (final NullPointerException e) {
-                    fail("Should not throw NullPointerException when there are different nodes.");
-                }
-            }
-        };
-        runTest(lcr, test);
-    }
-
-    @Test
-    public void testAttributeMergeForLoggers() {
-        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger-root.xml,log4j-comp-logger-attr-override.json");
-        final Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                //Test for Root log level override
-                assertEquals("Expected Root logger log level to be WARN", Level.WARN, config.getRootLogger().getLevel());
-
-                //Test for cat2 level override
-                final LoggerConfig cat2 = config.getLogger("cat2");
-                assertEquals("Expected cat2 log level to be INFO", Level.INFO, cat2.getLevel());
-
-                //Test for cat2 additivity override
-                assertTrue("Expected cat2 additivity to be true", cat2.isAdditive());
-
-                //Regression
-                //Check level on cat3 (not present in root config)
-                assertEquals("Expected cat3 log level to be ERROR", Level.ERROR, config.getLogger("cat3").getLevel());
-                //Check level on cat1 (not present in overriden config)
-                assertEquals("Expected cat1 log level to be DEBUG", Level.DEBUG, config.getLogger("cat1").getLevel());
-            }
-        };
-        runTest(lcr, test);
-    }
-/*
-    @Test
-    public void overrideFilter() {
-        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-filter.xml,log4j-comp-filter.json");
-        Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
-                assertTrue(config.getFilter() instanceof CompositeFilter);
-                CompositeFilter filter = (CompositeFilter) config.getFilter();
-                assertTrue(filter.getFiltersArray().length == 2);
-            }
-        };
-        runTest(lcr, test);
-    }
-
-    @Test
-    public void testReconfiguration() throws Exception {
-        final LoggerContextRule rule =
-                new LoggerContextRule("classpath:log4j-comp-reconfig.xml,log4j-comp-reconfig.properties");
-        Statement test = new Statement() {
-            @Override
-            public void evaluate() throws Throwable {
-                final Configuration oldConfig = rule.getConfiguration();
-                final org.apache.logging.log4j.Logger logger = rule.getLogger("LoggerTest");
-                final int MONITOR_INTERVAL_SECONDS = 5;
-                final File file = new File("target/test-classes/log4j-comp-reconfig.properties");
-                final long orig = file.lastModified();
-                final long newTime = orig + 10000;
-                assertTrue("setLastModified should have succeeded.", file.setLastModified(newTime));
-                TimeUnit.SECONDS.sleep(MONITOR_INTERVAL_SECONDS + 1);
-                for (int i = 0; i < 17; ++i) {
-                    logger.debug("Reconfigure");
-                }
-                int loopCount = 0;
-                Configuration newConfig;
-                do {
-                    Thread.sleep(100);
-                    newConfig = rule.getConfiguration();
-                    ++loopCount;
-                } while (newConfig == oldConfig && loopCount <= 5);
-                assertNotSame("Reconfiguration failed", newConfig, oldConfig);
-            }
-        };
-        runTest(rule, test);
-
-    } */
-
-    private void runTest(final LoggerContextRule rule, final Statement statement) {
-        try {
-            rule.apply(statement, Description
-                    .createTestDescription(getClass(), Thread.currentThread().getStackTrace()[1].getMethodName()))
-                    .evaluate();
-        } catch (final Throwable e) {
-            Throwables.rethrow(e);
-        }
-    }
-}
+/*
+ * 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.logging.log4j.core.config;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.appender.FileAppender;
+import org.apache.logging.log4j.core.config.composite.CompositeConfiguration;
+import org.apache.logging.log4j.core.filter.RegexFilter;
+import org.apache.logging.log4j.core.util.Throwables;
+import org.apache.logging.log4j.junit.LoggerContextRule;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import static org.junit.Assert.*;
+
+public class CompositeConfigurationTest {
+/*
+    @Test
+    public void compositeConfigurationUsed() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-appender.xml,log4j-comp-appender.json");
+        Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                assertTrue(lcr.getConfiguration() instanceof CompositeConfiguration);
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
+    public void compositeProperties() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-properties.xml,log4j-comp-properties.json");
+        Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+                assertEquals("json", config.getStrSubstitutor().replace("${propertyShared}"));
+                assertEquals("xml", config.getStrSubstitutor().replace("${propertyXml}"));
+                assertEquals("json", config.getStrSubstitutor().replace("${propertyJson}"));
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
+    public void compositeAppenders() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-appender.xml,log4j-comp-appender.json");
+        Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+                Map<String, Appender> appender = config.getAppenders();
+                assertEquals(3, appender.size());
+                assertTrue(appender.get("STDOUT") instanceof ConsoleAppender);
+                assertTrue(appender.get("File") instanceof FileAppender);
+                assertTrue(appender.get("Override") instanceof RollingFileAppender);
+            }
+        };
+        runTest(lcr, test);
+    }
+*/
+    @Test
+    public void compositeLogger() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger.xml,log4j-comp-logger.json");
+        final Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+                Map<String, Appender> appendersMap = config.getLogger("cat1").getAppenders();
+                assertEquals("Expected 2 Appender references for cat1 but got " + appendersMap.size(), 2,
+                        appendersMap.size());
+                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
+
+                appendersMap = config.getLogger("cat2").getAppenders();
+                assertEquals("Expected 1 Appender reference for cat2 but got " + appendersMap.size(), 1,
+                        appendersMap.size());
+                assertTrue(appendersMap.get("File") instanceof FileAppender);
+
+                appendersMap = config.getLogger("cat3").getAppenders();
+                assertEquals("Expected 1 Appender reference for cat3 but got " + appendersMap.size(), 1,
+                        appendersMap.size());
+                assertTrue(appendersMap.get("File") instanceof FileAppender);
+
+                appendersMap = config.getRootLogger().getAppenders();
+                assertEquals("Expected 2 Appender references for the root logger but got " + appendersMap.size(), 2,
+                        appendersMap.size());
+                assertTrue(appendersMap.get("File") instanceof FileAppender);
+                assertTrue(appendersMap.get("STDOUT") instanceof ConsoleAppender);
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
+    public void testAttributeCheckWhenMergingConfigurations() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-root-loggers.xml,log4j-comp-logger.json");
+        final Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                try {
+                    final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+                    Assert.assertNotNull(config);
+                } catch (final NullPointerException e) {
+                    fail("Should not throw NullPointerException when there are different nodes.");
+                }
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
+    public void testAttributeMergeForLoggers() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-logger-root.xml,log4j-comp-logger-attr-override.json");
+        final Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+                //Test for Root log level override
+                assertEquals("Expected Root logger log level to be WARN", Level.WARN, config.getRootLogger().getLevel());
+
+                //Test for cat2 level override
+                final LoggerConfig cat2 = config.getLogger("cat2");
+                assertEquals("Expected cat2 log level to be INFO", Level.INFO, cat2.getLevel());
+
+                //Test for cat2 additivity override
+                assertTrue("Expected cat2 additivity to be true", cat2.isAdditive());
+
+                //Regression
+                //Check level on cat3 (not present in root config)
+                assertEquals("Expected cat3 log level to be ERROR", Level.ERROR, config.getLogger("cat3").getLevel());
+                //Check level on cat1 (not present in overriden config)
+                assertEquals("Expected cat1 log level to be DEBUG", Level.DEBUG, config.getLogger("cat1").getLevel());
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
+    public void testAppenderRefFilterMerge() {
+        final LoggerContextRule lcr = new LoggerContextRule(
+                "classpath:log4j-comp-logger-ref.xml,log4j-comp-logger-ref.json");
+        final Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                final CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+
+                List<AppenderRef> appenderRefList = config.getLogger("cat1").getAppenderRefs();
+                AppenderRef appenderRef = getAppenderRef(appenderRefList, "STDOUT");
+                assertTrue("Expected cat1 STDOUT appenderRef to have a regex filter",
+                        appenderRef.getFilter() != null && appenderRef.getFilter() instanceof RegexFilter);
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    private AppenderRef getAppenderRef(List<AppenderRef> appenderRefList, String refName) {
+        for (AppenderRef ref : appenderRefList) {
+            if (ref.getRef().equalsIgnoreCase(refName)) {
+                return ref;
+            }
+        }
+        return null;
+    }
+/*
+    @Test
+    public void overrideFilter() {
+        final LoggerContextRule lcr = new LoggerContextRule("classpath:log4j-comp-filter.xml,log4j-comp-filter.json");
+        Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                CompositeConfiguration config = (CompositeConfiguration) lcr.getConfiguration();
+                assertTrue(config.getFilter() instanceof CompositeFilter);
+                CompositeFilter filter = (CompositeFilter) config.getFilter();
+                assertTrue(filter.getFiltersArray().length == 2);
+            }
+        };
+        runTest(lcr, test);
+    }
+
+    @Test
+    public void testReconfiguration() throws Exception {
+        final LoggerContextRule rule =
+                new LoggerContextRule("classpath:log4j-comp-reconfig.xml,log4j-comp-reconfig.properties");
+        Statement test = new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                final Configuration oldConfig = rule.getConfiguration();
+                final org.apache.logging.log4j.Logger logger = rule.getLogger("LoggerTest");
+                final int MONITOR_INTERVAL_SECONDS = 5;
+                final File file = new File("target/test-classes/log4j-comp-reconfig.properties");
+                final long orig = file.lastModified();
+                final long newTime = orig + 10000;
+                assertTrue("setLastModified should have succeeded.", file.setLastModified(newTime));
+                TimeUnit.SECONDS.sleep(MONITOR_INTERVAL_SECONDS + 1);
+                for (int i = 0; i < 17; ++i) {
+                    logger.debug("Reconfigure");
+                }
+                int loopCount = 0;
+                Configuration newConfig;
+                do {
+                    Thread.sleep(100);
+                    newConfig = rule.getConfiguration();
+                    ++loopCount;
+                } while (newConfig == oldConfig && loopCount <= 5);
+                assertNotSame("Reconfiguration failed", newConfig, oldConfig);
+            }
+        };
+        runTest(rule, test);
+
+    } */
+
+    private void runTest(final LoggerContextRule rule, final Statement statement) {
+        try {
+            rule.apply(statement, Description
+                    .createTestDescription(getClass(), Thread.currentThread().getStackTrace()[1].getMethodName()))
+                    .evaluate();
+        } catch (final Throwable e) {
+            Throwables.rethrow(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d21f7595/log4j-core/src/test/resources/log4j-comp-logger-ref.json
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-logger-ref.json b/log4j-core/src/test/resources/log4j-comp-logger-ref.json
new file mode 100644
index 0000000..ab591c8
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-comp-logger-ref.json
@@ -0,0 +1,18 @@
+{
+    "Configuration" : {
+        "name": "LoggerConfigTest",
+        "Loggers" : {
+            "logger" : [
+                {
+                    "name" : "cat1",
+                    "level" : "debug",
+                    "additivity" : false,
+                    "AppenderRef" : {
+                        "ref" : "STDOUT",
+                        "RegexFilter": {"regex" : "TEST", "onMatch": "deny", "onMismatch": "accept"}
+                    }
+                }
+            ]
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d21f7595/log4j-core/src/test/resources/log4j-comp-logger-ref.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/log4j-comp-logger-ref.xml b/log4j-core/src/test/resources/log4j-comp-logger-ref.xml
new file mode 100644
index 0000000..78b4cc3
--- /dev/null
+++ b/log4j-core/src/test/resources/log4j-comp-logger-ref.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+
+-->
+<Configuration status="ERROR" name="LoggerConfigTest">
+    <Appenders>
+        <Console name="STDOUT">
+            <PatternLayout pattern="%m%n"/>
+        </Console>
+    </Appenders>
+
+    <Loggers>
+        <Logger name="cat1" level="debug" additivity="false">
+            <AppenderRef ref="STDOUT"/>
+        </Logger>
+    </Loggers>
+
+</Configuration>
\ No newline at end of file