javolution.context.AbstractContext Maven / Gradle / Ivy
/*
* Javolution - Java(TM) Solution for Real-Time and Embedded Systems
* Copyright (C) 2012 - Javolution (http://javolution.org/)
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software is
* freely granted, provided that this notice is preserved.
*/
package javolution.context;
import javolution.lang.Parallelizable;
import javolution.context.SecurityContext.Permission;
import javolution.lang.Realtime;
/**
* The parent class for all contexts.
* Contexts allow for cross cutting concerns (performance, logging,
* security, ...) to be addressed at run-time through OSGi published
* services without polluting the application code
* (
* Separation of Concerns).
*
* Context configuration is performed in a {@code try, finally}
* block statement and impacts only the current thread (although inherited
* by inner {@link ConcurrentContext} threads).
* [code]
* AnyContext ctx = AnyContext.enter(); // Enters a context scope.
* try {
* ctx.configure(...); // Local configuration (optional).
* ... // Current thread executes using the configured context.
* } finally {
* ctx.exit();
* }[/code]
*
* @author Jean-Marie Dautelle
* @version 6.0, July 21, 2013
*/
@Realtime
@Parallelizable(comment = "Sequential configuration, parallel use")
public abstract class AbstractContext {
/**
* Holds the last context entered (thread-local).
*/
private static final ThreadLocal CURRENT = new ThreadLocal();
/**
* Holds the outer context or {@code null} if none (top context).
*/
private AbstractContext outer;
/**
* Default constructor.
*/
protected AbstractContext() {}
/**
* Returns the current context for the current thread or {@code null}
* if this thread has no context (default).
*/
public static AbstractContext current() {
return AbstractContext.CURRENT.get();
}
/**
* Returns the current context of specified type or {@code null} if none.
*/
@SuppressWarnings("unchecked")
protected static T current(Class type) {
AbstractContext ctx = AbstractContext.CURRENT.get();
while (ctx != null) {
if (type.isInstance(ctx))
return (T) ctx;
ctx = ctx.outer;
}
return null;
}
/**
* Enters the scope of a custom context. This method raises a
* {@link SecurityException} if the permission to enter contexts of
* the specified class is not granted. For example, the following
* disallow entering any custom context.
*[code]
* SecurityContext ctx = SecurityContext.enter();
* try {
* ctx.revoke(new SecurityContext.Permission(AbstractContext.class, "enter"));
* ... // Cannot enter any custom context.
* } finally {
* ctx.exit(); // Back to previous security settings.
* }[/code]
*
* @param custom the custom context to enter.
* @throws IllegalArgumentException if the specified class default constructor
* cannot be instantiated.
* @throws SecurityException if {@code SecurityContext.Permission(custom, "enter")}
* is not granted.
* @see SecurityContext.Permission
*/
@SuppressWarnings("unchecked")
public static T enter(Class custom) {
SecurityContext.check(new Permission(custom, "enter"));
try {
return (T) custom.newInstance().enterInner();
} catch (InstantiationException e) {
throw new IllegalArgumentException(
"Cannot instantiate instance of " + custom, e);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Cannot access " + custom, e);
}
}
/**
* Inherits the specified context which becomes the context of the current
* thread. This method is particularly useful when creating new threads to
* make them inherits from the context stack of the parent thread.
* [code]
* //Spawns a new thread inheriting the context of the current thread.
* MyThread myThread = new MyThread();
* myThread.inherited = AbstractContext.current();
* myThread.start();
* ...
* class MyThread extends Thread {
* AbstractContext inherited;
* public void run() {
* AbstractContext.inherit(inherited); // Sets current context.
* ...
* }
* }[/code]
*/
public static void inherit(AbstractContext ctx) {
CURRENT.set(ctx);
}
/**
* Enters the scope of an inner context which becomes the current context;
* the previous current context becomes the outer of this context.
*
* @return the inner context entered.
*/
protected AbstractContext enterInner() {
AbstractContext inner = inner();
inner.outer = AbstractContext.CURRENT.get();
AbstractContext.CURRENT.set(inner);
return inner;
}
/**
* Exits the scope of this context; the outer of this context becomes
* the current context.
*
* @throws IllegalStateException if this context is not the current
* context.
*/
public void exit() {
if (this != AbstractContext.CURRENT.get())
throw new IllegalStateException(
"This context is not the current context");
AbstractContext.CURRENT.set(outer);
outer = null;
}
/**
* Returns the outer context of this context or {@code null} if this
* context has no outer context.
*/
protected AbstractContext getOuter() {
return outer;
}
/**
* Returns a new inner instance of this context inheriting the properties
* of this context. The new instance can be configured independently
* from its parent.
*/
protected abstract AbstractContext inner();
}