org.openbp.server.persistence.BasicPersistenceContextProvider Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openbp-server Show documentation
Show all versions of openbp-server Show documentation
The OpenBP process engine (main module)
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openbp.server.persistence;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openbp.common.SpringUtil;
import org.openbp.common.logger.LogUtil;
import org.openbp.common.util.ToStringHelper;
import org.openbp.server.context.TokenContext;
import org.openbp.server.context.TokenContextImpl;
import org.openbp.server.context.WorkflowTask;
import org.openbp.server.context.WorkflowTaskImpl;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Abstract implementation of a persistence context provider.
* Uses a ThreadLocal to bind contexts to the current thread.
* The final implementation needs to supply the {@link #createPersistenceContext} method.
* Also provides the {@link #unbindThreadContext} method that contexts can call from their
* {@link PersistenceContext#release} method.
*
* @author Heiko Erhardt
*/
public abstract class BasicPersistenceContextProvider
implements PersistenceContextProvider, ApplicationContextAware
{
/** Lifecycle listeners */
private List listenerList = new ArrayList ();
/** Thread local that holds the persistence context bound to this thread */
protected ThreadLocal threadContext = new ThreadLocal();
/** Spring application context if the process server was instantiated by the Spring framework */
protected ApplicationContext applicationContext;
/** Transactionality flag */
private boolean transactional = true;
/**
* Constructor.
*/
public BasicPersistenceContextProvider()
{
// Default: Transactional behaviour
setTransactional(true);
}
/**
* Implementation of the ApplicationContextAware interface.
* See org.springframework.context.ApplicationContextAware.
* Called by the Spring framework after bean construction.
*
* @param applicationContext Spring application context the process server was instantiated by the Spring framework
*/
public void setApplicationContext(ApplicationContext applicationContext)
{
this.applicationContext = applicationContext;
}
/**
* Gets the transactionality flag.
*/
public boolean isTransactional()
{
return transactional;
}
/**
* Sets the transactionality flag.
*/
public void setTransactional(boolean transactional)
{
this.transactional = transactional;
}
/**
* Returns a string representation of this object.
*/
public String toString()
{
return ToStringHelper.toString(this);
}
//////////////////////////////////////////////////
// @@ Persistence context management
//////////////////////////////////////////////////
/**
* Obtains a persistence context that can be used to persist process engine objects related to the given token context.
* Creates a new context if none exists for this thread.
*
* @return The persistence context
* @throws PersistenceException On error (e. g. if there is no database defined or a database session cannot be established)
*/
public PersistenceContext obtainPersistenceContext()
throws PersistenceException
{
PersistenceContext context = (PersistenceContext) threadContext.get();
if (context == null)
{
context = createPersistenceContext();
threadContext.set(context);
LogUtil.debug(getClass(), "Created thread persistence context $0.", context);
}
return context;
}
/**
* Obtains an existing persistence context that can be used to persist process engine objects related to the given token context.
*
* @return The persistence context or null if none exists
*/
public PersistenceContext obtainExistingPersistenceContext()
{
return (PersistenceContext) threadContext.get();
}
/**
* Creates a new persistence context.
*
* @return The new context
* @throws PersistenceException On error (e. g. if there is no database defined or a database session cannot be established)
*/
protected abstract PersistenceContext createPersistenceContext()
throws PersistenceException;
/**
* Releases a persistence context obtained by the obtainPersistenceContext method.
* After calling this method, the context must not be used any more.
*
* @param context Context to release
*/
protected void unbindThreadContext(PersistenceContext context)
{
threadContext.set(null);
LogUtil.debug(getClass(), "Unbound persistence context $0 from current thread.", context);
}
//////////////////////////////////////////////////
// @@ Entity creation
//////////////////////////////////////////////////
protected Map entityToBeanClassMap = new HashMap();
/**
* Returns the actual bean class of a given entity.
*
* @param entityClass Entity (interface) class that the instance must match
* @return The class of the instantiated bean for the given entity class or the argument if no entity definition can be found
*/
public Class determineEntityClass(Class entityClass)
{
Class beanClass = entityToBeanClassMap.get(entityClass);
if (beanClass == null)
{
try
{
Object bean = createEntity(entityClass, null);
beanClass = bean.getClass();
}
catch (NoSuchBeanDefinitionException e)
{
beanClass = entityClass;
}
entityToBeanClassMap.put(entityClass, beanClass);
}
return beanClass;
}
/**
* Returns a new instance of an entity.
* The application context will provide a prototype bean matching the entity class.
* If no matching bean definition is found, the method tries to apply defaults for standard OpenBP entities.
*
* @param entityClass Entity (interface or object) class that the instance must match.
* @param pc Persistence context that creates the entity
* @return The new entity instance
*/
public Object createEntity(Class entityClass, PersistenceContext pc)
{
Object entity = null;
try
{
entity = applicationContext.getBean(entityClass);
}
catch (NoSuchBeanDefinitionException e)
{
// Try to apply defaults for token context and workflow task
entity = tryEntityDefaults(entityClass);
if (entity == null)
throw e;
// Perform auto-wiring on the default bean
SpringUtil.autowireBean(entity, applicationContext);
}
fireOnCreate(entity, pc);
return entity;
}
/**
* Tries to return a new instance of a standard OpenBP entity class.
*
* @param entityClass Entity class that the entity must match
* @return The new entity instance or null if the class does not denote a standard OpenBP entities
*/
protected Object tryEntityDefaults(Class entityClass)
{
if (entityClass.equals(TokenContext.class))
return new TokenContextImpl();
if (entityClass.equals(WorkflowTask.class))
return new WorkflowTaskImpl();
return null;
}
//////////////////////////////////////////////////
// @@ Lifecycle support
//////////////////////////////////////////////////
/**
* Adds a lifecycle listener.
*
* @param listener Listener
*/
public void addEntityLifecycleListener(EntityLifecycleListener listener)
{
if (! listenerList.contains(listener))
{
listenerList.add(listener);
}
}
/**
* Removes a lifecycle listener.
*
* @param listener Listener
*/
public void removeEntityLifecycleListener(EntityLifecycleListener listener)
{
listenerList.remove(listener);
}
public void fireOnCreate(Object entity, PersistenceContext pc)
{
if (entity instanceof PersistentObject)
{
((PersistentObject) entity).onCreate();
}
EntityLifecycleEvent event = new EntityLifecycleEvent(entity, pc);
for (EntityLifecycleListener listener : listenerList)
{
listener.onCreate(event);
}
}
public void fireOnLoad(Object entity, PersistenceContext pc)
{
// Perform auto-wiring on the default bean
SpringUtil.autowireBean(entity, applicationContext);
if (entity instanceof PersistentObject)
{
((PersistentObject) entity).onLoad();
}
EntityLifecycleEvent event = new EntityLifecycleEvent(entity, pc);
for (EntityLifecycleListener listener : listenerList)
{
listener.onLoad(event);
}
}
public void fireBeforeSave(Object entity, PersistenceContext pc)
{
if (entity instanceof PersistentObject)
{
((PersistentObject) entity).beforeSave();
}
EntityLifecycleEvent event = new EntityLifecycleEvent(entity, pc);
for (EntityLifecycleListener listener : listenerList)
{
listener.beforeSave(event);
}
}
public void fireAfterSave(Object entity, PersistenceContext pc)
{
if (entity instanceof PersistentObject)
{
((PersistentObject) entity).afterSave();
}
EntityLifecycleEvent event = new EntityLifecycleEvent(entity, pc);
for (EntityLifecycleListener listener : listenerList)
{
listener.afterSave(event);
}
}
public void fireBeforeDelete(Object entity, PersistenceContext pc)
{
if (entity instanceof PersistentObject)
{
((PersistentObject) entity).beforeDelete();
}
EntityLifecycleEvent event = new EntityLifecycleEvent(entity, pc);
for (EntityLifecycleListener listener : listenerList)
{
listener.beforeDelete(event);
}
}
public void fireAfterDelete(Object entity, PersistenceContext pc)
{
if (entity instanceof PersistentObject)
{
((PersistentObject) entity).afterDelete();
}
EntityLifecycleEvent event = new EntityLifecycleEvent(entity, pc);
for (EntityLifecycleListener listener : listenerList)
{
listener.afterDelete(event);
}
}
}