package com.processpuzzle.fitnesse.persistence; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.processpuzzle.commons.compiler.SourceCodeTemplateEnhancer; import com.processpuzzle.commons.compiler.StringCompiler; import com.processpuzzle.commons.compiler.StringCompilerException; import com.processpuzzle.commons.persistence.AggregateRoot; import com.processpuzzle.commons.persistence.Entity; import com.processpuzzle.commons.persistence.PersistentObject; import com.processpuzzle.commons.persistence.RepositoryResultSet; import fit.RowFixture; public class RepositoryResultSetChecker extends RowFixture { private static final String SOURCE_CODE_FILE = "classpath:com/processpuzzle/fitnesse/persistence/DefaultPersistentObjectWrapper.java.template"; private static final Logger logger = LoggerFactory.getLogger( RepositoryResultSetChecker.class ); private static final List<String> COMPILER_OPTIONS = Arrays.asList( new String[] { "-target", "1.5" } ); private StringCompiler<PersistentObjectWrapper<?>> compiler; private RepositoryResultSet<? extends PersistentObject> repositoryResultSet; private Class<? extends PersistentObject> persistentObjectClass; private Class<? extends PersistentObjectWrapper<?>> wrapperClass; private String sourceToCompile; private PersistentObjectWrapper<?>[] wrappedPersistentObjects; RepositoryResultSetChecker( RepositoryResultSet<?> repositoryResultSet, Class<? extends AggregateRoot> aggregateRootClass ) { super(); this.repositoryResultSet = repositoryResultSet; persistentObjectClass = aggregateRootClass; wrapResultSet(); } @Override public Class<?> getTargetClass() { return wrapperClass; } @Override public Object[] query() throws Exception { return wrappedPersistentObjects; } public ClassLoader getCompilerClassLoader() { return compiler.getClassLoader(); } private void compileWrapperClass() { logger.trace( "Intending to compile:\n" + sourceToCompile ); wrapperClass = null; try{ wrapperClass = compiler.compile( sourceToCompile, null, new Class<?>[] { PersistentObjectWrapper.class } ); }catch( ClassCastException e ){ String message = "Type mismatch in compilation of 'DefaultPersistentObjectWrapper'"; logger.error( message ); throw new RepositoryTesterException( message, e ); }catch( StringCompilerException e ){ String message = "There was a problem in compiling 'DefaultPersistentObjectWrapper'."; logger.error( message, e ); throw new RepositoryTesterException( message, e ); } } private void instantiateRuntimeCompiler() { compiler = new StringCompiler<PersistentObjectWrapper<?>>( getClass().getClassLoader(), COMPILER_OPTIONS, compiler ); } @SuppressWarnings( "unchecked" ) private PersistentObjectWrapper<Entity> instantiateWrapper() { PersistentObjectWrapper<Entity> wrapper = null; try{ wrapper = (PersistentObjectWrapper<Entity>) wrapperClass.newInstance(); }catch( InstantiationException e ){ String message = "There was a problem when instantiting '" + wrapperClass.getName() + "'"; logger.error( message, e ); throw new RepositoryTesterException( message, e ); }catch( IllegalAccessException e ){ String message = "Can't access when instantiting '" + wrapperClass.getName() + "'"; logger.error( message, e ); throw new RepositoryTesterException( message, e ); } return wrapper; } private boolean isPublicConcreteGetter( Method property ) { boolean isGetter = false; isGetter = StringUtils.startsWith( property.getName(), "get" ) && Modifier.isPublic( property.getModifiers() ) && !property.getName().equals( "getClass" ) && !Modifier.isVolatile( property.getModifiers() ) && !Modifier.isAbstract( property.getModifiers() ); return isGetter; } private void replaceExpressionsInSourceTemplate( SourceCodeTemplateEnhancer sourceEnhancer ) { String assignments = ""; for( Method property : persistentObjectClass.getMethods() ){ if( isPublicConcreteGetter( property ) ){ assignments += " " + sourceEnhancer.createFieldNameFromMethod( property ) + " = persistentObject." + property.getName() + "();\n"; //assignments += " " + "System.out.println( \"" + sourceEnhancer.createFieldNameFromMethod( property ) + " field was assigned.\" );\n"; } } sourceEnhancer.insertExpressions( assignments ); } private void replaceFieldsInSourceTemplate( SourceCodeTemplateEnhancer sourceEnhancer ) { for( Method property : persistentObjectClass.getMethods() ){ if( isPublicConcreteGetter( property ) ){ sourceEnhancer.insertFieldFromGetter( property ); } } } private void replacePlaceholdersInSourceTemplate() { SourceCodeTemplateEnhancer sourceEnhancer = new SourceCodeTemplateEnhancer( SOURCE_CODE_FILE ); sourceEnhancer.replaceGenericType( persistentObjectClass.getSimpleName() ); sourceEnhancer.insertImportIntoSource( persistentObjectClass ); replaceFieldsInSourceTemplate( sourceEnhancer ); replaceExpressionsInSourceTemplate( sourceEnhancer ); sourceEnhancer.finalizeSourceCode(); sourceToCompile = sourceEnhancer.getSourceCodeTeamplate(); } private void wrapResultSet() { wrappedPersistentObjects = new PersistentObjectWrapper[repositoryResultSet.size()]; instantiateRuntimeCompiler(); replacePlaceholdersInSourceTemplate(); compileWrapperClass(); for( int i = 0; i < repositoryResultSet.size(); i++ ){ PersistentObjectWrapper<Entity> wrapper = instantiateWrapper(); wrapper.wrapPersistentObject( (Entity) repositoryResultSet.getEntityAt( i ) ); wrappedPersistentObjects[i] = wrapper; } } }