
org.ow2.bonita.env.Environment Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.ow2.bonita.env;
import java.io.Serializable;
import java.util.Stack;
import org.ow2.bonita.util.BonitaRuntimeException;
import org.ow2.bonita.util.ExceptionManager;
/**
* maintains contextual information for a thread in a set of {@link Context}s.
*
* Introduction
*
*
* Objects have different lifecycles and different context's (aka scopes). An
* environment provides the structure to easily manage objects with different
* contexts.
*
*
*
* Examples of contexts are:
*
* - environment-factory: The environment-factory context is used to
* store e.g. data sources, session factories and other static resources needed
* by an application. The environment-factory context lives for the complete
* duration of the EnvironmentFactory. So if the
* EnvironmentFactory is maintained in a static member field, the
* environment-factory context lives for the duration of the application. The
* same environment-factory context is shared for all the Environments produced
* by one EnvironmentFactory.
* - environment: The environment context is used for e.g. a
* transaction and transactional resources, user authentication. This results in
* an efficient and configurable use of transactional resources that need to be
* lazily initialized.
* - The environment can accomodate other contexts as well. They can be added
* and removed dynamically. Examples of other potential contexts are
* web-request, web-session, web-application, business processDefinition, ...
*
*
* 
*
*
* An environment is typically installed like this
*
*
*
*
*
* static EnvironmentFactory environmentFactory = new DefaultEnvironmentFactory();
*
* ...
*
* Environment environment = environmentFactory.openEnvironment();
* try {
*
* ... everything available in this block ...
*
* } finally {
* environment.close();
* }
*
*
*
*
* Purpose
*
*
* The first purpose of the environment is to separate the application from the
* environment. Standard Java and Enterprise Java are quite different and an
* environment abstraction like this allows for the development of applications
* that can run in both Standard and Enterprise environments. Also test
* environments are easier to tweak this way.
*
*
*
* A second purpose of the environment is to enable specific to global searching
* of resources. E.g. you could search for an 'adminEmailAddress' in the
* contexts 'processDefinition-execution', 'processDefinition-definition' and
* 'environment-factory' in the given order. That way, a global
* adminEmailAddress can be specified in the environment-factory context and it
* can be refined in more specific contexts processDefinition-definition or
* processDefinition-execution.
*
*
* Search order
*
*
* To find an object in the environment, a searchOrder can be specified. A
* search order is an sequence that specifies the order in which the contexts
* should be searched.
*
*
*
* The default search order is the inverse sequence of how the contexts are
* added to the environment. This is because in general, we can assume that the
* more recent a context was added, the more specific it is.
*
*
* Transaction, username and classloader
*
*
* Three objects are used so frequently in an environment that they get special
* treatment:
*
*
*
* - Transaction: an abstraction for marking a transaction with
* setRollbackOnly.
* - Classloader: the current class loader.
* - Username: the name of the currently authenticated user.
*
*
*
* For these special properties, setters are also available. That is to support
* programmatic injection into the environment. Alternatively, they can be
* configured in one of the contexts.
*
*
*
* @author Tom Baeyens
*/
public abstract class Environment implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4160822335317326182L;
/**
* searches a named object in all the contexts in the default search order.
*
* @return the object if it exists in the environment, null
if
* there is no object with the given name in the environment.
*/
public abstract Object get(String name);
/**
* searches a named object in all the contexts in the given search order. The
* given search order doesn't have to include all contexts. It can be a subset
* of the contexts available.
*
* @param searchOrder
* list of contexts names. The object will be searched in these
* contexts, in the given order.
* @return the object if it exists in the environment, null
if
* there is no object with the given name in the specified searchOrder
* contexts.
*/
public abstract Object get(String name, String[] searchOrder);
/**
* searches an object based on type. The search does not take superclasses of the
* context elements into account.
*
* @return the first object of the given type or null in case no such element
* was found.
*/
public abstract T get(Class type);
/**
* searches an object based on type. The search does not take superclasses of the
* context elements into account.
*
* @return the first object of the given type or null in case no such element
* was found.
*/
public abstract T get(Class type, String[] searchOrder);
/** get the authenticated user id */
public abstract String getUserId();
/** set the authenticated user id */
public abstract void setUserId(String userId);
/**
* closes the Environment by removing all its contexts.
*/
public abstract void close();
public abstract Context getContext(String contextName);
public abstract void addContext(Context context);
public abstract void removeContext(Context context);
public abstract ClassLoader getClassLoader();
public abstract void setClassLoader(ClassLoader classLoader);
// current environment //////////////////////////////////////////////////////
/**
* the current environment is maintained in the currentEnvironment thread
* local
*/
static ThreadLocal currentEnvironment = new ThreadLocal();
/**
* in case of nested environments, the current environment stack maintains the
* outer environments
*/
static ThreadLocal> currentEnvironmentStack = new ThreadLocal>();
/** gets the most inner open environment. */
public static Environment getCurrent() {
return currentEnvironment.get();
}
public static T getFromCurrent(Class type) {
return getFromCurrent(type, true);
}
public static T getFromCurrent(Class type, boolean required) {
Environment environment = getCurrent();
if (environment == null) {
if (required) {
String message = ExceptionManager.getInstance().getFullMessage(
"bp_E_1", type.getName());
throw new BonitaRuntimeException(message);
}
return null;
}
T object = environment.get(type);
if (object == null) {
if (required) {
String message = ExceptionManager.getInstance().getFullMessage("bp_E_2", type.getName());
throw new BonitaRuntimeException(message);
}
return null;
}
return object;
}
public static Object getFromCurrent(String name) {
return getFromCurrent(name, true);
}
public static Object getFromCurrent(String name, boolean required) {
Environment environment = getCurrent();
if (environment == null) {
if (required) {
String message = ExceptionManager.getInstance().getFullMessage("bp_E_3", name);
throw new BonitaRuntimeException(message);
}
return null;
}
Object object = environment.get(name);
if (object == null) {
if (required) {
String message = ExceptionManager.getInstance().getFullMessage("bp_E_4", name);
throw new BonitaRuntimeException(message);
}
return null;
}
return object;
}
static Stack getStack() {
// lazy initialize the current environment stack
Stack stack = currentEnvironmentStack.get();
if (stack == null) {
stack = new Stack();
currentEnvironmentStack.set(stack);
}
return stack;
}
/**
* pops the closing context from the stack of current contexts. This is the
* first thing that needs to be done when an environment is closed.
*
*/
protected static synchronized Environment popEnvironment() {
Environment popped = currentEnvironment.get();
currentEnvironment.set(null);
Stack stack = currentEnvironmentStack.get();
if ((stack != null) && (!stack.isEmpty())) {
currentEnvironment.set(stack.pop());
}
return popped;
}
/**
* after opening of a new environment succeeded, the environment must be
* pushed in the stack of current environments.
*
*/
protected static synchronized void pushEnvironment(Environment environment) {
Environment current = currentEnvironment.get();
if (current != null) {
getStack().push(current);
}
currentEnvironment.set(environment);
}
}