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.log4j.spi; 018 019 import java.util.Collections; 020 import java.util.HashMap; 021 import java.util.Map; 022 023 /** 024 * The actual ThreadContext Map. A new ThreadContext Map is created each time it is updated and the Map stored 025 * is always immutable. This means the Map can be passed to other threads without concern that it will be updated. 026 * Since it is expected that the Map will be passed to many more log events than the number of keys it contains 027 * the performance should be much better than if the Map was copied for each event. 028 */ 029 public class DefaultThreadContextMap implements ThreadContextMap { 030 031 private final boolean useMap; 032 033 private final ThreadLocal<Map<String, String>> localMap = 034 new InheritableThreadLocal<Map<String, String>>() { 035 @Override 036 protected Map<String, String> childValue(final Map<String, String> parentValue) { 037 return parentValue == null || !useMap ? null : 038 Collections.unmodifiableMap(new HashMap<String, String>(parentValue)); 039 } 040 }; 041 042 public DefaultThreadContextMap(final boolean useMap) { 043 this.useMap = useMap; 044 } 045 046 /** 047 * Put a context value (the <code>o</code> parameter) as identified 048 * with the <code>key</code> parameter into the current thread's 049 * context map. 050 * <p/> 051 * <p>If the current thread does not have a context map it is 052 * created as a side effect. 053 * @param key The key name. 054 * @param value The key value. 055 */ 056 @Override 057 public void put(final String key, final String value) { 058 if (!useMap) { 059 return; 060 } 061 Map<String, String> map = localMap.get(); 062 map = map == null ? new HashMap<String, String>() : new HashMap<String, String>(map); 063 map.put(key, value); 064 localMap.set(Collections.unmodifiableMap(map)); 065 } 066 067 /** 068 * Get the context identified by the <code>key</code> parameter. 069 * <p/> 070 * <p>This method has no side effects. 071 * @param key The key to locate. 072 * @return The value associated with the key or null. 073 */ 074 @Override 075 public String get(final String key) { 076 final Map<String, String> map = localMap.get(); 077 return map == null ? null : map.get(key); 078 } 079 080 /** 081 * Remove the the context identified by the <code>key</code> 082 * parameter. 083 * @param key The key to remove. 084 */ 085 @Override 086 public void remove(final String key) { 087 final Map<String, String> map = localMap.get(); 088 if (map != null) { 089 final Map<String, String> copy = new HashMap<String, String>(map); 090 copy.remove(key); 091 localMap.set(Collections.unmodifiableMap(copy)); 092 } 093 } 094 095 /** 096 * Clear the context. 097 */ 098 @Override 099 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 }