@Override public void accept(final String key, final Object value, final StringMap contextData) { contextData.putValue(key, value); } };
@Override public Map<String, String> getImmutableMapOrNull() { final StringMap map = localMap.get(); return map == null ? null : Collections.unmodifiableMap(map.toMap()); }
@Override public void clear() { final StringMap map = localMap.get(); if (map != null) { map.clear(); } }
private void testContextDataInjector() { ReadOnlyThreadContextMap readOnlythreadContextMap = getThreadContextMap(); assertThat("thread context map class name", (readOnlythreadContextMap == null) ? null : readOnlythreadContextMap.getClass().getName(), is(equalTo(readOnlythreadContextMapClassName))); ContextDataInjector contextDataInjector = createInjector(); StringMap stringMap = contextDataInjector.injectContextData(null, new SortedArrayStringMap()); assertThat("thread context map", ThreadContext.getContext(), allOf(hasEntry("foo", "bar"), not(hasKey("baz")))); assertThat("context map", stringMap.toMap(), allOf(hasEntry("foo", "bar"), not(hasKey("baz")))); if (!stringMap.isFrozen()) { stringMap.clear(); assertThat("thread context map", ThreadContext.getContext(), allOf(hasEntry("foo", "bar"), not(hasKey("baz")))); assertThat("context map", stringMap.toMap().entrySet(), is(empty())); } ThreadContext.put("foo", "bum"); ThreadContext.put("baz", "bam"); assertThat("thread context map", ThreadContext.getContext(), allOf(hasEntry("foo", "bum"), hasEntry("baz", "bam"))); if (stringMap.isFrozen()) { assertThat("context map", stringMap.toMap(), allOf(hasEntry("foo", "bar"), not(hasKey("baz")))); } else { assertThat("context map", stringMap.toMap().entrySet(), is(empty())); } }
@Override public boolean isEmpty() { final StringMap map = localMap.get(); return map == null || map.size() == 0; }
/** * Release references held by ring buffer to allow objects to be garbage-collected. */ public void clear() { this.asyncLogger = null; this.loggerName = null; this.marker = null; this.fqcn = null; this.level = null; this.message = null; this.thrown = null; this.thrownProxy = null; this.contextStack = null; this.location = null; if (contextData != null) { if (contextData.isFrozen()) { // came from CopyOnWrite thread context contextData = null; } else { contextData.clear(); } } // ensure that excessively long char[] arrays are not kept in memory forever StringBuilders.trimToMaxSize(messageText, Constants.MAX_REUSABLE_MESSAGE_SIZE); if (parameters != null) { for (int i = 0; i < parameters.length; i++) { parameters[i] = null; } } }
@Override public int hashCode() { final int prime = 31; int result = 1; final StringMap map = this.localMap.get(); result = prime * result + ((map == null) ? 0 : map.hashCode()); return result; }
@Override public <V> V getValue(final String key) { final StringMap map = localMap.get(); return map == null ? null : map.<V>getValue(key); }
/** * If there are no configuration properties, this injector will return the thread context's internal data * structure. Otherwise the configuration properties are combined with the thread context key-value pairs into the * specified reusable StringMap. * * @param props list of configuration properties, may be {@code null} * @param ignore a {@code StringMap} instance from the log event * @return a {@code StringMap} combining configuration properties with thread context data */ @Override public StringMap injectContextData(final List<Property> props, final StringMap ignore) { // If there are no configuration properties we want to just return the ThreadContext's StringMap: // it is a copy-on-write data structure so we are sure ThreadContext changes will not affect our copy. final StringMap immutableCopy = ThreadContext.getThreadContextMap().getReadOnlyContextData(); if (props == null || props.isEmpty()) { return immutableCopy; // this will replace the LogEvent's context data with the returned instance } // However, if the list of Properties is non-empty we need to combine the properties and the ThreadContext // data. Note that we cannot reuse the specified StringMap: some Loggers may have properties defined // and others not, so the LogEvent's context data may have been replaced with an immutable copy from // the ThreadContext - this will throw an UnsupportedOperationException if we try to modify it. final StringMap result = ContextDataFactory.createContextData(props.size() + immutableCopy.size()); copyProperties(props, result); result.putAll(immutableCopy); return result; }
@Override protected StringMap childValue(final StringMap parentValue) { if (parentValue == null) { return null; } StringMap stringMap = createStringMap(parentValue); stringMap.freeze(); return stringMap; } };
@Override public boolean containsKey(final String key) { final StringMap map = localMap.get(); return map != null && map.containsKey(key); }
private static StringMap memento(final ReadOnlyStringMap data) { final StringMap result = ContextDataFactory.createContextData(); result.putAll(data); return result; }
@Override public void putAll(final Map<String, String> values) { if (values == null || values.isEmpty()) { return; } StringMap map = localMap.get(); map = map == null ? createStringMap() : createStringMap(map); for (final Map.Entry<String, String> entry : values.entrySet()) { map.putValue(entry.getKey(), entry.getValue()); } map.freeze(); localMap.set(map); }
@Override public boolean isEmpty() { final StringMap map = localMap.get(); return map == null || map.size() == 0; }