/*
Name:
- PersistenceContext
Description:
-
Requires:
-
Provides:
-
Part of: ProcessPuzzle Framework, Domain and Business Model Ready Architecture. Provides content, workflow and social networking functionality.
http://www.processpuzzle.com
ProcessPuzzle - Content and Workflow Management Integration Business Platform
Author(s):
- Zsolt Zsuffa
Copyright: (C) 2011 This program is free software: you can redistribute it and/or modify it under the terms of the
GNU General Public License as published by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.processpuzzle.application.configuration.domain;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.commons.configuration.HierarchicalConfiguration;
import com.processpuzzle.application.domain.Application;
import com.processpuzzle.commons.persistence.Entity;
import com.processpuzzle.commons.persistence.PersistenceStrategy;
import com.processpuzzle.commons.persistence.PersistentObject;
import com.processpuzzle.commons.persistence.Repository;
import com.processpuzzle.commons.persistence.RepositoryEventHandler;
import com.processpuzzle.fundamental_types.domain.OpAssertion;
import com.processpuzzle.persistence.domain.DefaultPersistenceStrategy;
import com.processpuzzle.persistence.domain.DefaultRepositoryEventHandler;
import com.processpuzzle.persistence.domain.GenericRepository;
import com.processpuzzle.persistence.domain.PersistentClassList;
import com.processpuzzle.persistence.domain.RepositoryClassList;
import com.processpuzzle.persistence.domain.UndefinedPersistentDataInitializationStrategyException;
public class PersistenceContext extends PersistentApplicationContext implements ApplicationContext {
public static final String ENTITY_CLASS_PROPERTY_NAME = "entityClass";
public static final String ENTITY_CLASS_PROPERTY_NODE_SELECTOR = "persistence/entities";
public static final String HIBERNATE_STRATEGY = "hibernate";
public static final String HIERARCHICAL_PROPERTY_SELECTOR_DELIMITER = ".";
public static final String NAME_SPACE_PREFIX = "pr:";
private ProcessPuzzleContext applicationContext;
private Map<Class<? extends Repository<?>>, Repository<?>> availableRepositories = new HashMap<Class<? extends Repository<?>>, Repository<?>>();
private Map<Class<? extends Repository<?>>, GenericRepository<?>> domainClassRepositoryMappings = new HashMap<Class<? extends Repository<?>>, GenericRepository<?>>();
private List<Class<? extends PersistentObject>> persistentClasses = new ArrayList<Class<? extends PersistentObject>>();
private PersistentDataInitializationStrategies persistentDataInitializationStrategy = null;
private PropertyContext propertyContext = null;
private Map<String, PersistenceStrategy> supportedStrategies = new HashMap<String, PersistenceStrategy>();
// Constructors
PersistenceContext( Application application ) {
super( application );
this.applicationContext = application.getContext();
this.propertyContext = applicationContext.getPropertyContext();
}
// Public mutators and accessors
// Properties
public Map<Class<? extends Repository<?>>, Repository<?>> getAvailableRepositories() { return availableRepositories; }
public int getPersistentClassesSize() { return persistentClasses.size(); }
public Iterator<Class<? extends PersistentObject>> getPersistentClassesIterator() { return persistentClasses.iterator(); }
public PersistentDataInitializationStrategies getPersistentDataInitializationStrategy() { return persistentDataInitializationStrategy; }
@SuppressWarnings( "unchecked" )
public <R extends Repository<?>> R getRepositoryInstance( Class<R> repositoryClass ) {
R repository = (R) availableRepositories.get( repositoryClass );
if( repository != null )
return repository;
else
throw new UndeclaredRepositoryException( repositoryClass );
}
public Repository<?> getRepositoryByAggregateRootClass( Class<? extends Entity> entityClass ) {
Repository<?> repository = domainClassRepositoryMappings.get( entityClass );
if( repository != null )
return repository;
else{
repository = findRepositoryBySuperClass( entityClass );
if( repository == null ){
throw new UndeclaredAggregateRootRepositoryMapping( entityClass );
}else{
return repository;
}
}
}
public PersistenceStrategy getStrategy( String strategyName ) {
PersistenceStrategy strategy = supportedStrategies.get( strategyName );
if( strategy == null )
throw new Error( "PersistenceStrategy `" + strategyName + "` not found!" );
return strategy;
}
public Map<String, PersistenceStrategy> getSupportedStrategies() {
return supportedStrategies;
}
public boolean isConfigured() { return isConfigured; }
// Protected, private helper methods
@Override
protected void setUpTransientComponents() {}
@Override
protected void setUpPersistentComponents() {
determinePersistentClasses();
determinePersistentDataInitializationStrategy();
instantiateSupportedStrategies();
Map<Class<? extends Repository<?>>, PersistenceStrategy> repositories = new HashMap<Class<? extends Repository<?>>, PersistenceStrategy>();
repositories = determineRepositories();
instantiateRepositories( repositories );
configureStrategies();
buildDomainClassRepositoryMapping();
}
@Override
protected void tearDownTransientComponents() {
}
@SuppressWarnings( "unchecked" )
@Override
protected void tearDownPersistentComponents() {
domainClassRepositoryMappings.clear();
availableRepositories.clear();
for( Iterator iter = supportedStrategies.entrySet().iterator(); iter.hasNext(); ){
Map.Entry<String, DefaultPersistenceStrategy> mapEntry = (Map.Entry<String, DefaultPersistenceStrategy>) iter.next();
DefaultPersistenceStrategy strategy = mapEntry.getValue();
strategy.release();
}
supportedStrategies.clear();
}
@SuppressWarnings( "unchecked" )
private void buildDomainClassRepositoryMapping() {
for( Iterator iter = availableRepositories.entrySet().iterator(); iter.hasNext(); ){
Map.Entry<Class, GenericRepository> availableRepositoryEntry = (Map.Entry<Class, GenericRepository>) iter.next();
GenericRepository repository = availableRepositoryEntry.getValue();
domainClassRepositoryMappings.put( repository.getSupportedAggregateRootClass(), repository );
}
}
private void configureStrategies() {
for( Map.Entry<String, PersistenceStrategy> strategyEntry : supportedStrategies.entrySet() ){
Map.Entry<String, PersistenceStrategy> strategiesEntry = strategyEntry;
PersistenceStrategy strategy = strategiesEntry.getValue();
strategy.configure();
}
}
private void determinePersistentClasses() {
determinePersistentClassesFromConfigurationFile();
determinePersistentClassesFromHardCodedClass();
}
private void determinePersistentDataInitializationStrategy() {
String strategyProperty = propertyContext.getProperty( PropertyKeys.APPLICATION_DATABASE_CREATION.getDefaultKey() );
if( strategyProperty.equals( PersistentDataInitializationStrategies.create.asString() ) ){
persistentDataInitializationStrategy = PersistentDataInitializationStrategies.create;
}else if( strategyProperty.equals( PersistentDataInitializationStrategies.dropAndCreate.asString() ) ){
persistentDataInitializationStrategy = PersistentDataInitializationStrategies.dropAndCreate;
}else if( strategyProperty.equals( PersistentDataInitializationStrategies.update.asString() ) ){
persistentDataInitializationStrategy = PersistentDataInitializationStrategies.update;
}else
throw new UndefinedPersistentDataInitializationStrategyException( strategyProperty );
}
@SuppressWarnings("unchecked")
private void determinePersistentClassesFromConfigurationFile() {
List<String> persistentClassNames = propertyContext.getPropertyList( PropertyKeys.PERSISTENCE_PERSISTENT_CLASSES.getDefaultKey() );
for( Iterator<String> iter = persistentClassNames.iterator(); iter.hasNext(); ){
String className = (String) iter.next();
Class<? extends PersistentObject> persistentClass = null;
try{
persistentClass = (Class<? extends PersistentObject>) Class.forName( className );
}catch( ClassNotFoundException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}
persistentClasses.add( persistentClass );
}
}
@SuppressWarnings("unchecked")
private void determinePersistentClassesFromHardCodedClass() {
String classListClassName = propertyContext.getProperty( PropertyKeys.PERSISTENCE_PERSISTENT_CLASSLIST_CLASS.getDefaultKey() );
if( classListClassName != null ){
PersistentClassList persistentClassList = null;
try{
Class<? extends PersistentObject> classListClass = (Class<? extends PersistentObject>) Class.forName( classListClassName );
persistentClassList = (PersistentClassList) classListClass.newInstance();
}catch( Exception e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}
persistentClasses.addAll( persistentClassList.getAggregateRoots() );
persistentClasses.addAll( persistentClassList.getEntities() );
persistentClasses.addAll( persistentClassList.getValueObjects() );
}
}
private Map<Class<? extends Repository<?>>, PersistenceStrategy> determineRepositories() {
Map<Class<? extends Repository<?>>, PersistenceStrategy> repositoryClasses = new HashMap<Class<? extends Repository<?>>, PersistenceStrategy>();
repositoryClasses.putAll( determineRepositoriesFromConfigurationFile() );
repositoryClasses.putAll( determineRepositoryFromHardCodedClass() );
return repositoryClasses;
}
@SuppressWarnings("unchecked")
private Map<Class<? extends Repository<?>>, PersistenceStrategy> determineRepositoryFromHardCodedClass() {
Map<Class<? extends Repository<?>>, PersistenceStrategy> repositoryClasses = new HashMap<Class<? extends Repository<?>>, PersistenceStrategy>();
String repositoryClassListClassName = propertyContext.getProperty( PropertyKeys.PERSISTENCE_REPOSITORY_LIST_CLASS.getDefaultKey() );
if( repositoryClassListClassName != null ){
RepositoryClassList repositoryClassList = null;
PersistenceStrategy strategy = null;
try{
Class<RepositoryClassList> classListClass = (Class<RepositoryClassList>) Class.forName( repositoryClassListClassName );
repositoryClassList = (RepositoryClassList) classListClass.newInstance();
Object[] parameters = { classListClass.getName() };
String strategyName = propertyContext.getProperty( PropertyKeys.createKey( PropertyKeys.PERSISTENCE_REPOSITORY_LIST_STRATEGY.getDefaultKey(), parameters ) );
strategy = supportedStrategies.get( strategyName );
}catch( Exception e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}
for( Class<? extends Repository<?>> repositoryClass : repositoryClassList.gerRepositories() ) {
repositoryClasses.put( repositoryClass, strategy );
}
}
return repositoryClasses;
}
@SuppressWarnings("unchecked")
private Map<? extends Class<Repository<?>>, PersistenceStrategy> determineRepositoriesFromConfigurationFile() {
Map<Class<Repository<?>>, PersistenceStrategy> repositoryClasses = new HashMap<Class<Repository<?>>, PersistenceStrategy>();
List<String> repositoryClassNames = propertyContext.getPropertyList( PropertyKeys.PERSISTENCE_REPOSITORY_CLASS.getDefaultKey() );
for( String repositoryClassName : repositoryClassNames ){
Class<Repository<?>> repositoryClass = null;
try{
repositoryClass = (Class<Repository<?>>) Class.forName( repositoryClassName );
Object[] parameters = { repositoryClass.getName() };
String strategyName = propertyContext.getPropertyByParameter( PropertyKeys.PERSISTENCE_REPOSITORY_CLASS_STRATEGY.getDefaultKey(), parameters );
PersistenceStrategy strategy = supportedStrategies.get( strategyName );
repositoryClasses.put( repositoryClass, strategy );
}catch( ClassNotFoundException e ){
throw new RepositoryInstantiationException( repositoryClassName, propertyContext, e );
}catch( Exception e ){
throw new RepositoryInstantiationException( repositoryClassName, propertyContext, e );
}
}
return repositoryClasses;
}
private Repository<?> findRepositoryBySuperClass( Class<? extends Entity> entityClass ) {
GenericRepository<?> repository = null;
boolean found = false;
Class<?> superClass = entityClass.getSuperclass();
while( !found && superClass != null ){
repository = domainClassRepositoryMappings.get( superClass );
if( repository != null ){
found = true;
}else{
superClass = superClass.getSuperclass();
}
}
return repository;
}
private void instantiateSupportedStrategies() {
List<String> supportedStrategyNames = propertyContext.getPropertyList( PropertyKeys.PERSISTENCE_STRATEGY_NAME.getDefaultKey() );
Iterator<String> supportedStrategyIterator = supportedStrategyNames.iterator();
Integer strategyIndex = 0;
while( supportedStrategyIterator.hasNext() ){
String supportedStrategyName = supportedStrategyIterator.next();
Object[] parameters = { supportedStrategyName };
List<String> eventHandlerNames = propertyContext.getPropertyListByParameter( PropertyKeys.PERSISTENCE_STRATEGY_EVENT_HANDLERS.getDefaultKey(), parameters );
List<RepositoryEventHandler> eventHandlers = new LinkedList<RepositoryEventHandler>();
Iterator<String> eventHandlersIterator = eventHandlerNames.iterator();
Integer eventHandlerIndex = 0;
while( eventHandlersIterator.hasNext() ){
String eventHandlerName = eventHandlersIterator.next();
String configurationAt = MessageFormat.format( PropertyKeys.REPOSITORY_EVENT_HANDLER.getDefaultKey(), new Object[] { strategyIndex.toString(), eventHandlerIndex.toString() } );
HierarchicalConfiguration eventHandlerConfiguration = propertyContext.getConfigurationAt( configurationAt );
// ParametrizedConfigurationPropertyHandler propertyHandler = new ParametrizedConfigurationPropertyHandler( eventHandlerConfiguration );
String eventHandlerClassName = eventHandlerConfiguration.getString( PropertyKeys.EVENT_HANDLER_CLASS.getDefaultKey() );
DefaultRepositoryEventHandler eventHandler = instantiateEventHandler( eventHandlerName, eventHandlerClassName, eventHandlerConfiguration );
eventHandlers.add( eventHandler );
eventHandlerIndex++;
}
PersistenceStrategy strategy = new DefaultPersistenceStrategy( supportedStrategyName, eventHandlers );
supportedStrategies.put( supportedStrategyName, strategy );
strategyIndex++;
}
}
@SuppressWarnings( "unchecked" )
private DefaultRepositoryEventHandler instantiateEventHandler( String eventHandlerName, String eventHandlerClassName,
HierarchicalConfiguration eventHandlerConfiguration ) {
OpAssertion.ppAssert( eventHandlerName != null,
"PersistenceContext.instantitateEventHandler: RepositoryEventHandler name can't be null." );
OpAssertion.ppAssert( eventHandlerClassName != null,
"PersistenceContext.instantitateEventHandler: RepositoryEventHandler class name can't be null." );
DefaultRepositoryEventHandler eventHandler = null;
if( eventHandlerClassName != null ){
try{
Class eventHandlerClass = Class.forName( eventHandlerClassName );
Class[] parameterTypes = new Class[] { String.class, HierarchicalConfiguration.class, List.class,
PersistentDataInitializationStrategies.class };
Constructor eventHandlerConstructor = eventHandlerClass.getConstructor( parameterTypes );
Object[] constructorArguments = { eventHandlerName, eventHandlerConfiguration, persistentClasses,
persistentDataInitializationStrategy };
eventHandler = (DefaultRepositoryEventHandler) eventHandlerConstructor.newInstance( constructorArguments );
}catch( ClassNotFoundException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( SecurityException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( NoSuchMethodException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( IllegalArgumentException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( InstantiationException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( IllegalAccessException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( InvocationTargetException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}
}
return eventHandler;
}
private void instantiateRepositories( Map<Class<? extends Repository<?>>, PersistenceStrategy> repositoryClasses ) {
for( Map.Entry<Class<? extends Repository<?>>, PersistenceStrategy> repositoryEntry : repositoryClasses.entrySet() ) {
Class<? extends Repository<?>> repositoryClass = repositoryEntry.getKey();
PersistenceStrategy strategy = repositoryEntry.getValue();
GenericRepository<?> repository = instantiateRepository( repositoryClass, strategy );
availableRepositories.put( repositoryClass, repository );
logger.debug( "Repository: '" + repositoryClass.getSimpleName() + "' instantiated." );
}
}
@SuppressWarnings( "unchecked" )
private GenericRepository<?> instantiateRepository( Class repositoryClass, PersistenceStrategy strategy ) {
GenericRepository repository = null;
if( repositoryClass != null ){
Class[] parameterTypes = new Class[] { PersistenceStrategy.class, ProcessPuzzleContext.class };
Constructor repositoryConstructor;
try{
repositoryConstructor = repositoryClass.getConstructor( parameterTypes );
Object[] constructorArguments = { strategy, applicationContext };
repository = (GenericRepository) repositoryConstructor.newInstance( constructorArguments );
}catch( SecurityException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( NoSuchMethodException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( IllegalArgumentException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( InstantiationException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( IllegalAccessException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}catch( InvocationTargetException e ){
throw new PersistenceContextSetUpException( propertyContext, e );
}
}
return repository;
}
}