/*
* JBoss, Home of Professional Open Source
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.seam.contexts;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.jboss.seam.Component;
import org.jboss.seam.ScopeType;
import org.jboss.seam.bpm.ProcessInstance;
import org.jboss.seam.bpm.TaskInstance;
import org.jboss.seam.core.Events;
import org.jboss.seam.core.Init;
import org.jboss.seam.log.LogProvider;
import org.jboss.seam.log.Logging;
import org.jbpm.context.exe.ContextInstance;
/**
* Exposes a jbpm variable context instance for reading/writing.
*
* @author <a href="mailto:theute@jboss.org">Thomas Heute</a>
* @author <a href="mailto:steve@hibernate.org">Steve Ebersole</a>
* @author Gavin King
*/
public class BusinessProcessContext implements Context
{
private static final LogProvider log = Logging.getLogProvider(BusinessProcessContext.class);
private final Map<String, Object> additions = new HashMap<String, Object>();
private final Set<String> removals = new HashSet<String>();
public ScopeType getType()
{
return ScopeType.BUSINESS_PROCESS;
}
public BusinessProcessContext() {}
public Object get(String name)
{
Object result = additions.get(name);
if (result!=null) return result;
if ( removals.contains(name) ) return null;
org.jbpm.taskmgmt.exe.TaskInstance taskInstance = getTaskInstance();
if (taskInstance==null)
{
ContextInstance context = getContextInstance();
return context==null ? null : context.getVariable(name);
}
else
{
return taskInstance.getVariable(name);
}
}
public void set(String name, Object value)
{
if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.preSetVariable." + name);
if (value==null)
{
//yes, we need this
remove(name);
}
else
{
removals.remove(name);
additions.put(name, value);
}
if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.postSetVariable." + name);
}
public boolean isSet(String name)
{
return get(name)!=null;
}
public void remove(String name)
{
if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.preRemoveVariable." + name);
additions.remove(name);
removals.add(name);
if ( Events.exists() ) Events.instance().raiseEvent("org.jboss.seam.postRemoveVariable." + name);
}
public String[] getNames()
{
Set<String> results = getNamesFromContext();
results.removeAll(removals);
results.addAll( additions.keySet() ); //after, to override
return results.toArray(new String[]{});
}
private Set<String> getNamesFromContext()
{
//TODO: note that this is called from Contexts.destroy(),
// after the Seam-managed txn was committed, but
// this implementation requires a hit to the database!
HashSet<String> results = new HashSet<String>();
org.jbpm.taskmgmt.exe.TaskInstance taskInstance = getTaskInstance();
if (taskInstance==null) {
ContextInstance context = getContextInstance();
if (context!=null) {
Map variables = context.getVariables();
if (variables != null) {
results.addAll(variables.keySet());
}
}
} else {
results.addAll( taskInstance.getVariables().keySet() );
}
return results;
}
public Object get(Class clazz)
{
return get( Component.getComponentName(clazz) );
}
public void clear()
{
additions.clear();
removals.addAll( getNamesFromContext() );
}
/**
* Propagate all additions and removals to the jBPM database if
* there is a current process instance, or do nothing if there
* is no current process instance.
*/
public void flush()
{
if ( !additions.isEmpty() || !removals.isEmpty() )
{
org.jbpm.taskmgmt.exe.TaskInstance taskInstance = getTaskInstance();
if (taskInstance==null)
{
org.jbpm.graph.exe.ProcessInstance processInstance = getProcessInstance();
if ( processInstance==null )
{
log.debug( "no process instance to persist business process state" );
return; //don't clear the additions and removals
}
else
{
flushToProcessInstance(processInstance);
}
}
else
{
flushToTaskInstance(taskInstance);
}
additions.clear();
removals.clear();
}
}
private void flushToTaskInstance(org.jbpm.taskmgmt.exe.TaskInstance taskInstance)
{
log.debug( "flushing to task instance: " + taskInstance.getId() );
for ( Map.Entry<String, Object> entry: additions.entrySet() )
{
taskInstance.setVariableLocally( entry.getKey(), entry.getValue() );
}
for ( String name: removals )
{
taskInstance.deleteVariableLocally(name);
}
}
private void flushToProcessInstance(org.jbpm.graph.exe.ProcessInstance processInstance)
{
log.debug( "flushing to process instance: " + processInstance.getId() );
ContextInstance contextInstance = processInstance.getContextInstance();
for ( Map.Entry<String, Object> entry: additions.entrySet() )
{
contextInstance.setVariable( entry.getKey(), entry.getValue() );
}
for ( String name: removals )
{
contextInstance.deleteVariable(name);
}
}
private ContextInstance getContextInstance()
{
org.jbpm.graph.exe.ProcessInstance processInstance = getProcessInstance();
return processInstance==null ? null : processInstance.getContextInstance();
}
private org.jbpm.graph.exe.ProcessInstance getProcessInstance()
{
Init init = Init.instance(); //may be null in some tests
if ( init==null || !init.isJbpmInstalled() )
{
return null;
}
else
{
return ProcessInstance.instance();
}
}
private org.jbpm.taskmgmt.exe.TaskInstance getTaskInstance()
{
Init init = Init.instance(); //may be null in some tests
if ( init==null || !init.isJbpmInstalled() )
{
return null;
}
else
{
return TaskInstance.instance();
}
}
}