Index: log4j-api/src/main/java/org/apache/logging/log4j/Marker.java =================================================================== --- log4j-api/src/main/java/org/apache/logging/log4j/Marker.java (revision 1583045) +++ log4j-api/src/main/java/org/apache/logging/log4j/Marker.java (working copy) @@ -16,40 +16,463 @@ */ package org.apache.logging.log4j; +import java.io.IOException; import java.io.Serializable; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; /** - * Markers are objects that are used to add easily filterable information to log messages. - * - * Markers can be hierarchical - each Marker may have a parent. This allows for broad categories - * being subdivided into more specific categories. An example might be a Marker named "Error" with - * children named "SystemError" and "ApplicationError". + * Markers are objects that are used to add easily filterable information to log messages. + * + * Markers can be hierarchical - each Marker may have one or more parents. This allows for broad + * categories being subdivided into more specific categories. An example might be a Marker named + * "Error" with children named "SystemError" and "ApplicationError". */ -public interface Marker extends Serializable { +public final class Marker implements Serializable { + private static final long serialVersionUID = 1L; + private static final ReadWriteLock lock = new ReentrantReadWriteLock(); + private static final ConcurrentMap markerMap = new ConcurrentHashMap(); + + private final String name; + private final Parents parents = new Parents(); + private final transient Set allParentNames = Collections.newSetFromMap(new ConcurrentHashMap()); + + Marker(final String name) { + this.name = name; + } + + Marker(final String name, final Marker... parents) { + this.name = name; + if (parents != null) { + this.parents.addAll(Arrays.asList(parents)); + refreshAllParentNames(); + } + } + + private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + refreshAllParentNames(); + } /** * Returns the name of this Marker. + * * @return The name of the Marker. */ - String getName(); + public String getName() { + return this.name; + } /** - * Returns the parent of this Marker. - * @return The parent Marker or null if this Marker has no parent. + * Returns the parents of this Marker. + * + * @return The parent Markers. */ - Marker getParent(); + public Set getParents() { + return this.parents; + } + + void refreshAllParentNames() { + // The write lock must already be acquired or be invoked from the constructor or + // readObject + if (!parents.isEmpty()) { + for (Marker parent : parents) { + allParentNames.add(parent.name); + allParentNames.addAll(parent.allParentNames); + } + } else { + allParentNames.clear(); + } + } + + void refreshAllParentNamesRecursively() { + // The write lock must already be acquired + refreshAllParentNames(); + + for (Marker child : childrenOf(this)) { + child.refreshAllParentNamesRecursively(); + } + } /** * Checks whether this Marker is an instance of the specified Marker. + * * @param m The Marker to check. * @return true of this Marker or one of its ancestors is the specified Marker, false otherwise. */ - boolean isInstanceOf(Marker m); + public boolean isInstanceOf(final Marker marker) { + if (marker == null) { + throw new IllegalArgumentException("A marker parameter is required"); + } + return allParentNames.contains(marker.name); +// return isInstanceOf(marker.name); + } /** * Checks whether this Marker is an instance of the specified Marker. + * + * @param name The name of the Marker. + * @return true of this Marker or one of its ancestors matches the specified name, false + * otherwise. + */ + public boolean isInstanceOf(final String markerName) { + return allParentNames.contains(markerName); +// for (Marker parent : parents) { +// if (markerName == null && parent.name == null) { +// return true; +// } else if (markerName.equals(parent.name)) { +// return true; +// } else if (parent.isInstanceOf(markerName)) { +// return true; +// } +// } +// return false; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || !(o instanceof Marker)) { + return false; + } + final Marker that = (Marker) o; + return name == null ? that.getName() == null : name.equals(that.getName()); + } + + @Override + public int hashCode() { + return name != null ? name.hashCode() : 0; + } + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder(name); + if (!allParentNames.isEmpty()) { + sb.append("[ "); + boolean first = true; + for (String parent : new TreeSet(allParentNames)) { + if (!first) { + sb.append(", "); + } + sb.append(parent); + first = false; + } + } + return sb.toString(); + } + + private class Parents implements Set, Serializable { + private static final long serialVersionUID = 1L; + private final ConcurrentMap map = new ConcurrentHashMap(); + private transient Set set = map.keySet(); + + @Override + public int size() { + return map.size(); + } + + void replaceAll(Marker[] parents) { + lock.writeLock().lock(); + try { + map.clear(); + for (Marker parent : parents) { + map.put(parent, Boolean.TRUE); + } + refreshAllParentNamesRecursively(); + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public boolean isEmpty() { + return map.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return set.contains(o); + } + + @Override + public boolean containsAll(Collection c) { + return set.containsAll(c); + } + + @Override + public Iterator iterator() { + return set.iterator(); + } + + @Override + public Object[] toArray() { + return set.toArray(); + } + + @Override + public T[] toArray(T[] a) { + return set.toArray(a); + } + + @Override + public boolean add(Marker parent) { + lock.writeLock().lock(); + try { + assertNoCircularDependency(Marker.this, parent); + if (map.put(parent, Boolean.TRUE) == null) { + refreshAllParentNamesRecursively(); + return true; + } + } finally { + lock.writeLock().unlock(); + } + return false; + } + + @Override + public boolean addAll(Collection parents) { + lock.writeLock().lock(); + try { + assertNoCircularDependency(Marker.this, parents.toArray(new Marker[parents.size()])); + boolean changesMade = false; + for (Marker parent : parents) { + changesMade |= (map.put(parent, Boolean.TRUE) == null); + } + if (changesMade) { + refreshAllParentNamesRecursively(); + } + return changesMade; + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public boolean remove(Object o) { + lock.writeLock().lock(); + try { + if (map.remove(o) != null) { + refreshAllParentNamesRecursively(); + return true; + } + } finally { + lock.writeLock().unlock(); + } + return false; + } + + @Override + public boolean retainAll(Collection c) { + lock.writeLock().lock(); + try { + if (set.retainAll(c)) { + refreshAllParentNamesRecursively(); + return true; + } + } finally { + lock.writeLock().unlock(); + } + return false; + } + + @Override + public boolean removeAll(Collection c) { + lock.writeLock().lock(); + try { + if (set.removeAll(c)) { + refreshAllParentNamesRecursively(); + return true; + } + } finally { + lock.writeLock().unlock(); + } + return false; + } + + @Override + public void clear() { + lock.writeLock().lock(); + try { + if (!map.isEmpty()) { + map.clear(); + refreshAllParentNamesRecursively(); + } + } finally { + lock.writeLock().unlock(); + } + } + + @Override + public boolean equals(Object obj) { + return set.equals(obj); + } + + @Override + public int hashCode() { + return map.hashCode(); + } + + private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException { + stream.defaultReadObject(); + set = map.keySet(); + } + } + + /** + * Retrieve a Marker or create a Marker that has no parents. + * + * @param name The name of the Marker. + * @return The Marker with the specified name. + */ + public static Marker get(final String name) { + return get(name, true); + } + + public static Marker get(final String name, final boolean createIfMissing) { + lock.readLock().lock(); + try { + Marker marker = markerMap.get(name); + if (marker == null && createIfMissing) { + lock.readLock().unlock(); + lock.writeLock().lock(); + try { + markerMap.putIfAbsent(name, new Marker(name)); + } finally { + lock.readLock().lock(); + lock.writeLock().unlock(); + } + marker = markerMap.get(name); + } + return marker; + } finally { + lock.readLock().unlock(); + } + } + + public static Marker define(final String name) { + return define(name, new Marker[0]); + } + + /** + * Defines a Marker with the specified parents. The parents must have been previously created. + * If the the marker previously existed, its parents will be changed to match the list of + * parents provided and the previous marker instance will be returned. Otherwise a new marker + * will be created with the specified parents. + * + * @param name The name of the Marker. + * @param parents The name of the parent Marker. + * @return The Marker with the specified name. + * @throws IllegalArgumentException if the parent Marker does not exist. + */ + public static Marker define(final String name, final String... parents) { + final Marker[] parentMarkers = new Marker[parents.length]; + lock.writeLock().lock(); + try { + for (int i = 0; i < parents.length; i++) { + parentMarkers[i] = get(parents[i]); + } + return defineMarkerWithParents(name, parentMarkers); + } finally { + lock.writeLock().unlock(); + } + } + + /** + * Defines a Marker with the specified parents. If the the marker previously existed, its + * parents will be changed to match the list of parents provided and the previous marker + * instance will be returned. Otherwise a new marker will be created with the specified parents. + * * @param name The name of the Marker. - * @return true of this Marker or one of its ancestors matches the specified name, false otherwise. + * @param parent The parent Marker. + * @return The Marker with the specified name. */ - boolean isInstanceOf(String name); + public static Marker define(final String name, final Marker... parents) { + lock.writeLock().lock(); + try { + return defineMarkerWithParents(name, parents); + } finally { + lock.writeLock().unlock(); + } + } + + private static Marker defineMarkerWithParents(final String name, final Marker... parents) { + // it is assumed a write lock has already been acquired + Marker marker = markerMap.get(name); + if (marker == null) { + marker = new Marker(name, parents); + markerMap.put(name, marker); + } else if (marker.parents.size() != parents.length || marker.parents.containsAll(Arrays.asList(parents))) { + assertNoCircularDependency(marker, parents); + marker.parents.replaceAll(parents); + } + return marker; + } + + private static void assertNoCircularDependency(Marker marker, final Marker... parents) { + for (Marker parent : parents) { + if (parent.isInstanceOf(marker)) { + throw new IllegalArgumentException("Adding " + parent.name // + + " as a parent of " + marker.name + " would cause a circular reference"); + } + } + } + + public static boolean undefine(String name) { + lock.writeLock().lock(); + try { + final Marker marker = markerMap.get(name); + if (marker != null) { + for (Marker child : childrenOf(marker)) { + child.parents.remove(marker); + child.refreshAllParentNamesRecursively(); + } + marker.parents.clear(); + marker.allParentNames.clear(); + return true; + } + } finally { + lock.writeLock().unlock(); + } + return false; + } + + public static boolean hasChildren(final Marker marker) { + lock.readLock().lock(); + try { + for (final Marker existingMarker : markerMap.values()) { + if (existingMarker.getParents().contains(marker)) { + return true; + } + } + } finally { + lock.readLock().unlock(); + } + return false; + } + + public static Set childrenOf(final Marker marker) { + lock.readLock().lock(); + try { + final Set result = new HashSet(); + for (final Marker existingMarker : markerMap.values()) { + if (existingMarker.getParents().contains(marker)) { + result.add(existingMarker); + } + } + return result; + } finally { + lock.readLock().unlock(); + } + } } Index: log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java =================================================================== --- log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java (revision 1583045) +++ log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java (working copy) @@ -1,173 +0,0 @@ -/* - * 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; - -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - - -/** - * Applications create Markers by using the Marker Manager. All Markers created by this Manager are - * immutable. - */ -public final class MarkerManager { - - private static ConcurrentMap markerMap = new ConcurrentHashMap(); - - private MarkerManager() { - } - - /** - * Retrieve a Marker or create a Marker that has no parent. - * @param name The name of the Marker. - * @return The Marker with the specified name. - */ - public static Marker getMarker(final String name) { - markerMap.putIfAbsent(name, new Log4jMarker(name)); - return markerMap.get(name); - } - - /** - * Retrieves or creates a Marker with the specified parent. The parent must have been previously created. - * @param name The name of the Marker. - * @param parent The name of the parent Marker. - * @return The Marker with the specified name. - * @throws IllegalArgumentException if the parent Marker does not exist. - */ - public static Marker getMarker(final String name, final String parent) { - final Marker parentMarker = markerMap.get(parent); - if (parentMarker == null) { - throw new IllegalArgumentException("Parent Marker " + parent + " has not been defined"); - } - return getMarker(name, parentMarker); - } - - /** - * Retrieves or creates a Marker with the specified parent. - * @param name The name of the Marker. - * @param parent The parent Marker. - * @return The Marker with the specified name. - */ - public static Marker getMarker(final String name, final Marker parent) { - markerMap.putIfAbsent(name, new Log4jMarker(name, parent)); - return markerMap.get(name); - } - - /** - * The actual Marker implementation. - */ - private static class Log4jMarker implements Marker { - - private static final long serialVersionUID = 100L; - - private final String name; - private final Marker parent; - - public Log4jMarker(final String name) { - this.name = name; - this.parent = null; - } - - public Log4jMarker(final String name, final Marker parent) { - this.name = name; - this.parent = parent; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public Marker getParent() { - return this.parent; - } - - @Override - public boolean isInstanceOf(final Marker marker) { - if (marker == null) { - throw new IllegalArgumentException("A marker parameter is required"); - } - Marker test = this; - do { - if (test == marker) { - return true; - } - test = test.getParent(); - } while (test != null); - return false; - } - - @Override - public boolean isInstanceOf(final String markerName) { - if (markerName == null) { - throw new IllegalArgumentException("A marker name is required"); - } - Marker toTest = this; - do { - if (markerName.equals(toTest.getName())) { - return true; - } - toTest = toTest.getParent(); - } while (toTest != null); - return false; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || !(o instanceof Marker)) { - return false; - } - - final Marker marker = (Marker) o; - - if (name != null ? !name.equals(marker.getName()) : marker.getName() != null) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return name != null ? name.hashCode() : 0; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder(name); - if (parent != null) { - Marker m = parent; - sb.append("[ "); - boolean first = true; - while (m != null) { - if (!first) { - sb.append(", "); - } - sb.append(m.getName()); - first = false; - m = m.getParent(); - } - sb.append(" ]"); - } - return sb.toString(); - } - } -} Index: log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java =================================================================== --- log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java (revision 1583045) +++ log4j-api/src/main/java/org/apache/logging/log4j/EventLogger.java (working copy) @@ -29,7 +29,7 @@ /** * Define the Event Marker. */ - public static final Marker EVENT_MARKER = MarkerManager.getMarker("EVENT"); + public static final Marker EVENT_MARKER = Marker.define("EVENT"); private static final String FQCN = EventLogger.class.getName(); Index: log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/MarkerTest.java =================================================================== --- log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/MarkerTest.java (revision 1584342) +++ log4j-slf4j-impl/src/test/java/org/apache/logging/slf4j/MarkerTest.java (working copy) @@ -16,12 +16,11 @@ */ package org.apache.logging.slf4j; +import static org.junit.Assert.assertTrue; + import org.apache.logging.log4j.Marker; -import org.apache.logging.log4j.MarkerManager; +import org.apache.logging.slf4j.Log4jMarkerFactory.Slf4jMarker; import org.junit.Test; -import org.slf4j.helpers.MarkerWrapper; - -import static org.junit.Assert.assertTrue; /** * @@ -30,14 +29,20 @@ @Test public void testMarker() { - final org.slf4j.Marker slf4jMarker = org.slf4j.MarkerFactory.getMarker("TEST"); - final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker("PARENT"); - slf4jMarker.add(slf4jParent); - final Marker log4jParent = MarkerManager.getMarker("PARENT"); - final Marker log4jMarker = MarkerManager.getMarker("TEST", log4jParent); + final Marker log4jParent = Marker.define("PARENT"); + final Marker log4jChildA = Marker.define("CHILD_A", log4jParent); - assertTrue("Incorrect Marker class", slf4jMarker instanceof MarkerWrapper); - assertTrue("SLF4J Marker doesn't match Log4j Marker", ((MarkerWrapper) slf4jMarker).isInstanceOf(log4jMarker)); - assertTrue("SLF4J Parent doesn't match Log4j parent", ((MarkerWrapper) slf4jMarker).isInstanceOf(log4jParent)); + final org.slf4j.Marker slf4jParent = org.slf4j.MarkerFactory.getMarker("PARENT"); + final org.slf4j.Marker slf4jChildA = org.slf4j.MarkerFactory.getMarker("CHILD_A"); + final org.slf4j.Marker slf4jChildB = org.slf4j.MarkerFactory.getDetachedMarker("CHILD_B"); + slf4jParent.add(slf4jChildB); + + final Marker log4jChildB = Marker.get("CHILD_B", false); + + assertTrue("slf4jParent type", slf4jParent instanceof Slf4jMarker); + assertTrue("slf4jParent contains childA", slf4jParent.contains(slf4jChildA)); + assertTrue("slf4jParent contains childB", slf4jParent.contains("CHILD_B")); + assertTrue("childA has log4jParent", log4jChildA.isInstanceOf("PARENT")); + assertTrue("childB has log4jParent", log4jChildB.isInstanceOf(log4jParent)); } } Index: log4j-slf4j-impl/src/main/java/org/slf4j/helpers/package-info.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/slf4j/helpers/package-info.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/slf4j/helpers/package-info.java (working copy) @@ -1,20 +0,0 @@ -/* - * 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. - */ -/** - * Log4j 2.0 SLF4J adapter helper classes. - */ -package org.slf4j.helpers; Index: log4j-slf4j-impl/src/main/java/org/slf4j/helpers/MarkerWrapper.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/slf4j/helpers/MarkerWrapper.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/slf4j/helpers/MarkerWrapper.java (working copy) @@ -1,68 +0,0 @@ -/* - * 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.slf4j.helpers; - -import org.apache.logging.log4j.Marker; - -/** - * - */ -public class MarkerWrapper extends BasicMarker implements Marker { - private static final long serialVersionUID = 1903952589649545191L; - - private MarkerWrapper parent; - - public MarkerWrapper(final String name) { - super(name); - } - - @Override - public void add(final org.slf4j.Marker reference) { - super.add(reference); - ((MarkerWrapper) reference).setParent(this); - } - - private void setParent(final MarkerWrapper marker) { - parent = marker; - } - - @Override - public Marker getParent() { - return this.parent; - } - - @Override - public boolean isInstanceOf(final Marker marker) { - if (marker == null) { - throw new IllegalArgumentException("A marker parameter is required"); - } - - if (marker instanceof MarkerWrapper) { - return contains((MarkerWrapper) marker); - } else { - return contains(marker.getName()); - } - } - - @Override - public boolean isInstanceOf(final String name) { - if (name == null) { - throw new IllegalArgumentException("A marker name is required"); - } - return contains(name); - } -} Index: log4j-slf4j-impl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/slf4j/impl/StaticMarkerBinder.java (working copy) @@ -16,13 +16,12 @@ */ package org.slf4j.impl; -import org.slf4j.IMarkerFactory; import org.apache.logging.slf4j.Log4jMarkerFactory; +import org.slf4j.IMarkerFactory; import org.slf4j.spi.MarkerFactoryBinder; /** - * SLF4J MarkerFactoryBinder implementation using Log4j. This class is part of the required classes used to specify an - * SLF4J logging provider implementation. + * */ public class StaticMarkerBinder implements MarkerFactoryBinder { Index: log4j-slf4j-impl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/slf4j/impl/StaticLoggerBinder.java (working copy) @@ -16,13 +16,12 @@ */ package org.slf4j.impl; -import org.slf4j.ILoggerFactory; import org.apache.logging.slf4j.Log4jLoggerFactory; +import org.slf4j.ILoggerFactory; import org.slf4j.spi.LoggerFactoryBinder; /** - * SLF4J LoggerFactoryBinder implementation using Log4j. This class is part of the required classes used to specify an - * SLF4J logger provider implementation. + * */ public final class StaticLoggerBinder implements LoggerFactoryBinder { Index: log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/SLF4JLoggingException.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/SLF4JLoggingException.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/SLF4JLoggingException.java (working copy) @@ -1,41 +0,0 @@ -/* - * 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.slf4j; - -/** - * Exception thrown when the SLF4J adapter encounters a problem. - * - */ -public class SLF4JLoggingException extends RuntimeException { - - /** - * Generated serial version ID. - */ - private static final long serialVersionUID = -1618650972455089998L; - - public SLF4JLoggingException(final String msg) { - super(msg); - } - - public SLF4JLoggingException(final String msg, final Exception ex) { - super(msg, ex); - } - - public SLF4JLoggingException(final Exception ex) { - super(ex); - } -} Index: log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jLogger.java (working copy) @@ -27,6 +27,7 @@ import org.apache.logging.log4j.message.ParameterizedMessage; import org.apache.logging.log4j.message.SimpleMessage; import org.apache.logging.log4j.spi.LoggerProvider; +import org.apache.logging.slf4j.Log4jMarkerFactory.Slf4jMarker; import org.slf4j.Marker; import org.slf4j.MarkerFactory; import org.slf4j.spi.LocationAwareLogger; @@ -84,32 +85,32 @@ @Override public boolean isTraceEnabled(final Marker marker) { - return logger.isEnabled(Level.TRACE, (org.apache.logging.log4j.Marker) marker, null); + return logger.isEnabled(Level.TRACE, ((Slf4jMarker) marker).getMarker(), null); } @Override public void trace(final Marker marker, final String s) { - logger.logIfEnabled(FQCN, Level.TRACE, (org.apache.logging.log4j.Marker) marker, s); + logger.logIfEnabled(FQCN, Level.TRACE, ((Slf4jMarker) marker).getMarker(), s); } @Override public void trace(final Marker marker, final String s, final Object o) { - logger.logIfEnabled(FQCN, Level.TRACE, (org.apache.logging.log4j.Marker) marker, s, o); + logger.logIfEnabled(FQCN, Level.TRACE, ((Slf4jMarker) marker).getMarker(), s, o); } @Override public void trace(final Marker marker, final String s, final Object o, final Object o1) { - logger.logIfEnabled(FQCN, Level.TRACE, (org.apache.logging.log4j.Marker) marker, s, o, o1); + logger.logIfEnabled(FQCN, Level.TRACE, ((Slf4jMarker) marker).getMarker(), s, o, o1); } @Override public void trace(final Marker marker, final String s, final Object... objects) { - logger.logIfEnabled(FQCN, Level.TRACE, (org.apache.logging.log4j.Marker) marker, s, objects); + logger.logIfEnabled(FQCN, Level.TRACE, ((Slf4jMarker) marker).getMarker(), s, objects); } @Override public void trace(final Marker marker, final String s, final Throwable throwable) { - logger.logIfEnabled(FQCN, Level.TRACE, (org.apache.logging.log4j.Marker) marker, s, throwable); + logger.logIfEnabled(FQCN, Level.TRACE, ((Slf4jMarker) marker).getMarker(), s, throwable); } @Override @@ -144,32 +145,32 @@ @Override public boolean isDebugEnabled(final Marker marker) { - return logger.isEnabled(Level.DEBUG, (org.apache.logging.log4j.Marker) marker, null); + return logger.isEnabled(Level.DEBUG, ((Slf4jMarker) marker).getMarker(), null); } @Override public void debug(final Marker marker, final String s) { - logger.logIfEnabled(FQCN, Level.DEBUG, (org.apache.logging.log4j.Marker) marker, s); + logger.logIfEnabled(FQCN, Level.DEBUG, ((Slf4jMarker) marker).getMarker(), s); } @Override public void debug(final Marker marker, final String s, final Object o) { - logger.logIfEnabled(FQCN, Level.DEBUG, (org.apache.logging.log4j.Marker) marker, s, o); + logger.logIfEnabled(FQCN, Level.DEBUG, ((Slf4jMarker) marker).getMarker(), s, o); } @Override public void debug(final Marker marker, final String s, final Object o, final Object o1) { - logger.logIfEnabled(FQCN, Level.DEBUG, (org.apache.logging.log4j.Marker) marker, s, o, o1); + logger.logIfEnabled(FQCN, Level.DEBUG, ((Slf4jMarker) marker).getMarker(), s, o, o1); } @Override public void debug(final Marker marker, final String s, final Object... objects) { - logger.logIfEnabled(FQCN, Level.DEBUG, (org.apache.logging.log4j.Marker) marker, s, objects); + logger.logIfEnabled(FQCN, Level.DEBUG, ((Slf4jMarker) marker).getMarker(), s, objects); } @Override public void debug(final Marker marker, final String s, final Throwable throwable) { - logger.logIfEnabled(FQCN, Level.DEBUG, (org.apache.logging.log4j.Marker) marker, s, throwable); + logger.logIfEnabled(FQCN, Level.DEBUG, ((Slf4jMarker) marker).getMarker(), s, throwable); } @Override @@ -204,32 +205,32 @@ @Override public boolean isInfoEnabled(final Marker marker) { - return logger.isEnabled(Level.INFO, (org.apache.logging.log4j.Marker) marker, null); + return logger.isEnabled(Level.INFO, ((Slf4jMarker) marker).getMarker(), null); } @Override public void info(final Marker marker, final String s) { - logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker) marker, s); + logger.logIfEnabled(FQCN, Level.INFO, ((Slf4jMarker) marker).getMarker(), s); } @Override public void info(final Marker marker, final String s, final Object o) { - logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker) marker, s, o); + logger.logIfEnabled(FQCN, Level.INFO, ((Slf4jMarker) marker).getMarker(), s, o); } @Override public void info(final Marker marker, final String s, final Object o, final Object o1) { - logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker) marker, s, o, o1); + logger.logIfEnabled(FQCN, Level.INFO, ((Slf4jMarker) marker).getMarker(), s, o, o1); } @Override public void info(final Marker marker, final String s, final Object... objects) { - logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker) marker, s, objects); + logger.logIfEnabled(FQCN, Level.INFO, ((Slf4jMarker) marker).getMarker(), s, objects); } @Override public void info(final Marker marker, final String s, final Throwable throwable) { - logger.logIfEnabled(FQCN, Level.INFO, (org.apache.logging.log4j.Marker) marker, s, throwable); + logger.logIfEnabled(FQCN, Level.INFO, ((Slf4jMarker) marker).getMarker(), s, throwable); } @Override @@ -264,32 +265,32 @@ @Override public boolean isWarnEnabled(final Marker marker) { - return logger.isEnabled(Level.WARN, (org.apache.logging.log4j.Marker) marker, null); + return logger.isEnabled(Level.WARN, ((Slf4jMarker) marker).getMarker(), null); } @Override public void warn(final Marker marker, final String s) { - logger.logIfEnabled(FQCN, Level.WARN, (org.apache.logging.log4j.Marker) marker, s); + logger.logIfEnabled(FQCN, Level.WARN, ((Slf4jMarker) marker).getMarker(), s); } @Override public void warn(final Marker marker, final String s, final Object o) { - logger.logIfEnabled(FQCN, Level.WARN, (org.apache.logging.log4j.Marker) marker, s, o); + logger.logIfEnabled(FQCN, Level.WARN, ((Slf4jMarker) marker).getMarker(), s, o); } @Override public void warn(final Marker marker, final String s, final Object o, final Object o1) { - logger.logIfEnabled(FQCN, Level.WARN, (org.apache.logging.log4j.Marker) marker, s, o, o1); + logger.logIfEnabled(FQCN, Level.WARN, ((Slf4jMarker) marker).getMarker(), s, o, o1); } @Override public void warn(final Marker marker, final String s, final Object... objects) { - logger.logIfEnabled(FQCN, Level.WARN, (org.apache.logging.log4j.Marker) marker, s, objects); + logger.logIfEnabled(FQCN, Level.WARN, ((Slf4jMarker) marker).getMarker(), s, objects); } @Override public void warn(final Marker marker, final String s, final Throwable throwable) { - logger.logIfEnabled(FQCN, Level.WARN, (org.apache.logging.log4j.Marker) marker, s, throwable); + logger.logIfEnabled(FQCN, Level.WARN, ((Slf4jMarker) marker).getMarker(), s, throwable); } @Override @@ -324,38 +325,38 @@ @Override public boolean isErrorEnabled(final Marker marker) { - return logger.isEnabled(Level.ERROR, (org.apache.logging.log4j.Marker) marker, null); + return logger.isEnabled(Level.ERROR, ((Slf4jMarker) marker).getMarker(), null); } @Override public void error(final Marker marker, final String s) { - logger.logIfEnabled(FQCN, Level.ERROR, (org.apache.logging.log4j.Marker) marker, s); + logger.logIfEnabled(FQCN, Level.ERROR, ((Slf4jMarker) marker).getMarker(), s); } @Override public void error(final Marker marker, final String s, final Object o) { - logger.logIfEnabled(FQCN, Level.ERROR, (org.apache.logging.log4j.Marker) marker, s, o); + logger.logIfEnabled(FQCN, Level.ERROR, ((Slf4jMarker) marker).getMarker(), s, o); } @Override public void error(final Marker marker, final String s, final Object o, final Object o1) { - logger.logIfEnabled(FQCN, Level.ERROR, (org.apache.logging.log4j.Marker) marker, s, o, o1); + logger.logIfEnabled(FQCN, Level.ERROR, ((Slf4jMarker) marker).getMarker(), s, o, o1); } @Override public void error(final Marker marker, final String s, final Object... objects) { - logger.logIfEnabled(FQCN, Level.ERROR, (org.apache.logging.log4j.Marker) marker, s, objects); + logger.logIfEnabled(FQCN, Level.ERROR, ((Slf4jMarker) marker).getMarker(), s, objects); } @Override public void error(final Marker marker, final String s, final Throwable throwable) { - logger.logIfEnabled(FQCN, Level.ERROR, (org.apache.logging.log4j.Marker) marker, s, throwable); + logger.logIfEnabled(FQCN, Level.ERROR, ((Slf4jMarker) marker).getMarker(), s, throwable); } @Override public void log(final Marker marker, final String fqcn, final int level, final String message, final Object[] params, Throwable throwable) { final Level log4jLevel = getLevel(level); - final org.apache.logging.log4j.Marker log4jMarker = (org.apache.logging.log4j.Marker) marker; + final org.apache.logging.log4j.Marker log4jMarker = ((Slf4jMarker) marker).getMarker(); if (!logger.isEnabled(log4jLevel, log4jMarker, message, params)) { return; Index: log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jMarkerFactory.java =================================================================== --- log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jMarkerFactory.java (revision 1584342) +++ log4j-slf4j-impl/src/main/java/org/apache/logging/slf4j/Log4jMarkerFactory.java (working copy) @@ -16,46 +16,241 @@ */ package org.apache.logging.slf4j; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.TreeSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import org.apache.logging.log4j.Marker; import org.slf4j.IMarkerFactory; -import org.slf4j.Marker; -import org.slf4j.helpers.MarkerWrapper; /** * */ public class Log4jMarkerFactory implements IMarkerFactory { - private final ConcurrentMap markerMap = new ConcurrentHashMap(); + private final ConcurrentMap markerMap = new ConcurrentHashMap(); @Override - public Marker getMarker(final String name) { + public org.slf4j.Marker getMarker(final String name) { if (name == null) { throw new IllegalArgumentException("Marker name must not be null"); } - Marker marker = markerMap.get(name); - if (marker != null) { - return marker; + org.slf4j.Marker marker = markerMap.get(name); + if (marker == null) { + markerMap.putIfAbsent(name, new Slf4jMarker(Marker.get(name))); + marker = markerMap.get(name); } - marker = new MarkerWrapper(name); - final Marker existing = markerMap.putIfAbsent(name, marker); - return existing == null ? marker : existing; + return marker; } @Override public boolean exists(final String name) { - return markerMap.containsKey(name); + return Marker.get(name, false) != null; } @Override public boolean detachMarker(final String name) { - return false; + return Marker.undefine(name); } @Override - public Marker getDetachedMarker(final String name) { - return new MarkerWrapper(name); + public org.slf4j.Marker getDetachedMarker(final String name) { + return new Slf4jMarker(name); + } + + class Slf4jMarker implements org.slf4j.Marker { + private static final long serialVersionUID = 1L; + + private final String name; + private ConcurrentMap references; + private Marker marker; + + Slf4jMarker(final Marker marker) { + this.name = marker.getName(); + this.marker = marker; + } + + Slf4jMarker(final String name) { + this.name = name; + this.references = new ConcurrentHashMap(); + } + + @Override + public String getName() { + return name; + } + + Marker getMarker() { + return marker; + } + + private boolean isDetached() { + return marker == null; + } + + @Override + public boolean contains(final org.slf4j.Marker reference) { + final Slf4jMarker ref = assertMarkerType(reference); + if (nameMatches(ref.name)) { + return true; + } else if (isDetached()) { + for (final org.slf4j.Marker existing : references.values()) { + if (existing.contains(ref)) { + return true; + } + } + } + return ref.marker.isInstanceOf(marker); + } + + @Override + public boolean contains(final String name) { + if (nameMatches(name)) { + return true; + } else if (isDetached()) { + for (final org.slf4j.Marker reference : references.values()) { + if (reference.contains(name)) { + return true; + } + } + } + final Marker contained = Marker.get(name, false); + if (contained != null) { + return contained.isInstanceOf(marker); + } + return false; + } + + @Override + public boolean hasChildren() { + return hasReferences(); + } + + @Override + public boolean hasReferences() { + return !Marker.hasChildren(marker); + } + + @Override + public Iterator iterator() { + final Iterator childIterator = Marker.childrenOf(marker).iterator(); + return new Iterator() { + + @Override + public boolean hasNext() { + return childIterator.hasNext(); + } + + @Override + public org.slf4j.Marker next() { + final Marker marker = childIterator.next(); + final String markerName = marker.getName(); + final org.slf4j.Marker cached = markerMap.get(markerName); + if (cached == null) { + markerMap.putIfAbsent(markerName, new Slf4jMarker(marker)); + return markerMap.get(markerName); + } + return cached; + } + + @Override + public void remove() { + childIterator.remove(); + } + }; + } + + @Override + public void add(final org.slf4j.Marker reference) { + final Slf4jMarker ref = assertMarkerType(reference); + if (isDetached()) { + references.putIfAbsent(reference.getName(), ref); + } else if (ref.isDetached()) { + ref.attachTo(marker); + } else { + ref.marker.getParents().add(marker); + } + } + + @Override + public boolean remove(final org.slf4j.Marker reference) { + final Slf4jMarker ref = assertMarkerType(reference); + if (isDetached()) { + return references.remove(ref.name) != null; + } + return ref.marker.getParents().remove(marker); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null || !(obj instanceof org.slf4j.Marker)) { + return false; + } + final org.slf4j.Marker that = (org.slf4j.Marker) obj; + return this.name == null ? that.getName() == null : this.name.equals(that.getName()); + } + + @Override + public int hashCode() { + return name == null ? 0 : name.hashCode(); + } + + @Override + public String toString() { + final StringBuilder result = new StringBuilder(name); + if (isDetached()) { + appendChildNames(result, references.keySet()); + } else { + final List children = new LinkedList(); + for (Marker child : Marker.childrenOf(marker)) { + children.add(child.getName()); + } + appendChildNames(result, children); + } + return result.toString(); + } + + private void appendChildNames(final StringBuilder result, final Collection names) { + if (!names.isEmpty()) { + result.append(' ').append('['); + boolean first = true; + for (final String refName : new TreeSet(names)) { + if (!first) { + result.append(',').append(' '); + } + result.append(refName); + } + result.append(']'); + } + } + + private boolean nameMatches(final String otherName) { + return name == null ? otherName == null : name.equals(otherName); + } + + private void attachTo(final Marker existingParent) { + marker = Marker.define(name, existingParent); + for (final Slf4jMarker ref : references.values()) { + if (ref.isDetached()) { + ref.attachTo(marker); + } else { + ref.marker.getParents().add(marker); + } + } + } + + private Slf4jMarker assertMarkerType(final org.slf4j.Marker marker) { + if (!(marker instanceof Slf4jMarker)) { + throw new IllegalArgumentException("Invalid marker type provided"); + } + return (Slf4jMarker) marker; + } } }