X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=liblttng-ust-java-agent%2Fjava%2Flttng-ust-agent-common%2Forg%2Flttng%2Fust%2Fagent%2Fcontext%2FContextInfoManager.java;h=22efe022e794c3b1930570f560df5b408567ea2a;hb=c0c0989ab70574e09b2f7e8b48c2da6af664a849;hp=90a79acc646a43e2135589f756e368b11da33999;hpb=27dbdc0036ec754a3c9608aafa651cc558a5df4b;p=lttng-ust.git diff --git a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java index 90a79acc..22efe022 100644 --- a/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java +++ b/liblttng-ust-java-agent/java/lttng-ust-agent-common/org/lttng/ust/agent/context/ContextInfoManager.java @@ -1,24 +1,18 @@ /* - * Copyright (C) 2015 - EfficiOS Inc., Alexandre Montplaisir + * SPDX-License-Identifier: LGPL-2.1-only * - * This library is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License, version 2.1 only, - * as published by the Free Software Foundation. - * - * This library is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2015 EfficiOS Inc. + * Copyright (C) 2015 Alexandre Montplaisir */ package org.lttng.ust.agent.context; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * The singleton manager of {@link IContextInfoRetriever} objects. @@ -27,9 +21,20 @@ import java.util.concurrent.CopyOnWriteArraySet; */ public final class ContextInfoManager { - private static final ContextInfoManager INSTANCE = new ContextInfoManager(); + private static final String SHARED_LIBRARY_NAME = "lttng-ust-context-jni"; + + private static final Pattern VALID_CONTEXT_NAME_PATTERN = Pattern.compile("^[a-zA-Z0-9_\\.]+$"); + + private static ContextInfoManager instance; + + private final Map contextInfoRetrievers = new ConcurrentHashMap(); + private final Map contextInforRetrieverRefs = new HashMap(); - private final Set cirs = new CopyOnWriteArraySet(); + /** + * Lock used to keep the two maps above in sync when retrievers are + * registered or unregistered. + */ + private final Object retrieverLock = new Object(); /** Singleton class, constructor should not be accessed directly */ private ContextInfoManager() { @@ -38,25 +43,81 @@ public final class ContextInfoManager { /** * Get the singleton instance. * + *

+ * Usage of this class requires the "liblttng-ust-context-jni.so" native + * library to be present on the system and available (passing + * -Djava.library.path=path to the JVM may be needed). + *

+ * * @return The singleton instance - * @deprecated The context-retrieving facilities are not yet implemented. + * @throws IOException + * If the shared library cannot be found. + * @throws SecurityException + * We will forward any SecurityExcepion that may be thrown when + * trying to load the JNI library. */ - @Deprecated - public static ContextInfoManager getInstance() { - return INSTANCE; + public static synchronized ContextInfoManager getInstance() throws IOException, SecurityException { + if (instance == null) { + try { + System.loadLibrary(SHARED_LIBRARY_NAME); + } catch (UnsatisfiedLinkError e) { + throw new IOException(e); + } + instance = new ContextInfoManager(); + } + return instance; } /** * Register a new context info retriever. * - * This method has no effect if the exact same retriever is already - * registered. + *

+ * Each context info retriever is registered with a given "retriever name", + * which specifies the namespace of the context elements. This name is + * specified separately from the retriever objects, which would allow + * register the same retriever under different namespaces for example. + *

* - * @param cir + *

+ * If the method returns false (indicating registration failure), then the + * retriever object will *not* be used for context information. + *

+ * + * @param retrieverName + * The name to register to the context retriever object with. + * @param contextInfoRetriever * The context info retriever to register + * @return True if the retriever was successfully registered, false if there + * was an error, for example if a retriever is already registered + * with that name. */ - public void addContextInfoRetriever(IContextInfoRetriever cir) { - cirs.add(cir); + public boolean registerContextInfoRetriever(String retrieverName, IContextInfoRetriever contextInfoRetriever) { + synchronized (retrieverLock) { + if (!validateRetrieverName(retrieverName)) { + return false; + } + + if (contextInfoRetrievers.containsKey(retrieverName)) { + /* + * There is already a retriever registered with that name, + * refuse the new registration. + */ + return false; + } + /* + * Inform LTTng-UST of the new retriever. The names have to start + * with "$app." on the UST side! + */ + long ref = LttngContextApi.registerProvider("$app." + retrieverName); + if (ref == 0) { + return false; + } + + contextInfoRetrievers.put(retrieverName, contextInfoRetriever); + contextInforRetrieverRefs.put(retrieverName, Long.valueOf(ref)); + + return true; + } } /** @@ -64,21 +125,65 @@ public final class ContextInfoManager { * * This method has no effect if the retriever was not already registered. * - * @param cir + * @param retrieverName * The context info retriever to unregister + * @return True if unregistration was successful, false if there was an + * error */ - public void removeContextInfoRetriever(IContextInfoRetriever cir) { - cirs.remove(cir); + public boolean unregisterContextInfoRetriever(String retrieverName) { + synchronized (retrieverLock) { + if (!contextInfoRetrievers.containsKey(retrieverName)) { + /* + * There was no retriever registered with that name. + */ + return false; + } + contextInfoRetrievers.remove(retrieverName); + long ref = contextInforRetrieverRefs.remove(retrieverName).longValue(); + + /* Unregister the retriever on the UST side too */ + LttngContextApi.unregisterProvider(ref); + + return true; + } } /** - * Return a read-only view (does not support - * {@link java.util.Iterator#remove}) of the currently registered context - * info retrievers. + * Return the context info retriever object registered with the given name. * - * @return The current context info retrievers + * @param retrieverName + * The retriever name to look for + * @return The corresponding retriever object, or null if there + * was none + */ + public IContextInfoRetriever getContextInfoRetriever(String retrieverName) { + /* + * Note that this method does not take the retrieverLock, it lets + * concurrent threads access the ConcurrentHashMap directly. + * + * It's fine for a get() to happen during a registration or + * unregistration, it's first-come-first-serve. + */ + return contextInfoRetrievers.get(retrieverName); + } + + /** + * Validate that the given retriever name contains only the allowed + * characters, which are alphanumerical characters, period "." and + * underscore "_". The name must also not start with a number. */ - public Iterable getContextInfoRetrievers() { - return cirs; + private static boolean validateRetrieverName(String contextName) { + if (contextName.isEmpty()) { + return false; + } + + /* First character must not be a number */ + if (Character.isDigit(contextName.charAt(0))) { + return false; + } + + /* Validate the other characters of the string */ + Matcher matcher = VALID_CONTEXT_NAME_PATTERN.matcher(contextName); + return matcher.matches(); } }