/* Name: - Application 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/>. */ /* * Created on Feb 12, 2006 * * TODO To change the template for this generated file go to * Window - Preferences - Java - Code Style - Code Templates */ package com.processpuzzle.application.domain; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.configuration.HierarchicalConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; import com.processpuzzle.application.configuration.domain.PersistentDataInitializationStrategies; import com.processpuzzle.application.configuration.domain.ProcessPuzzleApplicationComponent; import com.processpuzzle.application.configuration.domain.ProcessPuzzleContext; import com.processpuzzle.application.configuration.domain.PropertyContext; import com.processpuzzle.application.configuration.domain.PropertyContextOverrides; import com.processpuzzle.application.configuration.domain.PropertyKeys; import com.processpuzzle.application.resource.domain.DataLoader; import com.processpuzzle.application.resource.domain.HardCodedDataLoader; import com.processpuzzle.application.resource.domain.XmlDataLoader; import com.processpuzzle.application.security.domain.PredefinedUsersLoader; import com.processpuzzle.application.security.domain.User; import com.processpuzzle.application.security.domain.UserRepository; import com.processpuzzle.commons.persistence.AggregateRoot; import com.processpuzzle.fundamental_types.domain.GenericEntity; import com.processpuzzle.party.artifact.PredefinedUserDataSheetsCreator; import com.processpuzzle.persistence.domain.DefaultUnitOfWork; import com.processpuzzle.persistence.query.domain.DefaultQueryContext; import com.processpuzzle.user_session.domain.UserRequestManager; public abstract class Application extends GenericEntity<Application> implements AggregateRoot { private static final String PARAMETER_TYPE_ELEMENT_NAME = "type"; private static final String INSTANTIATION_ARGUMENTS_SELECTOR = "dl:instantiationArguments.dl:argument"; private static Logger log = LoggerFactory.getLogger( Application.class ); protected ResourceLoader resourceLoader; protected String applicationName; protected String applicationVersion; protected String applicationDescription; protected ExecutionStatus executionStatus = ExecutionStatus.stopped; protected InstallationStatus installationStatus = InstallationStatus.notInstalled; protected ProcessPuzzleContext applicationContext; protected String configurationDescriptorPath = "classpath:com/itcodex/objectpuzzle/framework/configuration/domaintier/configuration_descriptor.xml"; protected Map<Application.Events, List<ApplicationEvent>> history = new LinkedHashMap<Events, List<ApplicationEvent>>(); protected List<DataLoader> dataLoaders = new ArrayList<DataLoader>(); // Constructors protected Application( String configurationDescriptorPath ) { this( configurationDescriptorPath, new DefaultResourceLoader() ); } protected Application( String configurationDescriptorPath, ResourceLoader resourceLoader ) { this.configurationDescriptorPath = configurationDescriptorPath; this.resourceLoader = resourceLoader; defineApplicationDescription(); determineInstallationConfiguration(); determineInstallationStatus(); } public @Override @SuppressWarnings( "unchecked" ) ApplicationIdentity getDefaultIdentity() { DefaultQueryContext context = new DefaultQueryContext(); context.addTextValueFor( "applicationNameValue", applicationName ); context.addTextValueFor( "applicationVersionValue", applicationVersion ); return new ApplicationIdentity( context ); } // Public mutators public void install() throws ApplicationException { log.info( "Installation of application: " + applicationName + " begins." ); if( installationStatus.equals( InstallationStatus.installed ) ) throw new ReinstallationException( this ); PropertyContextOverrides overrides = defineInstallationOverrides(); try{ setUpApplicationContext( Action.install, overrides ); applicationContext.createSystemInstallerRequestContext( this ); persistSystemInstallerUser(); dataLoaders = determineDataLoaders(); executeDataLoaders( Action.install ); executionStatus = ExecutionStatus.running; installationStatus = InstallationStatus.installed; addEventToHistory( Events.installed ); }catch( Exception e ){ throw new ApplicationInstallationException( this, e ); } log.info( "Installation of application: " + applicationName + " finished. \n" ); } public void unInstall() { if( executionStatus == ExecutionStatus.running ) stop(); log.info( "Uninstallation of application: " + applicationName + " begins." ); executionStatus = ExecutionStatus.stopped; installationStatus = InstallationStatus.notInstalled; log.info( "Uninstallation of application: " + applicationName + " finished. \n" ); } public void start() throws ApplicationException { start( null ); } public void start( PropertyContextOverrides overrides ) throws ApplicationException { if( executionStatus == ExecutionStatus.running ) return; log.info( "Starting of application: " + applicationName + " begins." ); setUpApplicationContext( Action.start, overrides ); executionStatus = ExecutionStatus.running; addEventToHistory( Events.started ); log.info( "Starting of application: " + applicationName + " ended." ); } public void stop() { if( executionStatus == ExecutionStatus.stopped ) return; applicationContext.tearDown( Action.stop ); applicationContext = null; executionStatus = ExecutionStatus.stopped; log.info( "Application stopped." ); }; public User authenticateUser( String userName, String password ) { UserRepository repository = (UserRepository) applicationContext.getRepository( UserRepository.class ); DefaultUnitOfWork work = new DefaultUnitOfWork( true ); User userInQuestion = repository.findUserByName( work, userName ); if( userInQuestion != null && userInQuestion.getPassword().equals( password ) ) return userInQuestion; else return null; } public boolean loginUser( String userName, String password ) { User user = authenticateUser( userName, password ); if( user != null ) return true; else return false; } // Public accessors public List<ApplicationEvent> findApplicationEventsByType( Events searchedEvent ) { return history.get( searchedEvent ); } @Override public boolean equals( Object objectToCheck ) { if( !(objectToCheck instanceof Application) ) return false; Application anotherApplication = (Application) objectToCheck; boolean returnValue = applicationName.equals( anotherApplication.applicationName ) && applicationVersion.equals( anotherApplication.applicationVersion ) && executionStatus.equals( anotherApplication.executionStatus ) && installationStatus.equals( anotherApplication.installationStatus ) && configurationDescriptorPath.equals( anotherApplication.configurationDescriptorPath ) && applicationDescription.equals( anotherApplication.applicationDescription ) && dataLoaders.equals( anotherApplication.dataLoaders ); return returnValue; } // Collection facades public int getHistorySize() { return history.size(); } // Properties public String getApplicationName() { return applicationName; } public String getApplicationVersion() { return applicationVersion; } public String getConfigurationDescriptorPath() { return configurationDescriptorPath; } public ProcessPuzzleContext getContext() { return applicationContext; } public List<DataLoader> getDataLoaders() { return dataLoaders; } public String getDescription() { return applicationDescription; } public ExecutionStatus getExecutionStatus() { return executionStatus; } public InstallationStatus getInstallationStatus() { return installationStatus; } // Embeded enumerations public enum InstallationStatus { installed, notInstalled } public enum ExecutionStatus { stopped, running, suspended } public enum Events { started, stopped, installed, unistalled, dataload, backup, restore } public enum Action { install, uninstall, start, stop } // Protedted, private helper methods protected abstract void defineApplicationDescription(); protected void runDataLoader( String property ) { String loaderClassName = (String) applicationContext.getProperty( property ); if( loaderClassName != null ){ try{ DataLoader loader = (DataLoader) Class.forName( loaderClassName ).newInstance(); loader.loadData(); }catch( Exception e ){ e.printStackTrace(); throw new Error( "The data loader: " + loaderClassName + " doesn't exist!" ); } } } protected void addEventToHistory( Events eventName ) { ApplicationEvent event = null; List<ApplicationEvent> eventList = history.get( eventName ); if( eventList == null ) eventList = new ArrayList<ApplicationEvent>(); switch( eventName ) { case started: event = new ApplicationStartedEvent(); break; case stopped: event = new ApplicationStopped(); break; case installed: event = new ApplicationInstallationEvent(); break; case dataload: event = new DataLoadEvent(); break; case backup: event = new BackupEvent(); break; case restore: event = new RestoreEvent(); break; default: break; } eventList.add( event ); history.put( eventName, eventList ); } protected @Override void defineIdentityExpressions() { identities.add( getDefaultIdentity() ); } private void addBusinessDefintionLoader( List<DataLoader> dataLoaders ) { String path = null; try{ path = determineBusinessDefintionsPaths(); XmlDataLoader businessDefinitionLoader = (XmlDataLoader) applicationContext.getBean( ProcessPuzzleApplicationComponent.BUSINESS_DEFINITION_LOADER.getComponentId() ); businessDefinitionLoader.setResourcePath( path ); dataLoaders.add( businessDefinitionLoader ); }catch( NoSuchBeanDefinitionException e ){ if( path != null && path != "" ) throw e; } } private void addPredefinedUsersDataSheetLoader( List<DataLoader> dataLoaders ) { PredefinedUserDataSheetsCreator userDataSheetCreator = new PredefinedUserDataSheetsCreator( applicationContext ); dataLoaders.add( userDataSheetCreator ); } private void addPredefinedUsersLoader( List<DataLoader> dataLoaders ) { PredefinedUsersLoader usersLoader = (PredefinedUsersLoader) applicationContext.getBean( ProcessPuzzleApplicationComponent.PREDEFINED_USERS_LOADER.getComponentId() ); usersLoader.setApplicationContext( applicationContext ); dataLoaders.add( usersLoader ); } private void addSystemArtifactsLoader( List<DataLoader> dataLoaders ) { String componentName = ProcessPuzzleApplicationComponent.SYSTEM_ARTIFACTS_LOADER.getComponentId(); try{ HardCodedDataLoader systemArtifactsLoader = (HardCodedDataLoader) applicationContext.getBean( componentName ); dataLoaders.add( systemArtifactsLoader ); }catch( NoSuchBeanDefinitionException e ){ log.warn( "SystemArtifactsLoder not found." ); throw e; } } private void determineInstallationConfiguration() {} private void determineInstallationStatus() {} private PropertyContextOverrides defineInstallationOverrides() { PropertyContextOverrides overrides = new PropertyContextOverrides(); overrides.addProperty( PropertyKeys.APPLICATION_DATABASE_CREATION, PersistentDataInitializationStrategies.dropAndCreate ); return overrides; } private List<DataLoader> determineDataLoaders() throws ApplicationException { List<DataLoader> dataLoaders = new ArrayList<DataLoader>(); determinePredefinedDataLoaders( dataLoaders ); determineCustomDataLoaders( dataLoaders ); return dataLoaders; } private void determinePredefinedDataLoaders( List<DataLoader> dataLoaders ) { addPredefinedUsersLoader( dataLoaders ); addBusinessDefintionLoader( dataLoaders ); addSystemArtifactsLoader( dataLoaders ); addPredefinedUsersDataSheetLoader( dataLoaders ); } private void determineCustomDataLoaders( List<DataLoader> dataLoaders ) throws ApplicationException { List<String> dataLoaderClassNames = applicationContext.getPropertyContext().getPropertyList( PropertyKeys.DATA_LOADER_CLASSES.getDefaultKey() ); Integer dataLoaderIndex = 0; for( Iterator<String> iter = dataLoaderClassNames.iterator(); iter.hasNext(); ){ String className = (String) iter.next(); String selector = MessageFormat.format( PropertyKeys.DATA_LOADER_CONFIGURATION.getDefaultKey(), new Object[] { dataLoaderIndex.toString() } ); HierarchicalConfiguration dataLoaderConfig = applicationContext.getPropertyContext().getConfigurationAt( selector ); DataLoader dataLoader = instantitateDataLoader( className, dataLoaderConfig ); dataLoaders.add( dataLoader ); dataLoaderIndex++; } } private String determineBusinessDefintionsPaths() { PropertyContext propertyContext = applicationContext.getPropertyContext(); List<String> businessDefinitionPaths = propertyContext.getPropertyList( PropertyKeys.BUSINESS_DEFINITION.getDefaultKey() ); if( businessDefinitionPaths.size() == 0 ) { throw new MissingRequiredConfigurationPropertyException( PropertyKeys.BUSINESS_DEFINITION.getDefaultKey(), configurationDescriptorPath ); } String combinedPath = ""; for( String path : businessDefinitionPaths ){ combinedPath += path + ";"; } return combinedPath; } private void executeDataLoaders( Action action ) throws ApplicationException { for( Iterator<DataLoader> iter = dataLoaders.iterator(); iter.hasNext(); ){ DataLoader dataLoader = iter.next(); if( (action == Action.install && dataLoader.isResultInPersistentObjects()) || (action == Action.start && !dataLoader.isResultInPersistentObjects()) ){ dataLoader.setResourceLoader( applicationContext.getResourceLoader() ); try{ dataLoader.loadData(); }catch( Exception e ){ throw new ApplicationInstallationException( applicationName, e ); } addEventToHistory( Events.dataload ); } } } @SuppressWarnings( "unchecked" ) private DataLoader instantitateDataLoader( String className, HierarchicalConfiguration dataLoaderConfig ) throws ApplicationException { DataLoader dataLoader = null; Constructor<DataLoader> dataLoaderConstructor; List<HierarchicalConfiguration> arguments = dataLoaderConfig.configurationsAt( INSTANTIATION_ARGUMENTS_SELECTOR ); Class<?>[] parameterTypes = new Class[arguments.size()]; Object[] parameterValues = new Object[arguments.size()]; try{ for( int j = 0; j < arguments.size(); j++ ){ String selectorBase = INSTANTIATION_ARGUMENTS_SELECTOR + PropertyContext.PROPERTY_ARRAY_BEGIN + String.valueOf( j ) + PropertyContext.PROPERTY_ARRAY_END; String typeSelector = selectorBase + PropertyContext.ATTRIBUTE_BEGIN + PropertyContext.ATTRIBUTE_SIGNER + PARAMETER_TYPE_ELEMENT_NAME + PropertyContext.ATTRIBUTE_END; String paremeterType = dataLoaderConfig.getString( typeSelector ); parameterTypes[j] = Class.forName( paremeterType ); //String nameSelector = selectorBase + PropertyContext.ATTRIBUTE_BEGIN + PropertyContext.ATTRIBUTE_SIGNER + PARAMETER_NAME_ELEMENT_NAME + PropertyContext.ATTRIBUTE_END; String parameterValue = dataLoaderConfig.getString( selectorBase ); parameterValues[j] = parameterValue; } Class<DataLoader> dataLoaderClass = (Class<DataLoader>) Class.forName( className ); dataLoaderConstructor = dataLoaderClass.getConstructor( parameterTypes ); dataLoader = (DataLoader) dataLoaderConstructor.newInstance( parameterValues ); }catch( SecurityException e ){ throw new ApplicationStartException( this, e ); }catch( NoSuchMethodException e ){ throw new ApplicationStartException( this, e ); }catch( IllegalArgumentException e ){ throw new ApplicationStartException( this, e ); }catch( InstantiationException e ){ throw new ApplicationStartException( this, e ); }catch( IllegalAccessException e ){ throw new ApplicationStartException( this, e ); }catch( InvocationTargetException e ){ throw new ApplicationStartException( this, e ); }catch( ClassNotFoundException e ){ throw new ApplicationStartException( this, e ); } return dataLoader; } private void persistSystemInstallerUser() { User systemInstaller = UserRequestManager.getInstance().currentUser(); UserRepository userRepository = applicationContext.getRepository( UserRepository.class ); userRepository.add( systemInstaller ); } private void setUpApplicationContext( Action applicationAction, PropertyContextOverrides overrides ) throws ApplicationException { try{ if( applicationContext == null ) applicationContext = new ProcessPuzzleContext( this, configurationDescriptorPath ); if( !applicationContext.isConfigured() ){ if( overrides != null ) applicationContext.setPropertyContextOverrides( overrides ); applicationContext.setUp( applicationAction ); } // applicationName = applicationContext.getProperty( PropertyKeys.APPLICATION_NAME.getXPathKey() ); }catch( Exception e ){ // applicationName = applicationContext.getProperty( PropertyKeys.APPLICATION_NAME.getXPathKey() ); String message = "Starting " + applicationName + "application failed."; log.error( message, e ); applicationContext = null; throw new ApplicationStartException( this, e ); } } }