blob: 2e737be20d4ebf50af9fdca8cff592964acfdaee [file] [log] [blame]
/*
* Copyright 2017, OpenCensus Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.opencensus.contrib.agent.bootstrap;
/**
* {@code ContextTrampoline} provides methods for accessing and manipulating the context from
* instrumented bytecode.
*
* <p>{@code ContextTrampoline} avoids tight coupling with the concrete implementation of the
* context by accessing and manipulating the context through the {@link ContextStrategy} interface.
*
* <p>Both {@link ContextTrampoline} and {@link ContextStrategy} are loaded by the bootstrap
* classloader so that they can be used from classes loaded by the bootstrap classloader. A concrete
* implementation of {@link ContextStrategy} will be loaded by the system classloader. This allows
* for using the same context implementation as the instrumented application.
*
* <p>{@code ContextTrampoline} is implemented as a static class to allow for easy and fast use from
* instrumented bytecode. We cannot use dependency injection for the instrumented bytecode.
*
* @since 0.9
*/
// TODO(sebright): Fix the Checker Framework warnings.
@SuppressWarnings("nullness")
public final class ContextTrampoline {
// Not synchronized to avoid any synchronization costs after initialization.
// The agent is responsible for initializing this once (through #setContextStrategy) before any
// other method of this class is called.
private static ContextStrategy contextStrategy;
private ContextTrampoline() {}
/**
* Sets the concrete strategy for accessing and manipulating the context.
*
* <p>NB: The agent is responsible for setting the context strategy once before any other method
* of this class is called.
*
* @param contextStrategy the concrete strategy for accessing and manipulating the context
* @since 0.9
*/
public static void setContextStrategy(ContextStrategy contextStrategy) {
if (ContextTrampoline.contextStrategy != null) {
throw new IllegalStateException("contextStrategy was already set");
}
if (contextStrategy == null) {
throw new NullPointerException("contextStrategy");
}
ContextTrampoline.contextStrategy = contextStrategy;
}
/**
* Wraps a {@link Runnable} so that it executes with the context that is associated with the
* current scope.
*
* @param runnable a {@link Runnable} object
* @return the wrapped {@link Runnable} object
* @see ContextStrategy#wrapInCurrentContext
* @since 0.9
*/
public static Runnable wrapInCurrentContext(Runnable runnable) {
return contextStrategy.wrapInCurrentContext(runnable);
}
/**
* Saves the context that is associated with the current scope.
*
* <p>The context will be attached when entering the specified thread's {@link Thread#run()}
* method.
*
* @param thread a {@link Thread} object
* @since 0.9
*/
public static void saveContextForThread(Thread thread) {
contextStrategy.saveContextForThread(thread);
}
/**
* Attaches the context that was previously saved for the specified thread.
*
* @param thread a {@link Thread} object
* @since 0.9
*/
public static void attachContextForThread(Thread thread) {
contextStrategy.attachContextForThread(thread);
}
}