
io.micronaut.scheduling.instrument.InvocationInstrumenter Maven / Gradle / Ivy
/*
* Copyright 2017-2020 original 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.micronaut.scheduling.instrument;
import io.micronaut.core.annotation.Experimental;
import io.micronaut.core.util.CollectionUtils;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import static io.micronaut.core.util.ArgumentUtils.requireNonNull;
/**
* An interface for invocation instrumentation.
*
* @author Denis Stepanov
* @author graemerocher
* @since 1.3
*/
@Experimental
public interface InvocationInstrumenter {
/**
* Noop implementation if {@link InvocationInstrumenter}.
*/
InvocationInstrumenter NOOP = Instrumentation::noop;
/**
* @return a one-time {@link Instrumentation} instance which to be used in a try-with-resources to do the
* instrumentation. To force cleanup invoke {@link Instrumentation#forceCleanup()} on the retuned instance.
* @since 2.0
*/
@NonNull Instrumentation newInstrumentation();
/**
* Combines multiple instrumenters into one.
*
* @param invocationInstrumenters instrumenters to combine
* @return new instrumenter
*/
static @NonNull InvocationInstrumenter combine(Collection invocationInstrumenters) {
if (CollectionUtils.isEmpty(invocationInstrumenters)) {
return NOOP;
}
if (invocationInstrumenters.size() == 1) {
return invocationInstrumenters.iterator().next();
}
return new MultipleInvocationInstrumenter(invocationInstrumenters);
}
/**
* Wraps {@link Runnable} with instrumentation invocations.
*
* @param runnable {@link Runnable} to be wrapped
* @param invocationInstrumenters instrumenters to be used
* @return wrapper
*/
static @NonNull Runnable instrument(@NonNull Runnable runnable, Collection invocationInstrumenters) {
if (CollectionUtils.isEmpty(invocationInstrumenters)) {
return runnable;
}
return instrument(runnable, combine(invocationInstrumenters));
}
/**
* Wraps {@link Callable} with instrumentation invocations.
*
* @param callable {@link Callable} to be wrapped
* @param invocationInstrumenters instrumenters to be used
* @param callable generic param
* @return wrapper
*/
static @NonNull Callable instrument(@NonNull Callable callable, Collection invocationInstrumenters) {
if (CollectionUtils.isEmpty(invocationInstrumenters)) {
return callable;
}
return instrument(callable, combine(invocationInstrumenters));
}
/**
* Wraps {@link Runnable} with instrumentation invocations.
*
* @param runnable {@link Runnable} to be wrapped
* @param invocationInstrumenter instrumenter to be used
* @return wrapper
*/
static @NonNull Runnable instrument(@NonNull Runnable runnable, InvocationInstrumenter invocationInstrumenter) {
if (runnable instanceof InvocationInstrumenterWrappedRunnable) {
return runnable;
}
return new InvocationInstrumenterWrappedRunnable(invocationInstrumenter, runnable);
}
/**
* Wraps {@link Callable} with instrumentation invocations.
*
* @param callable {@link Callable} to be wrapped
* @param invocationInstrumenter instrumenter to be used
* @param callable generic param
* @return wrapper
*/
static @NonNull Callable instrument(@NonNull Callable callable, InvocationInstrumenter invocationInstrumenter) {
if (callable instanceof InvocationInstrumenterWrappedCallable) {
return callable;
}
return new InvocationInstrumenterWrappedCallable<>(invocationInstrumenter, callable);
}
/**
* Wraps the {@code executor} so that every tasks submitted to it will be executed instrumented with the given
* {@code invocationInstrumenter}. Execution itself will be delegated to the underlying {@code executor}, but it has
* to be considered that all instrumentation will be done with this very same {@code invocationInstrumenter}
* instance. This is especially useful when follow-up actions of a given task need to be registered, where a new
* instrumenter, thus a new wrapped executor instance belongs to each task.
*
* The returned wrapped executor be of subtype {@link ExecutorService} or {@link ScheduledExecutorService} if the
* input executor instance implemented those interfaces.
*
* @param executor the executor to wrap
* @param invocationInstrumenter the instrumenter to be used upon task executions with the returned executor
* @return the wrapped executor
*/
static Executor instrument(@NonNull Executor executor, @NonNull InvocationInstrumenter invocationInstrumenter) {
requireNonNull("executor", executor);
requireNonNull("invocationInstrumenter", invocationInstrumenter);
if (executor instanceof ScheduledExecutorService) {
return new InstrumentedScheduledExecutorService() {
@Override
public ScheduledExecutorService getTarget() {
return (ScheduledExecutorService) executor;
}
@Override
public Callable instrument(Callable callable) {
return InvocationInstrumenter.instrument(callable, invocationInstrumenter);
}
@Override
public Runnable instrument(Runnable runnable) {
return InvocationInstrumenter.instrument(runnable, invocationInstrumenter);
}
};
} else if (executor instanceof ExecutorService) {
return new InstrumentedExecutorService() {
@Override
public ExecutorService getTarget() {
return (ExecutorService) executor;
}
@Override
public Callable instrument(Callable callable) {
return InvocationInstrumenter.instrument(callable, invocationInstrumenter);
}
@Override
public Runnable instrument(Runnable runnable) {
return InvocationInstrumenter.instrument(runnable, invocationInstrumenter);
}
};
} else {
return new InstrumentedExecutor() {
@Override
public Executor getTarget() {
return executor;
}
@Override
public Runnable instrument(Runnable runnable) {
return InvocationInstrumenter.instrument(runnable, invocationInstrumenter);
}
};
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy