1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.osgi;
18
19 import java.lang.ref.WeakReference;
20 import java.net.URI;
21 import java.util.Objects;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.atomic.AtomicReference;
24
25 import org.apache.logging.log4j.core.LoggerContext;
26 import org.apache.logging.log4j.core.impl.ContextAnchor;
27 import org.apache.logging.log4j.core.selector.ClassLoaderContextSelector;
28 import org.apache.logging.log4j.util.StackLocatorUtil;
29 import org.osgi.framework.Bundle;
30 import org.osgi.framework.BundleReference;
31 import org.osgi.framework.FrameworkUtil;
32
33
34
35
36
37
38
39
40 public class BundleContextSelector extends ClassLoaderContextSelector {
41
42 @Override
43 public void shutdown(final String fqcn, final ClassLoader loader, final boolean currentContext,
44 final boolean allContexts) {
45 LoggerContext ctx = null;
46 Bundle bundle = null;
47 if (currentContext) {
48 ctx = ContextAnchor.THREAD_CONTEXT.get();
49 ContextAnchor.THREAD_CONTEXT.remove();
50 }
51 if (ctx == null && loader instanceof BundleReference) {
52 bundle = ((BundleReference) loader).getBundle();
53 ctx = getLoggerContext(bundle);
54 removeLoggerContext(ctx);
55 }
56 if (ctx == null) {
57 final Class<?> callerClass = StackLocatorUtil.getCallerClass(fqcn);
58 if (callerClass != null) {
59 bundle = FrameworkUtil.getBundle(callerClass);
60 ctx = getLoggerContext(FrameworkUtil.getBundle(callerClass));
61 removeLoggerContext(ctx);
62 }
63 }
64 if (ctx == null) {
65 ctx = ContextAnchor.THREAD_CONTEXT.get();
66 ContextAnchor.THREAD_CONTEXT.remove();
67 }
68 if (ctx != null) {
69 ctx.stop(DEFAULT_STOP_TIMEOUT, TimeUnit.MILLISECONDS);
70 }
71 if (bundle != null && allContexts) {
72 final Bundle[] bundles = bundle.getBundleContext().getBundles();
73 for (final Bundle bdl : bundles) {
74 ctx = getLoggerContext(bdl);
75 if (ctx != null) {
76 ctx.stop(DEFAULT_STOP_TIMEOUT, TimeUnit.MILLISECONDS);
77 }
78 }
79 }
80 }
81 private LoggerContext getLoggerContext(final Bundle bundle) {
82 final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName();
83 final AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
84 if (ref != null && ref.get() != null) {
85 return ref.get().get();
86 }
87 return null;
88 }
89
90 private void removeLoggerContext(LoggerContext context) {
91 CONTEXT_MAP.remove(context.getName());
92 }
93
94 @Override
95 public boolean hasContext(final String fqcn, final ClassLoader loader, final boolean currentContext) {
96 if (currentContext && ContextAnchor.THREAD_CONTEXT.get() != null) {
97 return ContextAnchor.THREAD_CONTEXT.get().isStarted();
98 }
99 if (loader instanceof BundleReference) {
100 return hasContext(((BundleReference) loader).getBundle());
101 }
102 final Class<?> callerClass = StackLocatorUtil.getCallerClass(fqcn);
103 if (callerClass != null) {
104 return hasContext(FrameworkUtil.getBundle(callerClass));
105 }
106 return ContextAnchor.THREAD_CONTEXT.get() != null && ContextAnchor.THREAD_CONTEXT.get().isStarted();
107 }
108 @Override
109 public LoggerContext getContext(final String fqcn, final ClassLoader loader, final boolean currentContext,
110 final URI configLocation) {
111 if (currentContext) {
112 final LoggerContext ctx = ContextAnchor.THREAD_CONTEXT.get();
113 if (ctx != null) {
114 return ctx;
115 }
116 return getDefault();
117 }
118
119 if (loader instanceof BundleReference) {
120 return locateContext(((BundleReference) loader).getBundle(), configLocation);
121 }
122 final Class<?> callerClass = StackLocatorUtil.getCallerClass(fqcn);
123 if (callerClass != null) {
124 return locateContext(FrameworkUtil.getBundle(callerClass), configLocation);
125 }
126 final LoggerContext lc = ContextAnchor.THREAD_CONTEXT.get();
127 return lc == null ? getDefault() : lc;
128 }
129
130 private static boolean hasContext(final Bundle bundle) {
131 final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName();
132 final AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
133 return ref != null && ref.get() != null && ref.get().get() != null && ref.get().get().isStarted();
134 }
135
136 private static LoggerContext locateContext(final Bundle bundle, final URI configLocation) {
137 final String name = Objects.requireNonNull(bundle, "No Bundle provided").getSymbolicName();
138 final AtomicReference<WeakReference<LoggerContext>> ref = CONTEXT_MAP.get(name);
139 if (ref == null) {
140 final LoggerContext context = new LoggerContext(name, bundle, configLocation);
141 CONTEXT_MAP.putIfAbsent(name,
142 new AtomicReference<>(new WeakReference<>(context)));
143 return CONTEXT_MAP.get(name).get().get();
144 }
145 final WeakReference<LoggerContext> r = ref.get();
146 final LoggerContext ctx = r.get();
147 if (ctx == null) {
148 final LoggerContext context = new LoggerContext(name, bundle, configLocation);
149 ref.compareAndSet(r, new WeakReference<>(context));
150 return ref.get().get();
151 }
152 final URI oldConfigLocation = ctx.getConfigLocation();
153 if (oldConfigLocation == null && configLocation != null) {
154 LOGGER.debug("Setting bundle ({}) configuration to {}", name, configLocation);
155 ctx.setConfigLocation(configLocation);
156 } else if (oldConfigLocation != null && configLocation != null && !configLocation.equals(oldConfigLocation)) {
157 LOGGER.warn("locateContext called with URI [{}], but existing LoggerContext has URI [{}]",
158 configLocation, oldConfigLocation);
159 }
160 return ctx;
161 }
162 }