All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openbp.server.persistence.BasicPersistenceContextProvider Maven / Gradle / Ivy

There is a newer version: 0.9.11
Show newest version
/*
 *   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);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy