Commit | Line | Data |
---|---|---|
27dbdc00 AM |
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 | ||
8ab5c06b AM |
20 | import java.io.IOException; |
21 | import java.util.HashMap; | |
22 | import java.util.Map; | |
23 | import java.util.concurrent.ConcurrentHashMap; | |
cad6b749 AM |
24 | import java.util.regex.Matcher; |
25 | import java.util.regex.Pattern; | |
27dbdc00 AM |
26 | |
27 | /** | |
28 | * The singleton manager of {@link IContextInfoRetriever} objects. | |
29 | * | |
30 | * @author Alexandre Montplaisir | |
31 | */ | |
32 | public final class ContextInfoManager { | |
33 | ||
8ab5c06b | 34 | private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni"; |
27dbdc00 | 35 | |
cad6b749 AM |
36 | private static final Pattern VALID_CONTEXT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\.]+$"); |
37 | ||
8ab5c06b AM |
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 | private final Object retrieverLock = new Object(); | |
27dbdc00 AM |
44 | |
45 | /** Singleton class, constructor should not be accessed directly */ | |
46 | private ContextInfoManager() { | |
47 | } | |
48 | ||
49 | /** | |
50 | * Get the singleton instance. | |
51 | * | |
8ab5c06b AM |
52 | * <p> |
53 | * Usage of this class requires the "liblttng-ust-context-jni.so" native | |
54 | * library to be present on the system and available (passing | |
55 | * -Djava.library.path=path to the JVM may be needed). | |
56 | * </p> | |
57 | * | |
27dbdc00 | 58 | * @return The singleton instance |
8ab5c06b AM |
59 | * @throws IOException |
60 | * If the shared library cannot be found. | |
61 | * @throws SecurityException | |
62 | * We will forward any SecurityExcepion that may be thrown when | |
63 | * trying to load the JNI library. | |
27dbdc00 | 64 | */ |
8ab5c06b AM |
65 | public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException { |
66 | if (instance == null) { | |
67 | try { | |
68 | System.loadLibrary(SHARED_LIBRARY_NAME); | |
69 | } catch (UnsatisfiedLinkError e) { | |
70 | throw new IOException(e); | |
71 | } | |
72 | instance = new ContextInfoManager(); | |
73 | } | |
74 | return instance; | |
27dbdc00 AM |
75 | } |
76 | ||
77 | /** | |
78 | * Register a new context info retriever. | |
79 | * | |
8ab5c06b AM |
80 | * <p> |
81 | * Each context info retriever is registered with a given "retriever name", | |
82 | * which specifies the namespace of the context elements. This name is | |
83 | * specified separately from the retriever objects, which would allow | |
84 | * register the same retriever under different namespaces for example. | |
85 | * </p> | |
86 | * | |
87 | * <p> | |
88 | * If the method returns false (indicating registration failure), then the | |
89 | * retriever object will *not* be used for context information. | |
90 | * </p> | |
27dbdc00 | 91 | * |
8ab5c06b AM |
92 | * @param retrieverName |
93 | * The name to register to the context retriever object with. | |
94 | * @param contextInfoRetriever | |
27dbdc00 | 95 | * The context info retriever to register |
8ab5c06b AM |
96 | * @return True if the retriever was successfully registered, false if there |
97 | * was an error, for example if a retriever is already registered | |
98 | * with that name. | |
27dbdc00 | 99 | */ |
8ab5c06b AM |
100 | public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) { |
101 | synchronized (retrieverLock) { | |
cad6b749 AM |
102 | if (!validateRetrieverName(retrieverName)) { |
103 | return false; | |
104 | } | |
105 | ||
8ab5c06b AM |
106 | if (contextInfoRetrievers.containsKey(retrieverName)) { |
107 | /* | |
108 | * There is already a retriever registered with that name, | |
109 | * refuse the new registration. | |
110 | */ | |
111 | return false; | |
112 | } | |
113 | /* | |
114 | * Inform LTTng-UST of the new retriever. The names have to start | |
115 | * with "$app." on the UST side! | |
116 | */ | |
117 | long ref = LttngContextApi.registerProvider("$app." + retrieverName); | |
118 | if (ref == 0) { | |
119 | return false; | |
120 | } | |
121 | ||
122 | contextInfoRetrievers.put(retrieverName, contextInfoRetriever); | |
123 | contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref)); | |
124 | ||
125 | return true; | |
126 | } | |
27dbdc00 AM |
127 | } |
128 | ||
129 | /** | |
130 | * Unregister a previously added context info retriever. | |
131 | * | |
132 | * This method has no effect if the retriever was not already registered. | |
133 | * | |
8ab5c06b | 134 | * @param retrieverName |
27dbdc00 | 135 | * The context info retriever to unregister |
8ab5c06b AM |
136 | * @return True if unregistration was successful, false if there was an |
137 | * error | |
27dbdc00 | 138 | */ |
8ab5c06b AM |
139 | public boolean unregisterContextInfoRetriever(String retrieverName) { |
140 | synchronized (retrieverLock) { | |
141 | if (!contextInfoRetrievers.containsKey(retrieverName)) { | |
142 | /* | |
143 | * There was no retriever registered with that name. | |
144 | */ | |
145 | return false; | |
146 | } | |
147 | contextInfoRetrievers.remove(retrieverName); | |
148 | long ref = contextInforRetrieverRefs.remove(retrieverName).longValue(); | |
149 | ||
150 | /* Unregister the retriever on the UST side too */ | |
151 | LttngContextApi.unregisterProvider(ref); | |
152 | ||
153 | return true; | |
154 | } | |
27dbdc00 AM |
155 | } |
156 | ||
157 | /** | |
8ab5c06b | 158 | * Return the context info retriever object registered with the given name. |
27dbdc00 | 159 | * |
8ab5c06b AM |
160 | * @param retrieverName |
161 | * The retriever name to look for | |
162 | * @return The corresponding retriever object, or <code>null</code> if there | |
163 | * was none | |
27dbdc00 | 164 | */ |
8ab5c06b AM |
165 | public IContextInfoRetriever getContextInfoRetriever(String retrieverName) { |
166 | return contextInfoRetrievers.get(retrieverName); | |
27dbdc00 | 167 | } |
cad6b749 AM |
168 | |
169 | /** | |
170 | * Validate that the given retriever name contains only the allowed | |
171 | * characters, which are alphanumerical characters, period "." and | |
172 | * underscore "_". The name must also not start with a number. | |
173 | */ | |
174 | private static boolean validateRetrieverName(String contextName) { | |
175 | if (contextName.isEmpty()) { | |
176 | return false; | |
177 | } | |
178 | ||
179 | /* First character must not be a number */ | |
180 | if (Character.isDigit(contextName.charAt(0))) { | |
181 | return false; | |
182 | } | |
183 | ||
184 | /* Validate the other characters of the string */ | |
185 | Matcher matcher = VALID_CONTEXT_NAME_PATTERN.matcher(contextName); | |
186 | return matcher.matches(); | |
187 | } | |
27dbdc00 | 188 | } |