001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017 package org.apache.logging.slf4j;
018
019 import java.util.ArrayList;
020 import java.util.Collection;
021 import java.util.Iterator;
022 import java.util.concurrent.ConcurrentHashMap;
023 import java.util.concurrent.ConcurrentMap;
024
025 import org.apache.logging.log4j.Logger;
026 import org.apache.logging.log4j.MarkerManager;
027 import org.apache.logging.log4j.status.StatusLogger;
028 import org.slf4j.IMarkerFactory;
029 import org.slf4j.Marker;
030
031 /**
032 * Log4j/SLF4J bridge to create SLF4J Markers based on name or based on existing SLF4J Markers.
033 */
034 public class Log4jMarkerFactory implements IMarkerFactory {
035
036 private static final Logger LOGGER = StatusLogger.getLogger();
037
038 private final ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<String, Marker>();
039
040 /**
041 * Returns a Log4j Marker that is compatible with SLF4J.
042 * @param name The name of the Marker.
043 * @return A Marker.
044 */
045 @Override
046 public Marker getMarker(final String name) {
047 if (name == null) {
048 throw new IllegalArgumentException("Marker name must not be null");
049 }
050 final Marker marker = markerMap.get(name);
051 if (marker != null) {
052 return marker;
053 }
054 final org.apache.logging.log4j.Marker log4jMarker = MarkerManager.getMarker(name);
055 return addMarkerIfAbsent(name, log4jMarker);
056 }
057
058 private Marker addMarkerIfAbsent(final String name, final org.apache.logging.log4j.Marker log4jMarker) {
059 final Marker marker = new Log4jMarker(log4jMarker);
060 final Marker existing = markerMap.putIfAbsent(name, marker);
061 return existing == null ? marker : existing;
062 }
063
064 /**
065 * Returns a Log4j Marker converted from an existing custom SLF4J Marker.
066 * @param marker The SLF4J Marker to convert.
067 * @return A converted Log4j/SLF4J Marker.
068 * @since 2.1
069 */
070 public Marker getMarker(final Marker marker) {
071 if (marker == null) {
072 throw new IllegalArgumentException("Marker must not be null");
073 }
074 final Marker m = markerMap.get(marker.getName());
075 if (m != null) {
076 return m;
077 }
078 return addMarkerIfAbsent(marker.getName(), convertMarker(marker));
079 }
080
081 private static org.apache.logging.log4j.Marker convertMarker(final Marker original) {
082 if (original == null) {
083 throw new IllegalArgumentException("Marker must not be null");
084 }
085 return convertMarker(original, new ArrayList<Marker>());
086 }
087
088 private static org.apache.logging.log4j.Marker convertMarker(final Marker original,
089 final Collection<Marker> visited) {
090 final org.apache.logging.log4j.Marker marker = MarkerManager.getMarker(original.getName());
091 if (original.hasReferences()) {
092 final Iterator it = original.iterator();
093 while (it.hasNext()) {
094 final Marker next = (Marker) it.next();
095 if (visited.contains(next)) {
096 LOGGER.warn("Found a cycle in Marker [{}]. Cycle will be broken.", next.getName());
097 } else {
098 visited.add(next);
099 marker.addParents(convertMarker(next, visited));
100 }
101 }
102 }
103 return marker;
104 }
105
106 /**
107 * Returns true if the Marker exists.
108 * @param name The Marker name.
109 * @return {@code true} if the Marker exists, {@code false} otherwise.
110 */
111 @Override
112 public boolean exists(final String name) {
113 return markerMap.containsKey(name);
114 }
115
116 /**
117 * Log4j does not support detached Markers. This method always returns false.
118 * @param name The Marker name.
119 * @return {@code false}
120 */
121 @Override
122 public boolean detachMarker(final String name) {
123 return false;
124 }
125
126 /**
127 * Log4j does not support detached Markers for performance reasons. The returned Marker is attached.
128 * @param name The Marker name.
129 * @return The named Marker (unmodified).
130 */
131 @Override
132 public Marker getDetachedMarker(final String name) {
133 LOGGER.warn("Log4j does not support detached Markers. Returned Marker [{}] will be unchanged.", name);
134 return getMarker(name);
135 }
136
137
138 }