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 */
017package org.apache.logging.log4j;
018
019import java.util.concurrent.ConcurrentHashMap;
020import java.util.concurrent.ConcurrentMap;
021
022
023/**
024 * Applications create Markers by using the Marker Manager. All Markers created by this Manager are
025 * immutable.
026 */
027public final class MarkerManager {
028
029    private static ConcurrentMap<String, Marker> markerMap = new ConcurrentHashMap<String, Marker>();
030
031    private MarkerManager() {
032    }
033
034    /**
035     * Retrieve a Marker or create a Marker that has no parent.
036     * @param name The name of the Marker.
037     * @return The Marker with the specified name.
038     */
039    public static Marker getMarker(final String name) {
040        markerMap.putIfAbsent(name, new Log4jMarker(name));
041        return markerMap.get(name);
042    }
043
044    /**
045     * Retrieves or creates a Marker with the specified parent. The parent must have been previously created.
046     * @param name The name of the Marker.
047     * @param parent The name of the parent Marker.
048     * @return The Marker with the specified name.
049     * @throws IllegalArgumentException if the parent Marker does not exist.
050     */
051    public static Marker getMarker(final String name, final String parent) {
052        final Marker parentMarker = markerMap.get(parent);
053        if (parentMarker == null) {
054            throw new IllegalArgumentException("Parent Marker " + parent + " has not been defined");
055        }
056        return getMarker(name, parentMarker);
057    }
058
059    /**
060     * Retrieves or creates a Marker with the specified parent.
061     * @param name The name of the Marker.
062     * @param parent The parent Marker.
063     * @return The Marker with the specified name.
064     */
065    public static Marker getMarker(final String name, final Marker parent) {
066        markerMap.putIfAbsent(name, new Log4jMarker(name, parent));
067        return markerMap.get(name);
068    }
069
070    /**
071     * The actual Marker implementation.
072     */
073    private static class Log4jMarker implements Marker {
074
075        private static final long serialVersionUID = 100L;
076
077        private final String name;
078        private final Marker parent;
079
080        public Log4jMarker(final String name) {
081            this.name = name;
082            this.parent = null;
083        }
084
085        public Log4jMarker(final String name, final Marker parent) {
086            this.name = name;
087            this.parent = parent;
088        }
089
090        @Override
091        public String getName() {
092            return this.name;
093        }
094
095        @Override
096        public Marker getParent() {
097            return this.parent;
098        }
099
100        @Override
101        public boolean isInstanceOf(final Marker m) {
102            if (m == null) {
103                throw new IllegalArgumentException("A marker parameter is required");
104            }
105            Marker test = this;
106            do {
107                if (test == m) {
108                    return true;
109                }
110                test = test.getParent();
111            } while (test != null);
112            return false;
113        }
114
115        @Override
116        public boolean isInstanceOf(final String name) {
117            if (name == null) {
118                throw new IllegalArgumentException("A marker name is required");
119            }
120            Marker toTest = this;
121            do {
122                if (name.equals(toTest.getName())) {
123                    return true;
124                }
125                toTest = toTest.getParent();
126            } while (toTest != null);
127            return false;
128        }
129
130        @Override
131        public boolean equals(final Object o) {
132            if (this == o) {
133                return true;
134            }
135            if (o == null || !(o instanceof Marker)) {
136                return false;
137            }
138
139            final Marker marker = (Marker) o;
140
141            if (name != null ? !name.equals(marker.getName()) : marker.getName() != null) {
142                return false;
143            }
144
145            return true;
146        }
147
148        @Override
149        public int hashCode() {
150            return name != null ? name.hashCode() : 0;
151        }
152
153        @Override
154        public String toString() {
155            final StringBuilder sb = new StringBuilder(name);
156            if (parent != null) {
157                Marker m = parent;
158                sb.append("[ ");
159                boolean first = true;
160                while (m != null) {
161                    if (!first) {
162                        sb.append(", ");
163                    }
164                    sb.append(m.getName());
165                    first = false;
166                    m = m.getParent();
167                }
168                sb.append(" ]");
169            }
170            return sb.toString();
171        }
172    }
173}