io.vertx.core.internal.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.internal;
import io.netty.channel.EventLoop;
import io.vertx.core.*;
import io.vertx.core.Future;
import io.vertx.core.impl.*;
import io.vertx.core.impl.deployment.DeploymentContext;
import io.vertx.core.impl.future.FailedFuture;
import io.vertx.core.impl.future.PromiseImpl;
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.Objects;
import java.util.concurrent.*;
import java.util.function.Supplier;
/**
* 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() {
return VertxImpl.currentContext(Thread.currentThread());
}
@Override
default void runOnContext(Handler action) {
executor().execute(() -> dispatch(action));
}
/**
* @return an event executor that schedule a task on this context, the thread executing the task will not be associated with this context
*/
EventExecutor executor();
/**
* @return the event loop executor of this context
*/
EventExecutor eventLoop();
/**
* 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(Promise p) {
if (p instanceof PromiseInternal) {
PromiseInternal promise = (PromiseInternal) p;
if (promise.context() != null) {
return promise;
}
}
PromiseInternal promise = promise();
promise.future().onComplete(p);
return promise;
}
/**
* Create a promise and pass it to the {@code handler}, and then returns this future's promise. The {@code handler}
* is responsible for completing the promise, if the {@code handler} throws an exception, the promise is attempted
* to be failed with this exception.
*
* @param handler the handler completing the promise
* @return the future of the created promise
*/
default Future future(Handler> handler) {
Promise promise = promise();
try {
handler.handle(promise);
} catch (Throwable t) {
promise.tryFail(t);
}
return promise.future();
}
/**
* @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);
}
/**
* Execute an internal task on the internal blocking ordered executor.
*/
default Future executeBlockingInternal(Callable action) {
return owner().getInternalWorkerPool().executeBlocking(this, action, null);
}
/**
* @return the deployment associated with this context or {@code null}
*/
DeploymentContext deployment();
@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
*/
ContextInternal beginDispatch();
/**
* 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
*/
void endDispatch(ContextInternal 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