/* Name: - BeanContainer 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.io.FileNotFoundException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.core.io.Resource; import com.google.common.collect.Lists; import com.processpuzzle.application.domain.Application; import com.processpuzzle.commons.generics.GenericTypeParameterInvestigator; import com.processpuzzle.commons.persistence.Entity; import com.processpuzzle.commons.spring.BeanName; import com.processpuzzle.persistence.domain.EntityFactory; import com.processpuzzle.persistence.domain.GenericFactory; public class BeanContainer extends TransientApplicationContext implements com.processpuzzle.application.configuration.domain.ApplicationContext { private Resource containerDefinitionResource; private GenericApplicationContext springApplicationContext; private Map<Class<? extends Entity>, String> entityFactories; BeanContainer( Application application, Resource definitionResource ) { super( application ); this.containerDefinitionResource = definitionResource; } //Public mutators @Override public void setUpTransientComponents() { springApplicationContext = new GenericApplicationContext(); XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader( springApplicationContext ); try{ xmlReader.loadBeanDefinitions( containerDefinitionResource ); springApplicationContext.refresh(); }catch( BeanDefinitionStoreException e ){ throw new ConfigurationSetUpException( "BeanContainer", e ); }catch( Exception e ){ throw new ConfigurationSetUpException( "BeanContainer", e ); } } @Override public void tearDownTransientComponents() { if( springApplicationContext != null ) springApplicationContext.close(); springApplicationContext = null; } //Public accessors public Object getBean( String beanName ) { Object bean = null; try{ bean = springApplicationContext.getBean( beanName ); }catch( NoSuchBeanDefinitionException e ){ throw new UndefinedBeanException( beanName, containerDefinitionResource.getFilename() ); } return bean; } @SuppressWarnings("unchecked") public <F extends EntityFactory<?>> F getEntityFactory( Class<F> factoryClass ) { String beanName = determineBeanNameFromFactoryClass( factoryClass ); return (F) getBean( beanName ); } public EntityFactory<?> getEntityFactoryByEntityClass( Class<? extends Entity> entityClass ) { List<String> targetPackageNames = Lists.newArrayList(); targetPackageNames.add( "com.processpuzzle" ); targetPackageNames.add( "com.itkodex" ); return this.getEntityFactoryByEntityClass( targetPackageNames, entityClass ); } public EntityFactory<?> getEntityFactoryByEntityClass( List<String> targetPackageNames, Class<? extends Entity> entityClass ) { entityClass.getClass(); if( entityFactories == null ) discoverFactoryImplementations( targetPackageNames ); return (EntityFactory<?>) getBean( entityFactories.get( entityClass )); } //Properties public ApplicationContext getApplicationContext() { return springApplicationContext; } private <F> String determineBeanNameFromFactoryClass( Class<F> factoryClass ) { return BeanName.determineBeanNameFromClass( factoryClass ); } @SuppressWarnings("unchecked") private Class<? extends Entity> determineFactoriesTargetClass( Class<?> anyClass ) { Class<? extends EntityFactory<?>> factoryClass = (Class<? extends EntityFactory<?>>) anyClass; Class<? extends Entity> entityClass = (Class<? extends Entity>) GenericTypeParameterInvestigator.getTypeParameter( factoryClass, 0 ); return entityClass; } //Protected, private helper methods private void discoverFactoryImplementations( List<String> targetPackageNames ) { entityFactories = new HashMap<Class<? extends Entity>, String>(); RunTimeClassHierarchyAnalyser subClassIdentifier = new RunTimeClassHierarchyAnalyser(); try{ Set<Class<?>> factories = subClassIdentifier.findSubClasses( targetPackageNames, GenericFactory.class.getName() ); for( Class<?> factoryClass : factories ) { Class<? extends Entity> targetEntityClass = determineFactoriesTargetClass( factoryClass ); if( targetEntityClass == null ) log.error( "Factory: '" + "' dosn't have Entity parameter!" ); else { entityFactories.put( targetEntityClass, determineBeanNameFromFactoryClass( factoryClass ) ); log.debug( "BeanContainer: Factory implementation '" + targetEntityClass + "' added." ); } } }catch( FileNotFoundException e ){ throw new ConfigurationSetUpException( "BeanContainer", e ); } } }