Move to kernel style SPDX license identifiers
[lttng-ust.git] / liblttng-ust-java-agent / java / lttng-ust-agent-common / org / lttng / ust / agent / context / ContextInfoManager.java
CommitLineData
27dbdc00 1/*
c0c0989a 2 * SPDX-License-Identifier: LGPL-2.1-only
27dbdc00 3 *
c0c0989a
MJ
4 * Copyright (C) 2015 EfficiOS Inc.
5 * Copyright (C) 2015 Alexandre Montplaisir <alexmonthy@efficios.com>
27dbdc00
AM
6 */
7
8package org.lttng.ust.agent.context;
9
8ab5c06b
AM
10import java.io.IOException;
11import java.util.HashMap;
12import java.util.Map;
13import java.util.concurrent.ConcurrentHashMap;
cad6b749
AM
14import java.util.regex.Matcher;
15import java.util.regex.Pattern;
27dbdc00
AM
16
17/**
18 * The singleton manager of {@link IContextInfoRetriever} objects.
19 *
20 * @author Alexandre Montplaisir
21 */
22public final class ContextInfoManager {
23
8ab5c06b 24 private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni";
27dbdc00 25
cad6b749
AM
26 private static final Pattern VALID_CONTEXT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\.]+$");
27
8ab5c06b
AM
28 private static ContextInfoManager instance;
29
30 private final Map<String, IContextInfoRetriever> contextInfoRetrievers = new ConcurrentHashMap<String, IContextInfoRetriever>();
31 private final Map<String, Long> contextInforRetrieverRefs = new HashMap<String, Long>();
32
831b4b08
AM
33 /**
34 * Lock used to keep the two maps above in sync when retrievers are
35 * registered or unregistered.
36 */
8ab5c06b 37 private final Object retrieverLock = new Object();
27dbdc00
AM
38
39 /** Singleton class, constructor should not be accessed directly */
40 private ContextInfoManager() {
41 }
42
43 /**
44 * Get the singleton instance.
45 *
8ab5c06b
AM
46 * <p>
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).
50 * </p>
51 *
27dbdc00 52 * @return The singleton instance
8ab5c06b
AM
53 * @throws IOException
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.
27dbdc00 58 */
8ab5c06b
AM
59 public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException {
60 if (instance == null) {
61 try {
62 System.loadLibrary(SHARED_LIBRARY_NAME);
63 } catch (UnsatisfiedLinkError e) {
64 throw new IOException(e);
65 }
66 instance = new ContextInfoManager();
67 }
68 return instance;
27dbdc00
AM
69 }
70
71 /**
72 * Register a new context info retriever.
73 *
8ab5c06b
AM
74 * <p>
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.
79 * </p>
80 *
81 * <p>
82 * If the method returns false (indicating registration failure), then the
83 * retriever object will *not* be used for context information.
84 * </p>
27dbdc00 85 *
8ab5c06b
AM
86 * @param retrieverName
87 * The name to register to the context retriever object with.
88 * @param contextInfoRetriever
27dbdc00 89 * The context info retriever to register
8ab5c06b
AM
90 * @return True if the retriever was successfully registered, false if there
91 * was an error, for example if a retriever is already registered
92 * with that name.
27dbdc00 93 */
8ab5c06b
AM
94 public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) {
95 synchronized (retrieverLock) {
cad6b749
AM
96 if (!validateRetrieverName(retrieverName)) {
97 return false;
98 }
99
8ab5c06b
AM
100 if (contextInfoRetrievers.containsKey(retrieverName)) {
101 /*
102 * There is already a retriever registered with that name,
103 * refuse the new registration.
104 */
105 return false;
106 }
107 /*
108 * Inform LTTng-UST of the new retriever. The names have to start
109 * with "$app." on the UST side!
110 */
111 long ref = LttngContextApi.registerProvider("$app." + retrieverName);
112 if (ref == 0) {
113 return false;
114 }
115
116 contextInfoRetrievers.put(retrieverName, contextInfoRetriever);
117 contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref));
118
119 return true;
120 }
27dbdc00
AM
121 }
122
123 /**
124 * Unregister a previously added context info retriever.
125 *
126 * This method has no effect if the retriever was not already registered.
127 *
8ab5c06b 128 * @param retrieverName
27dbdc00 129 * The context info retriever to unregister
8ab5c06b
AM
130 * @return True if unregistration was successful, false if there was an
131 * error
27dbdc00 132 */
8ab5c06b
AM
133 public boolean unregisterContextInfoRetriever(String retrieverName) {
134 synchronized (retrieverLock) {
135 if (!contextInfoRetrievers.containsKey(retrieverName)) {
136 /*
137 * There was no retriever registered with that name.
138 */
139 return false;
140 }
141 contextInfoRetrievers.remove(retrieverName);
142 long ref = contextInforRetrieverRefs.remove(retrieverName).longValue();
143
144 /* Unregister the retriever on the UST side too */
145 LttngContextApi.unregisterProvider(ref);
146
147 return true;
148 }
27dbdc00
AM
149 }
150
151 /**
8ab5c06b 152 * Return the context info retriever object registered with the given name.
27dbdc00 153 *
8ab5c06b
AM
154 * @param retrieverName
155 * The retriever name to look for
156 * @return The corresponding retriever object, or <code>null</code> if there
157 * was none
27dbdc00 158 */
8ab5c06b 159 public IContextInfoRetriever getContextInfoRetriever(String retrieverName) {
831b4b08
AM
160 /*
161 * Note that this method does not take the retrieverLock, it lets
162 * concurrent threads access the ConcurrentHashMap directly.
163 *
164 * It's fine for a get() to happen during a registration or
165 * unregistration, it's first-come-first-serve.
166 */
8ab5c06b 167 return contextInfoRetrievers.get(retrieverName);
27dbdc00 168 }
cad6b749
AM
169
170 /**
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.
174 */
175 private static boolean validateRetrieverName(String contextName) {
176 if (contextName.isEmpty()) {
177 return false;
178 }
179
180 /* First character must not be a number */
181 if (Character.isDigit(contextName.charAt(0))) {
182 return false;
183 }
184
185 /* Validate the other characters of the string */
186 Matcher matcher = VALID_CONTEXT_NAME_PATTERN.matcher(contextName);
187 return matcher.matches();
188 }
27dbdc00 189}
This page took 0.032783 seconds and 4 git commands to generate.