io.vertx.core.impl.ContextInternal Maven / Gradle / Ivy
/*
* Copyright (c) 2011-2019 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
* which is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
*/
package io.vertx.core.impl;
import io.netty.channel.EventLoop;
import io.vertx.core.*;
import io.vertx.core.Future;
import io.vertx.core.impl.future.FailedFuture;
import io.vertx.core.impl.future.PromiseImpl;
import io.vertx.core.impl.future.PromiseInternal;
import io.vertx.core.impl.future.SucceededFuture;
import io.vertx.core.spi.context.storage.AccessMode;
import io.vertx.core.spi.context.storage.ContextLocal;
import io.vertx.core.spi.tracing.VertxTracer;
import java.util.concurrent.*;
import java.util.function.Supplier;
import static io.vertx.core.impl.ContextImpl.setResultHandler;
/**
* This interface provides an api for vert.x core internal use only
* It is not part of the public API and should not be used by
* developers creating vert.x applications
*
* @author Julien Viet
*/
public interface ContextInternal extends Context {
ContextLocal> LOCAL_MAP = new ContextLocalImpl<>(0);
/**
* @return the current context
*/
static ContextInternal current() {
Thread thread = Thread.currentThread();
if (thread instanceof VertxThread) {
return ((VertxThread) thread).context();
} else {
VertxImpl.ContextDispatch current = VertxImpl.nonVertxContextDispatch.get();
if (current != null) {
return current.context;
}
}
return null;
}
@Override
default void runOnContext(Handler action) {
executor().execute(() -> dispatch(action));
}
/**
* @return an executor that schedule a task on this context, the thread executing the task will not be associated with this context
*/
Executor executor();
/**
* Return the Netty EventLoop used by this Context. This can be used to integrate
* a Netty Server with a Vert.x runtime, specially the Context part.
*
* @return the EventLoop
*/
EventLoop nettyEventLoop();
/**
* @return a {@link Promise} associated with this context
*/
default PromiseInternal promise() {
return new PromiseImpl<>(this);
}
/**
* @return a {@link Promise} associated with this context or the {@code handler}
* if that handler is already an instance of {@code PromiseInternal}
*/
default PromiseInternal promise(Handler> handler) {
if (handler instanceof PromiseInternal) {
PromiseInternal promise = (PromiseInternal) handler;
if (promise.context() != null) {
return promise;
}
}
PromiseInternal promise = promise();
promise.future().onComplete(handler);
return promise;
}
/**
* @return an empty succeeded {@link Future} associated with this context
*/
default Future succeededFuture() {
return new SucceededFuture<>(this, null);
}
/**
* @return a succeeded {@link Future} of the {@code result} associated with this context
*/
default Future succeededFuture(T result) {
return new SucceededFuture<>(this, result);
}
/**
* @return a {@link Future} failed with the {@code failure} associated with this context
*/
default Future failedFuture(Throwable failure) {
return new FailedFuture<>(this, failure);
}
/**
* @return a {@link Future} failed with the {@code message} associated with this context
*/
default Future failedFuture(String message) {
return new FailedFuture<>(this, message);
}
/**
* Like {@link #executeBlocking(Handler, boolean, Handler)} but uses the {@code queue} to order the tasks instead
* of the internal queue of this context.
*
* @deprecated instead use {@link #executeBlocking(Callable, TaskQueue)}
*/
@Deprecated
default void executeBlocking(Handler> blockingCodeHandler, TaskQueue queue, Handler> resultHandler) {
Future fut = executeBlocking(blockingCodeHandler, queue);
setResultHandler(this, fut, resultHandler);
}
/**
* Like {@link #executeBlocking(Handler, boolean)} but uses the {@code queue} to order the tasks instead
* of the internal queue of this context.
*/
@Deprecated
Future executeBlocking(Handler> blockingCodeHandler, TaskQueue queue);
Future executeBlocking(Callable blockingCodeHandler, TaskQueue queue);
/**
* Execute an internal task on the internal blocking ordered executor.
*/
@Deprecated
default void executeBlockingInternal(Handler> action, Handler> resultHandler) {
Future fut = executeBlockingInternal(action);
setResultHandler(this, fut, resultHandler);
}
@Deprecated
default void executeBlockingInternal(Handler> action, boolean ordered, Handler> resultHandler) {
Future fut = executeBlockingInternal(action, ordered);
setResultHandler(this, fut, resultHandler);
}
@Override
default void executeBlocking(Handler> blockingCodeHandler, boolean ordered, Handler> resultHandler) {
Future fut = executeBlocking(blockingCodeHandler, ordered);
setResultHandler(this, fut, resultHandler);
}
/**
* Like {@link #executeBlockingInternal(Handler, Handler)} but returns a {@code Future} of the asynchronous result
*/
Future executeBlockingInternal(Handler> action);
Future executeBlockingInternal(Callable action);
/**
* Like {@link #executeBlockingInternal(Handler, boolean, Handler)} but returns a {@code Future} of the asynchronous result
*/
Future executeBlockingInternal(Handler> action, boolean ordered);
Future executeBlockingInternal(Callable action, boolean ordered);
/**
* @return the deployment associated with this context or {@code null}
*/
Deployment getDeployment();
@Override
VertxInternal owner();
boolean inThread();
/**
* Emit the given {@code argument} event to the {@code task} and switch on this context if necessary, this also associates the
* current thread with the current context so {@link Vertx#currentContext()} returns this context.
*
* Any exception thrown from the {@literal task} will be reported on this context.
*
* Calling this method is equivalent to {@code execute(v -> dispatch(argument, task))}
*
* @param argument the {@code task} argument
* @param task the handler to execute with the {@code event} argument
*/
void emit(T argument, Handler task);
/**
* @see #emit(Object, Handler)
*/
default void emit(Handler task) {
emit(null, task);
}
/**
* @see #execute(Object, Handler)
*/
default void execute(Handler task) {
execute(null, task);
}
/**
* Execute the {@code task} on this context, it will be executed according to the
* context concurrency model.
*
* @param task the task to execute
*/
void execute(Runnable task);
/**
* Execute a {@code task} on this context, the task will be executed according to the
* context concurrency model.
*
* @param argument the {@code task} argument
* @param task the task to execute
*/
void execute(T argument, Handler task);
/**
* @return whether the current thread is running on this context
*/
default boolean isRunningOnContext() {
return current() == this && inThread();
}
/**
* @see #dispatch(Handler)
*/
default void dispatch(Runnable handler) {
ContextInternal prev = beginDispatch();
try {
handler.run();
} catch (Throwable t) {
reportException(t);
} finally {
endDispatch(prev);
}
}
/**
* @see #dispatch(Object, Handler)
*/
default void dispatch(Handler handler) {
dispatch(null, handler);
}
/**
* Dispatch an {@code event} to the {@code handler} on this context.
*
* The handler is executed directly by the caller thread which must be a context thread.
*
* The handler execution is monitored by the blocked thread checker.
*
* This context is thread-local associated during the task execution.
*
* @param event the event for the {@code handler}
* @param handler the handler to execute with the {@code event}
*/
default void dispatch(E event, Handler handler) {
ContextInternal prev = beginDispatch();
try {
handler.handle(event);
} catch (Throwable t) {
reportException(t);
} finally {
endDispatch(prev);
}
}
/**
* Begin the execution of a task on this context.
*
* The task execution is monitored by the blocked thread checker.
*
* This context is thread-local associated during the task execution.
*
* You should not use this API directly, instead you should use {@link #dispatch(Object, Handler)}
*
* @return the previous context that shall be restored after or {@code null} if there is none
* @throws IllegalStateException when the current thread of execution cannot execute this task
*/
default ContextInternal beginDispatch() {
VertxImpl vertx = (VertxImpl) owner();
return vertx.beginDispatch(this);
}
/**
* End the execution of a task on this context, see {@link #beginDispatch()}
*
* You should not use this API directly, instead you should use {@link #dispatch(Object, Handler)}
*
* @param previous the previous context to restore or {@code null} if there is none
* @throws IllegalStateException when the current thread of execution cannot execute this task
*/
default void endDispatch(ContextInternal previous) {
VertxImpl vertx = (VertxImpl) owner();
vertx.endDispatch(previous);
}
/**
* Report an exception to this context synchronously.
*
* The exception handler will be called when there is one, otherwise the exception will be logged.
*
* @param t the exception to report
*/
void reportException(Throwable t);
/**
* @return the {@link ConcurrentMap} used to store context data
* @see Context#get(Object)
* @see Context#put(Object, Object)
*/
ConcurrentMap