7a8c80e9a83d6040f1ed630b2932870e65f4eb66
[lttng-ust.git] / liblttng-ust-java-agent / java / lttng-ust-agent-common / org / lttng / ust / agent / context / ContextInfoManager.java
1 /*
2 * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir <alexmonthy@efficios.com>
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 package org.lttng.ust.agent.context;
19
20 import java.io.IOException;
21 import java.util.HashMap;
22 import java.util.Map;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 /**
28 * The singleton manager of {@link IContextInfoRetriever} objects.
29 *
30 * @author Alexandre Montplaisir
31 */
32 public final class ContextInfoManager {
33
34 private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni";
35
36 private static final Pattern VALID_CONTEXT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\.]+$");
37
38 private static ContextInfoManager instance;
39
40 private final Map<String, IContextInfoRetriever> contextInfoRetrievers = new ConcurrentHashMap<String, IContextInfoRetriever>();
41 private final Map<String, Long> contextInforRetrieverRefs = new HashMap<String, Long>();
42
43 /**
44 * Lock used to keep the two maps above in sync when retrievers are
45 * registered or unregistered.
46 */
47 private final Object retrieverLock = new Object();
48
49 /** Singleton class, constructor should not be accessed directly */
50 private ContextInfoManager() {
51 }
52
53 /**
54 * Get the singleton instance.
55 *
56 * <p>
57 * Usage of this class requires the "liblttng-ust-context-jni.so" native
58 * library to be present on the system and available (passing
59 * -Djava.library.path=path to the JVM may be needed).
60 * </p>
61 *
62 * @return The singleton instance
63 * @throws IOException
64 * If the shared library cannot be found.
65 * @throws SecurityException
66 * We will forward any SecurityExcepion that may be thrown when
67 * trying to load the JNI library.
68 */
69 public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException {
70 if (instance == null) {
71 try {
72 System.loadLibrary(SHARED_LIBRARY_NAME);
73 } catch (UnsatisfiedLinkError e) {
74 throw new IOException(e);
75 }
76 instance = new ContextInfoManager();
77 }
78 return instance;
79 }
80
81 /**
82 * Register a new context info retriever.
83 *
84 * <p>
85 * Each context info retriever is registered with a given "retriever name",
86 * which specifies the namespace of the context elements. This name is
87 * specified separately from the retriever objects, which would allow
88 * register the same retriever under different namespaces for example.
89 * </p>
90 *
91 * <p>
92 * If the method returns false (indicating registration failure), then the
93 * retriever object will *not* be used for context information.
94 * </p>
95 *
96 * @param retrieverName
97 * The name to register to the context retriever object with.
98 * @param contextInfoRetriever
99 * The context info retriever to register
100 * @return True if the retriever was successfully registered, false if there
101 * was an error, for example if a retriever is already registered
102 * with that name.
103 */
104 public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) {
105 synchronized (retrieverLock) {
106 if (!validateRetrieverName(retrieverName)) {
107 return false;
108 }
109
110 if (contextInfoRetrievers.containsKey(retrieverName)) {
111 /*
112 * There is already a retriever registered with that name,
113 * refuse the new registration.
114 */
115 return false;
116 }
117 /*
118 * Inform LTTng-UST of the new retriever. The names have to start
119 * with "$app." on the UST side!
120 */
121 long ref = LttngContextApi.registerProvider("$app." + retrieverName);
122 if (ref == 0) {
123 return false;
124 }
125
126 contextInfoRetrievers.put(retrieverName, contextInfoRetriever);
127 contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref));
128
129 return true;
130 }
131 }
132
133 /**
134 * Unregister a previously added context info retriever.
135 *
136 * This method has no effect if the retriever was not already registered.
137 *
138 * @param retrieverName
139 * The context info retriever to unregister
140 * @return True if unregistration was successful, false if there was an
141 * error
142 */
143 public boolean unregisterContextInfoRetriever(String retrieverName) {
144 synchronized (retrieverLock) {
145 if (!contextInfoRetrievers.containsKey(retrieverName)) {
146 /*
147 * There was no retriever registered with that name.
148 */
149 return false;
150 }
151 contextInfoRetrievers.remove(retrieverName);
152 long ref = contextInforRetrieverRefs.remove(retrieverName).longValue();
153
154 /* Unregister the retriever on the UST side too */
155 LttngContextApi.unregisterProvider(ref);
156
157 return true;
158 }
159 }
160
161 /**
162 * Return the context info retriever object registered with the given name.
163 *
164 * @param retrieverName
165 * The retriever name to look for
166 * @return The corresponding retriever object, or <code>null</code> if there
167 * was none
168 */
169 public IContextInfoRetriever getContextInfoRetriever(String retrieverName) {
170 /*
171 * Note that this method does not take the retrieverLock, it lets
172 * concurrent threads access the ConcurrentHashMap directly.
173 *
174 * It's fine for a get() to happen during a registration or
175 * unregistration, it's first-come-first-serve.
176 */
177 return contextInfoRetrievers.get(retrieverName);
178 }
179
180 /**
181 * Validate that the given retriever name contains only the allowed
182 * characters, which are alphanumerical characters, period "." and
183 * underscore "_". The name must also not start with a number.
184 */
185 private static boolean validateRetrieverName(String contextName) {
186 if (contextName.isEmpty()) {
187 return false;
188 }
189
190 /* First character must not be a number */
191 if (Character.isDigit(contextName.charAt(0))) {
192 return false;
193 }
194
195 /* Validate the other characters of the string */
196 Matcher matcher = VALID_CONTEXT_NAME_PATTERN.matcher(contextName);
197 return matcher.matches();
198 }
199 }
This page took 0.032565 seconds and 3 git commands to generate.