2 * SPDX-License-Identifier: LGPL-2.1-only
4 * Copyright (C) 2015 EfficiOS Inc.
5 * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
8 package org
.lttng
.ust
.agent
.context
;
10 import java
.io
.IOException
;
11 import java
.util
.HashMap
;
13 import java
.util
.concurrent
.ConcurrentHashMap
;
14 import java
.util
.regex
.Matcher
;
15 import java
.util
.regex
.Pattern
;
18 * The singleton manager of {@link IContextInfoRetriever} objects.
20 * @author Alexandre Montplaisir
22 public final class ContextInfoManager
{
24 private static final String SHARED_LIBRARY_NAME
= "lttng-ust-context-jni";
26 private static final Pattern VALID_CONTEXT_NAME_PATTERN
= Pattern
.compile("^[a-zA-Z0-9_\\.]+$");
28 private static ContextInfoManager instance
;
30 private final Map
<String
, IContextInfoRetriever
> contextInfoRetrievers
= new ConcurrentHashMap
<String
, IContextInfoRetriever
>();
31 private final Map
<String
, Long
> contextInforRetrieverRefs
= new HashMap
<String
, Long
>();
34 * Lock used to keep the two maps above in sync when retrievers are
35 * registered or unregistered.
37 private final Object retrieverLock
= new Object();
39 /** Singleton class, constructor should not be accessed directly */
40 private ContextInfoManager() {
44 * Get the singleton instance.
47 * Usage of this class requires the "liblttng-ust-context-jni.so" native
48 * library to be present on the system and available (passing
49 * -Djava.library.path=path to the JVM may be needed).
52 * @return The singleton instance
54 * If the shared library cannot be found.
55 * @throws SecurityException
56 * We will forward any SecurityExcepion that may be thrown when
57 * trying to load the JNI library.
59 public static synchronized ContextInfoManager
getInstance() throws IOException
, SecurityException
{
60 if (instance
== null) {
62 System
.loadLibrary(SHARED_LIBRARY_NAME
);
63 } catch (UnsatisfiedLinkError e
) {
64 throw new IOException(e
);
66 instance
= new ContextInfoManager();
72 * Register a new context info retriever.
75 * Each context info retriever is registered with a given "retriever name",
76 * which specifies the namespace of the context elements. This name is
77 * specified separately from the retriever objects, which would allow
78 * register the same retriever under different namespaces for example.
82 * If the method returns false (indicating registration failure), then the
83 * retriever object will *not* be used for context information.
86 * @param retrieverName
87 * The name to register to the context retriever object with.
88 * @param contextInfoRetriever
89 * The context info retriever to register
90 * @return True if the retriever was successfully registered, false if there
91 * was an error, for example if a retriever is already registered
94 public boolean registerContextInfoRetriever(String retrieverName
, IContextInfoRetriever contextInfoRetriever
) {
95 synchronized (retrieverLock
) {
96 if (!validateRetrieverName(retrieverName
)) {
100 if (contextInfoRetrievers
.containsKey(retrieverName
)) {
102 * There is already a retriever registered with that name,
103 * refuse the new registration.
108 * Inform LTTng-UST of the new retriever. The names have to start
109 * with "$app." on the UST side!
111 long ref
= LttngContextApi
.registerProvider("$app." + retrieverName
);
116 contextInfoRetrievers
.put(retrieverName
, contextInfoRetriever
);
117 contextInforRetrieverRefs
.put(retrieverName
, Long
.valueOf(ref
));
124 * Unregister a previously added context info retriever.
126 * This method has no effect if the retriever was not already registered.
128 * @param retrieverName
129 * The context info retriever to unregister
130 * @return True if unregistration was successful, false if there was an
133 public boolean unregisterContextInfoRetriever(String retrieverName
) {
134 synchronized (retrieverLock
) {
135 if (!contextInfoRetrievers
.containsKey(retrieverName
)) {
137 * There was no retriever registered with that name.
141 contextInfoRetrievers
.remove(retrieverName
);
142 long ref
= contextInforRetrieverRefs
.remove(retrieverName
).longValue();
144 /* Unregister the retriever on the UST side too */
145 LttngContextApi
.unregisterProvider(ref
);
152 * Return the context info retriever object registered with the given name.
154 * @param retrieverName
155 * The retriever name to look for
156 * @return The corresponding retriever object, or <code>null</code> if there
159 public IContextInfoRetriever
getContextInfoRetriever(String retrieverName
) {
161 * Note that this method does not take the retrieverLock, it lets
162 * concurrent threads access the ConcurrentHashMap directly.
164 * It's fine for a get() to happen during a registration or
165 * unregistration, it's first-come-first-serve.
167 return contextInfoRetrievers
.get(retrieverName
);
171 * Validate that the given retriever name contains only the allowed
172 * characters, which are alphanumerical characters, period "." and
173 * underscore "_". The name must also not start with a number.
175 private static boolean validateRetrieverName(String contextName
) {
176 if (contextName
.isEmpty()) {
180 /* First character must not be a number */
181 if (Character
.isDigit(contextName
.charAt(0))) {
185 /* Validate the other characters of the string */
186 Matcher matcher
= VALID_CONTEXT_NAME_PATTERN
.matcher(contextName
);
187 return matcher
.matches();