/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache license, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the license for the specific language governing permissions and * limitations under the license. */ package org.ops4j.pax.logging.log4jv2; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.logging.log4j.spi.ThreadContextMap; import org.ops4j.pax.logging.OSGIPaxLoggingManager; import org.ops4j.pax.logging.PaxContext; import org.ops4j.pax.logging.PaxLoggingManager; import org.osgi.framework.BundleContext; /** * The actual ThreadContext Map. A new ThreadContext Map is created each time it is updated and the Map stored is always * immutable. This means the Map can be passed to other threads without concern that it will be updated. Since it is * expected that the Map will be passed to many more log events than the number of keys it contains the performance * should be much better than if the Map was copied for each event. */ public class Log4jv2ThreadContextMap implements ThreadContextMap { private static PaxContext m_context; private static PaxContext m_defaultContext = new PaxContext(); private static PaxLoggingManager m_paxLogging; public static void setBundleContext( BundleContext ctx ) { m_paxLogging = new OSGIPaxLoggingManager( ctx ); // We need to instruct all loggers to ensure the SimplePaxLoggingManager is replaced. m_paxLogging.open(); } public static void dispose() { } /** * For all the methods that operate against the context, return true if the MDC should use the PaxContext object from the PaxLoggingManager, * or if the logging manager is not set, or does not have its context available yet, use a default context local to this MDC. * @return m_context if the MDC should use the PaxContext object from the PaxLoggingManager, * or m_defaultContext if the logging manager is not set, or does not have its context available yet. */ private static PaxContext getContext() { if( m_context==null && m_paxLogging!=null ){ m_context=(m_paxLogging.getPaxLoggingService()!=null)?m_paxLogging.getPaxLoggingService().getPaxContext():null; } return m_context!=null?m_context:m_defaultContext; } @Override public void put(String key, String value) { getContext().put(key, value); } @Override public String get(String key) { Object obj = getContext().get(key); return obj != null ? obj.toString() : null; } @Override public void remove(String key) { getContext().remove(key); } @Override public void clear() { getContext().clear(); } @Override public boolean containsKey(String key) { return getContext().get(key) != null; } @Override public Map<String, String> getCopy() { final Map<String, Object> copy = getContext().getCopyOfContextMap(); if (copy == null) { return Collections.emptyMap(); } return new AbstractMap<String, String>() { @Override public Set<Entry<String, String>> entrySet() { return new AbstractSet<Entry<String, String>>() { final Set<Entry<String, Object>> set = copy.entrySet(); @Override public Iterator<Entry<String, String>> iterator() { return new Iterator<Entry<String, String>>() { Iterator<Entry<String, Object>> it = set.iterator(); @Override public boolean hasNext() { return it.hasNext(); } @Override public Entry<String, String> next() { Entry<String, Object> entry = it.next(); return new SimpleEntry<String, String>( entry.getKey(), entry.getValue() != null ? entry.getValue().toString() : null); } @Override public void remove() { // nothing to do } }; } @Override public int size() { return set.size(); } }; } }; } @Override public Map<String, String> getImmutableMapOrNull() { return getCopy(); } @Override public boolean isEmpty() { Map<String, Object> ctx = getContext().getContext(); return ctx == null || ctx.isEmpty(); } }