View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.spi;
18  
19  import java.util.Collections;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  /**
24   * The actual ThreadContext Map. A new ThreadContext Map is created each time it is updated and the Map stored
25   * is always immutable. This means the Map can be passed to other threads without concern that it will be updated.
26   * Since it is expected that the Map will be passed to many more log events than the number of keys it contains
27   * the performance should be much better than if the Map was copied for each event.
28   */
29  public class DefaultThreadContextMap implements ThreadContextMap {
30  
31      private final boolean useMap;
32  
33      private final ThreadLocal<Map<String, String>> localMap =
34          new InheritableThreadLocal<Map<String, String>>() {
35              @Override
36              protected Map<String, String> childValue(final Map<String, String> parentValue) {
37                  return parentValue == null || !useMap ? null :
38                      Collections.unmodifiableMap(new HashMap<String, String>(parentValue));
39              }
40          };
41  
42      public DefaultThreadContextMap(final boolean useMap) {
43          this.useMap = useMap;
44      }
45  
46      /**
47       * Put a context value (the <code>o</code> parameter) as identified
48       * with the <code>key</code> parameter into the current thread's
49       * context map.
50       * <p/>
51       * <p>If the current thread does not have a context map it is
52       * created as a side effect.
53       * @param key The key name.
54       * @param value The key value.
55       */
56      @Override
57      public void put(final String key, final String value) {
58          if (!useMap) {
59              return;
60          }
61          Map<String, String> map = localMap.get();
62          map = map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
63          map.put(key, value);
64          localMap.set(Collections.unmodifiableMap(map));
65      }
66  
67      /**
68       * Get the context identified by the <code>key</code> parameter.
69       * <p/>
70       * <p>This method has no side effects.
71       * @param key The key to locate.
72       * @return The value associated with the key or null.
73       */
74      @Override
75      public String get(final String key) {
76          final Map<String, String> map = localMap.get();
77          return map == null ? null : map.get(key);
78      }
79  
80      /**
81       * Remove the the context identified by the <code>key</code>
82       * parameter.
83       * @param key The key to remove.
84       */
85      @Override
86      public void remove(final String key) {
87          final Map<String, String> map = localMap.get();
88          if (map != null) {
89              final Map<String, String> copy = new HashMap<String, String>(map);
90              copy.remove(key);
91              localMap.set(Collections.unmodifiableMap(copy));
92          }
93      }
94  
95      /**
96       * Clear the context.
97       */
98      @Override
99      public void clear() {
100         localMap.remove();
101     }
102 
103     /**
104      * Determine if the key is in the context.
105      * @param key The key to locate.
106      * @return True if the key is in the context, false otherwise.
107      */
108     @Override
109     public boolean containsKey(final String key) {
110         final Map<String, String> map = localMap.get();
111         return map != null && map.containsKey(key);
112     }
113 
114     /**
115      * Returns a non-{@code null} mutable copy of the ThreadContext Map.
116      * @return a non-{@code null} mutable copy of the context.
117      */
118     @Override
119     public Map<String, String> getCopy() {
120         final Map<String, String> map = localMap.get();
121         return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
122     }
123 
124     /**
125      * Returns either {@code null} or an immutable view of the context Map.
126      * @return the Context Map.
127      */
128     @Override
129     public Map<String, String> getImmutableMapOrNull() {
130         return localMap.get();
131     }
132 
133     /**
134      * Returns true if the Map is empty.
135      * @return true if the Map is empty, false otherwise.
136      */
137     @Override
138     public boolean isEmpty() {
139         final Map<String, String> map = localMap.get();
140         return map == null || map.size() == 0;
141     }
142 }