Author: tfischer
Date: Mon Sep  9 20:25:24 2013
New Revision: 1521281

URL: http://svn.apache.org/r1521281
Log:
TORQUE-292 implement runOnlyOnSchemaChange

Added:
    
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/stream/CombinedFileSourceTest.java
Modified:
    db/torque/torque4/trunk/torque-generator/pom.xml
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfiguration.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfigurationReader.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitDescriptor.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/Source.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/jdbc/JdbcMetadataSource.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/CombinedFileSource.java
    
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/FileSource.java
    
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/control/PropertyToJavaGenerationTest.java

Modified: db/torque/torque4/trunk/torque-generator/pom.xml
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/pom.xml?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- db/torque/torque4/trunk/torque-generator/pom.xml (original)
+++ db/torque/torque4/trunk/torque-generator/pom.xml Mon Sep  9 20:25:24 2013
@@ -124,6 +124,12 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <version>1.9.0</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.derby</groupId>
       <artifactId>derby</artifactId>
       <version>10.5.3.0_1</version>

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfiguration.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfiguration.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfiguration.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfiguration.java
 Mon Sep  9 20:25:24 2013
@@ -67,9 +67,7 @@ public class UnitConfiguration
      */
     private final Map<String, File> outputDirectoryMap = new HashMap<String, 
File>();
 
-    /**
-     * A directory where the Torque generator can store internal files
-     */
+    /** A directory where the Torque generator can store internal files. */
     private File workDirectory;
 
     /** The Loglevel for generation. */
@@ -92,6 +90,12 @@ public class UnitConfiguration
     private ClassLoader classLoader;
 
     /**
+     * Set to true if only the sources should be processed which have
+     * changed since last generation.
+     */
+    private boolean runOnlyOnSchemaChange = false;
+
+    /**
      * Returns the configuration of the outlets in this generation unit.
      *
      * @return the outlet configuration, not null.
@@ -116,7 +120,7 @@ public class UnitConfiguration
      * @throws NullPointerException if outletConfiguration is null.
      */
     public void setOutletConfiguration(
-            OutletConfiguration outletConfiguration)
+            final OutletConfiguration outletConfiguration)
     {
         if (outletConfiguration == null)
         {
@@ -150,7 +154,7 @@ public class UnitConfiguration
      *
      * @throws NullPointerException if options is null.
      */
-    public void setOptions(Options options)
+    public void setOptions(final Options options)
     {
         if (options == null)
         {
@@ -172,7 +176,7 @@ public class UnitConfiguration
      * @throws IllegalStateException if the default output directory
      *         was not yet set.
      */
-    public File getOutputDirectory(String outputDirKey)
+    public File getOutputDirectory(final String outputDirKey)
     {
         File result = outputDirectoryMap.get(outputDirKey);
         if (result == null)
@@ -215,7 +219,7 @@ public class UnitConfiguration
      * @throws NullPointerException if outputDirectoryMap is null.
      * @throws IllegalStateException if the target directory was not yet set.
      */
-    public void setOutputDirectoryMap(Map<String, File> outputDirectoryMap)
+    public void setOutputDirectoryMap(final Map<String, File> 
outputDirectoryMap)
     {
         if (outputDirectoryMap == null)
         {
@@ -256,7 +260,7 @@ public class UnitConfiguration
      *
      * @throws NullPointerException if workDirectory is null.
      */
-    public void setWorkDirectory(File workDirectory)
+    public void setWorkDirectory(final File workDirectory)
     {
         if (workDirectory == null)
         {
@@ -272,7 +276,7 @@ public class UnitConfiguration
      *
      * @throws NullPointerException if outputFiles is null.
      */
-    public void setOutputList(List<Output> outputList)
+    public void setOutputList(final List<Output> outputList)
     {
         if (outputList == null)
         {
@@ -324,7 +328,7 @@ public class UnitConfiguration
      *
      * @throws NullPointerException if loglevel is set to null.
      */
-    public void setLoglevel(Loglevel loglevel)
+    public void setLoglevel(final Loglevel loglevel)
     {
         if (loglevel == null)
         {
@@ -349,7 +353,7 @@ public class UnitConfiguration
      * @param addDebuggingInfoToOutput true if debug information should be
      *        added, false otherwise.
      */
-    public void setAddDebuggingInfoToOutput(boolean addDebuggingInfoToOutput)
+    public void setAddDebuggingInfoToOutput(final boolean 
addDebuggingInfoToOutput)
     {
         this.addDebuggingInfoToOutput = addDebuggingInfoToOutput;
     }
@@ -381,7 +385,7 @@ public class UnitConfiguration
      * @throws NullPointerException if configurationHandlers is null.
      */
     public void setConfigurationHandlers(
-            ConfigurationHandlers configurationHandlers)
+            final ConfigurationHandlers configurationHandlers)
     {
         if (configurationHandlers == null)
         {
@@ -418,7 +422,7 @@ public class UnitConfiguration
      *        to use the source provider defined in the control file.
      */
     public void setOverrideSourceProvider(
-            SourceProvider overrideSourceProvider)
+            final SourceProvider overrideSourceProvider)
     {
         this.overrideSourceProvider = overrideSourceProvider;
         overrideSourceProviderInitialized = true;
@@ -448,7 +452,7 @@ public class UnitConfiguration
      *
      * @throws NullPointerException if entityReferences is null.
      */
-    public void setEntityReferences(EntityReferences entityReferences)
+    public void setEntityReferences(final EntityReferences entityReferences)
     {
         if (entityReferences == null)
         {
@@ -477,7 +481,7 @@ public class UnitConfiguration
      * @param defaultOutputEncoding the default output encoding,
      *        null for the default platform encoding.
      */
-    public void setDefaultOutputEncoding(String defaultOutputEncoding)
+    public void setDefaultOutputEncoding(final String defaultOutputEncoding)
     {
         this.defaultOutputEncoding = defaultOutputEncoding;
     }
@@ -502,12 +506,39 @@ public class UnitConfiguration
      *        or null if the standard class loader
      *        of the torque generator classes should be used.
      */
-    public void setClassLoader(ClassLoader classLoader)
+    public void setClassLoader(final ClassLoader classLoader)
     {
         this.classLoader = classLoader;
     }
 
     /**
+     * Returns true if only the sources should be processed which have
+     * changed since last generation.
+     *
+     * @return false if the controller should be run irrespective of changes
+     *         in the source files, true if the controller should be run for
+     *         source files which have changed during last generation.
+     */
+    public boolean isRunOnlyOnSchemaChange()
+    {
+        return runOnlyOnSchemaChange;
+    }
+
+    /**
+     * Sets whether only the sources should be processed which have
+     * changed since last generation.
+     *
+     * @param runOnlyOnSchemaChange false if the controller should be run
+     *        irrespective of changes in the source files,
+     *        true if the controller should be run for source files
+     *        which have changed during last generation.
+     */
+    public void setRunOnlyOnSchemaChange(final boolean runOnlyOnSchemaChange)
+    {
+        this.runOnlyOnSchemaChange = runOnlyOnSchemaChange;
+    }
+
+    /**
      * Checks whether the unit configuration is fully initialized.
      *
      * @return true if the unit configuration is fully initialized,

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfigurationReader.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfigurationReader.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfigurationReader.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitConfigurationReader.java
 Mon Sep  9 20:25:24 2013
@@ -66,8 +66,8 @@ class UnitConfigurationReader
      *         for the given configuration type.
      */
     public UnitConfiguration read(
-            UnitDescriptor unitDescriptor,
-            ConfigurationHandlers configurationHandlers)
+            final UnitDescriptor unitDescriptor,
+            final ConfigurationHandlers configurationHandlers)
         throws ConfigurationException
     {
         if (unitDescriptor == null)
@@ -96,6 +96,8 @@ class UnitConfigurationReader
         unitConfiguration.setOverrideSourceProvider(
                 unitDescriptor.getOverrideSourceProvider());
         unitConfiguration.setClassLoader(unitDescriptor.getClassLoader());
+        unitConfiguration.setRunOnlyOnSchemaChange(
+                unitDescriptor.isRunOnlyOnSchemaChange());
 
         ConfigurationProvider configurationProvider
             = createConfigurationProvider(unitDescriptor);
@@ -163,8 +165,8 @@ class UnitConfigurationReader
      *        which option configuration should be merged.
      */
     private void mergeInheritedOutputFiles(
-            UnitConfiguration unitConfiguration,
-            UnitConfiguration inheritedConfiguration)
+            final UnitConfiguration unitConfiguration,
+            final UnitConfiguration inheritedConfiguration)
     {
         List<Output> outputFiles = new ArrayList<Output>();
         // inherited Files are generated first.
@@ -204,8 +206,8 @@ class UnitConfigurationReader
      *        which entity references should be merged.
      */
     private void mergeInheritedEntityRefernces(
-            UnitConfiguration unitConfiguration,
-            UnitConfiguration inheritedConfiguration)
+            final UnitConfiguration unitConfiguration,
+            final UnitConfiguration inheritedConfiguration)
     {
         EntityReferences entityReferences
                 = unitConfiguration.getEntityReferences();
@@ -243,8 +245,8 @@ class UnitConfigurationReader
      *        which option configuration should be merged.
      */
     private void mergeInheritedOptionConfiguration(
-            UnitConfiguration unitConfiguration,
-            UnitConfiguration inheritedConfiguration)
+            final UnitConfiguration unitConfiguration,
+            final UnitConfiguration inheritedConfiguration)
     {
         Options options = unitConfiguration.getOptions();
         Options inheritedOptions = inheritedConfiguration.getOptions();
@@ -272,9 +274,9 @@ class UnitConfigurationReader
      * @throws ConfigurationException will not normally happen.
      */
     private void mergeInheritedOutletConfiguration(
-                UnitDescriptor unitDescriptor,
-                UnitConfiguration unitConfiguration,
-                UnitConfiguration inheritedConfiguration)
+                final UnitDescriptor unitDescriptor,
+                final UnitConfiguration unitConfiguration,
+                final UnitConfiguration inheritedConfiguration)
             throws ConfigurationException
     {
         OutletConfiguration outletConfiguration
@@ -314,10 +316,10 @@ class UnitConfigurationReader
      *         the configuration.
      */
     private void readControlConfiguration(
-                UnitConfiguration unitConfiguration,
-                UnitDescriptor unitDescriptor,
-                ConfigurationHandlers configurationHandlers,
-                ConfigurationProvider configurationProvider)
+                final UnitConfiguration unitConfiguration,
+                final UnitDescriptor unitDescriptor,
+                final ConfigurationHandlers configurationHandlers,
+                final ConfigurationProvider configurationProvider)
             throws ConfigurationException
     {
         if (log.isDebugEnabled())
@@ -388,7 +390,7 @@ class UnitConfigurationReader
      *         or if a jar file cannot be accessed.
      */
     private ConfigurationProvider createConfigurationProvider(
-                UnitDescriptor unitDescriptor)
+                final UnitDescriptor unitDescriptor)
             throws ConfigurationException
     {
         ConfigurationProvider configurationProvider;
@@ -418,7 +420,7 @@ class UnitConfigurationReader
         return configurationProvider;
     }
 
-    private String getUnitDisplayName(UnitDescriptor unitDescriptor)
+    private String getUnitDisplayName(final UnitDescriptor unitDescriptor)
     {
         if (Packaging.CLASSPATH == unitDescriptor.getPackaging())
         {

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitDescriptor.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitDescriptor.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitDescriptor.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/configuration/UnitDescriptor.java
 Mon Sep  9 20:25:24 2013
@@ -46,17 +46,17 @@ public class UnitDescriptor
     /**
      * The packaging of the generation unit.
      */
-    private Packaging packaging;
+    private final Packaging packaging;
 
    /**
     * The paths the Torque generator must know about the surrounding project.
     */
-    private ProjectPaths projectPaths;
+    private final ProjectPaths projectPaths;
 
     /**
      * How the Torque generator's configuration is organized internally.
      */
-    private TorqueGeneratorPaths configurationPaths;
+    private final TorqueGeneratorPaths configurationPaths;
 
     /**
      * The parent of this generation unit, or null if it has no parent.
@@ -92,6 +92,12 @@ public class UnitDescriptor
     private ClassLoader classLoader;
 
     /**
+     * Set to true if only the sources should be processed which have
+     * changed since last generation.
+     */
+    private boolean runOnlyOnSchemaChange = false;
+
+    /**
      * Constructor without inheritance, override options, 
overrideSourceFileset,
      * loglevel and addDebuggingInfoToOutput.
      *
@@ -102,9 +108,9 @@ public class UnitDescriptor
      *        of the configuration unit, not null.
      */
     public UnitDescriptor(
-            Packaging packaging,
-            ProjectPaths projectPaths,
-            TorqueGeneratorPaths configurationPaths)
+            final Packaging packaging,
+            final ProjectPaths projectPaths,
+            final TorqueGeneratorPaths configurationPaths)
     {
         if (packaging == null)
         {
@@ -176,7 +182,7 @@ public class UnitDescriptor
      * @param inheritsFrom the parents unit descriptor,
      *        or null if no parent exists.
      */
-    public void setInheritsFrom(UnitDescriptor inheritsFrom)
+    public void setInheritsFrom(final UnitDescriptor inheritsFrom)
     {
         this.inheritsFrom = inheritsFrom;
     }
@@ -200,7 +206,7 @@ public class UnitDescriptor
      * @param overrideSourceProvider the overriding source provider,
      *        or null if the control file definition is not overridden.
      */
-    public void setOverrideSourceProvider(SourceProvider 
overrideSourceProvider)
+    public void setOverrideSourceProvider(final SourceProvider 
overrideSourceProvider)
     {
         this.overrideSourceProvider = overrideSourceProvider;
     }
@@ -221,7 +227,7 @@ public class UnitDescriptor
      * @param overrideOptions the configuration of the overriding options,
      *        or null.
      */
-    public void setOverrideOptions(OptionsConfiguration overrideOptions)
+    public void setOverrideOptions(final OptionsConfiguration overrideOptions)
     {
         this.overrideOptions = overrideOptions;
     }
@@ -243,7 +249,7 @@ public class UnitDescriptor
      *
      * @param loglevel the log level, or null.
      */
-    public void setLoglevel(Loglevel loglevel)
+    public void setLoglevel(final Loglevel loglevel)
     {
         this.loglevel = loglevel;
     }
@@ -265,7 +271,7 @@ public class UnitDescriptor
      * @param addDebuggingInfoToOutput true if debugging info should be added
      *        to the output, false if not.
      */
-    public void setAddDebuggingInfoToOutput(boolean addDebuggingInfoToOutput)
+    public void setAddDebuggingInfoToOutput(final boolean 
addDebuggingInfoToOutput)
     {
         this.addDebuggingInfoToOutput = addDebuggingInfoToOutput;
     }
@@ -289,7 +295,7 @@ public class UnitDescriptor
      * @param defaultOutputEncoding the default output encoding,
      *        null for the default platform encoding.
      */
-    public void setDefaultOutputEncoding(String defaultOutputEncoding)
+    public void setDefaultOutputEncoding(final String defaultOutputEncoding)
     {
         this.defaultOutputEncoding = defaultOutputEncoding;
     }
@@ -314,10 +320,36 @@ public class UnitDescriptor
      *        or null if the standard class loader
      *        of the torque generator classes should be used.
      */
-    public void setClassLoader(ClassLoader classLoader)
+    public void setClassLoader(final ClassLoader classLoader)
     {
         this.classLoader = classLoader;
     }
 
 
+    /**
+     * Returns true if only the sources should be processed which have
+     * changed since last generation.
+     *
+     * @return false if the controller should be run irrespective of changes
+     *         in the source files, true if the controller should be run for
+     *         source files which have changed during last generation.
+     */
+    public boolean isRunOnlyOnSchemaChange()
+    {
+        return runOnlyOnSchemaChange;
+    }
+
+    /**
+     * Sets whether only the sources should be processed which have
+     * changed since last generation.
+     *
+     * @param runOnlyOnSchemaChange false if the controller should be run
+     *        irrespective of changes in the source files,
+     *        true if the controller should be run for source files
+     *        which have changed during last generation.
+     */
+    public void setRunOnlyOnSchemaChange(final boolean runOnlyOnSchemaChange)
+    {
+        this.runOnlyOnSchemaChange = runOnlyOnSchemaChange;
+    }
 }

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/control/Controller.java
 Mon Sep  9 20:25:24 2013
@@ -24,11 +24,16 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.log4j.PropertyConfigurator;
@@ -66,6 +71,20 @@ public class Controller
     private static Log log = LogFactory.getLog(Controller.class);
 
     /**
+     * The subdirectory in the work directory where last source changes
+     * are stored.
+     */
+    public static final String LAST_SOURCE_CHANGE_WORK_SUBDIR
+            = "last-source-changes";
+
+    /** The suffix for written checksum files. */
+    public static final String CHECKSUM_SUFFIX = ".checksum";
+
+    /** The content of checksum files if no checksum can be computed. */
+    public static final String NO_CHECKSUM_CONTENT
+        = "[checksum could not be determined]";
+
+    /**
      * All known ExistingTargetStrategies.
      * TODO: move to a better place.
      */
@@ -85,6 +104,18 @@ public class Controller
     }
 
     /**
+     * Caches the result whether the source was modified since last generation
+     * (relevant if the runOnlyOnSchemaCahne Flag is set).
+     * Caching is necessary because a source file can be read several times
+     * during one generation, and only the first check against the checksum 
file
+     * is meaningful.
+     * The key is the absolute path to the source file, the value the result
+     * of the sourceModified check.
+     */
+    private final Map<String,Boolean> sourceModifiedCache
+            = new HashMap<String,Boolean>();
+
+    /**
      * Executes the controller action.
      *
      * @param unitDescriptors the units of generation to execute.
@@ -101,6 +132,7 @@ public class Controller
         throws GeneratorException
     {
         initLogging();
+        sourceModifiedCache.clear();
         final Configuration configuration = readConfiguration(unitDescriptors);
 
         final List<UnitConfiguration> unitConfigurations
@@ -225,11 +257,19 @@ public class Controller
         while (sourceProvider.hasNext())
         {
             final Source source = sourceProvider.next();
-            processSourceInOutput(
-                    source,
-                    output,
-                    controllerState,
-                    unitConfiguration);
+            if (!unitConfiguration.isRunOnlyOnSchemaChange()
+                    || checkSourceModified(source, unitConfiguration))
+            {
+                processSourceInOutput(
+                        source,
+                        output,
+                        controllerState,
+                        unitConfiguration);
+            }
+            if (unitConfiguration.isRunOnlyOnSchemaChange())
+            {
+                writeLastModified(source, unitConfiguration);
+            }
         }
         controllerState.setSourceProvider(null);
     }
@@ -573,4 +613,153 @@ public class Controller
         return Charset.defaultCharset().displayName();
     }
 
+    /**
+     * Checks whether a source file was modified since the last generation.
+     *
+     * @param source the source file to check, not null.
+     * @param unitConfiguration the configuration of the unit of generation,
+     *        not null.
+     *
+     * @return true if the source file was modified since last generation,
+     *         if the time of the last generation cannot be determined,
+     *         or if the source file does not exist,
+     *         false otherwise.
+     */
+    private boolean checkSourceModified(
+            final Source source,
+            final UnitConfiguration unitConfiguration)
+    {
+        File sourceFile = source.getSourceFile();
+        if (sourceFile == null)
+        {
+            log.trace("checkSourceModified(): "
+                    + "source file cannot be determined, return true");
+            return true;
+        }
+        String absoluteSourcePath = sourceFile.getAbsoluteFile().toString();
+        if (sourceModifiedCache.get(absoluteSourcePath) != null)
+        {
+            return sourceModifiedCache.get(absoluteSourcePath);
+        }
+
+        Date sourceLastModified = source.getLastModified();
+        if (sourceLastModified == null)
+        {
+            log.trace("checkSourceModified(): "
+                    + "lastModified date of source cannot be determined, "
+                    + "return true");
+            sourceModifiedCache.put(absoluteSourcePath, true);
+            return true;
+        }
+        File lastChangesDir = new File(
+                unitConfiguration.getWorkDirectory(),
+                LAST_SOURCE_CHANGE_WORK_SUBDIR);
+        File lastChangesFile = new File(
+                lastChangesDir,
+                sourceFile.getName() + CHECKSUM_SUFFIX);
+        if (!lastChangesFile.exists())
+        {
+            log.trace("checkSourceModified(): "
+                    + "lastChanges file does not exist, return true");
+            sourceModifiedCache.put(absoluteSourcePath, true);
+            return true;
+        }
+        if (lastChangesFile.lastModified() < sourceLastModified.getTime())
+        {
+            log.trace("checkSourceModified(): "
+                    + "lastChanges file was last changed before source ("
+                    + new Date(lastChangesDir.lastModified())
+                    + " < "
+                    + sourceLastModified
+                    + "), return true");
+            sourceModifiedCache.put(absoluteSourcePath, true);
+            return true;
+        }
+        byte[] lastChangesContent = null;
+        try
+        {
+            lastChangesContent = 
FileUtils.readFileToByteArray(lastChangesFile);
+        }
+        catch (IOException e)
+        {
+            log.warn("checkSourceModified(): "
+                    + "could not access File "
+                    + lastChangesFile.getAbsolutePath()
+                    + ", return true");
+            sourceModifiedCache.put(absoluteSourcePath, true);
+            return true;
+        }
+        if (!Arrays.equals(lastChangesContent, source.getContentChecksum()))
+        {
+            log.trace("checkSourceModified(): "
+                    + " different checksum, return true");
+            sourceModifiedCache.put(absoluteSourcePath, true);
+            return true;
+        }
+        log.trace("checkSourceModified() : returning false");
+        sourceModifiedCache.put(absoluteSourcePath, false);
+        return false;
+    }
+
+    /**
+     * Writes the last modification time of a source to the work directory.
+     *
+     * @param source the source which modification time should be written,
+     *        not null.
+     * @param unitConfigurationthe configuration of the unit of generation,
+     *        not null.
+     */
+    private void writeLastModified(
+            final Source source,
+            final UnitConfiguration unitConfiguration)
+    {
+        File sourceFile = source.getSourceFile();
+        if (sourceFile == null)
+        {
+            log.trace("writeLastModified(): "
+                    + "source file cannot be determined, do nothing");
+            return;
+        }
+        File lastChangesDir = new File(
+                unitConfiguration.getWorkDirectory(),
+                LAST_SOURCE_CHANGE_WORK_SUBDIR);
+        if (!lastChangesDir.exists())
+        {
+            boolean dirCreationSuccessfull = lastChangesDir.mkdirs();
+            if (!dirCreationSuccessfull)
+            {
+                log.warn("could not create directory(): "
+                        + lastChangesDir.getAbsolutePath()
+                        + ", do nothing");
+                return;
+            }
+        }
+        File lastChangesFile = new File(
+                lastChangesDir,
+                sourceFile.getName() + CHECKSUM_SUFFIX);
+        byte[] contentChecksum = source.getContentChecksum();
+        try
+        {
+            if (contentChecksum != null)
+            {
+                FileUtils.writeByteArrayToFile(
+                        lastChangesFile,
+                        source.getContentChecksum());
+            }
+            else
+            {
+                FileUtils.writeStringToFile(
+                        lastChangesFile,
+                        NO_CHECKSUM_CONTENT,
+                        "ISO-8859-1");
+            }
+        }
+        catch (IOException e)
+        {
+            log.warn("could not write to file(): "
+                    + lastChangesFile,
+                e);
+            return;
+        }
+    }
 }

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/Source.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/Source.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/Source.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/Source.java
 Mon Sep  9 20:25:24 2013
@@ -20,6 +20,7 @@ package org.apache.torque.generator.sour
  */
 
 import java.io.File;
+import java.util.Date;
 
 /**
  * An entity which serves as an input for the generation process.
@@ -49,4 +50,23 @@ public interface Source
      * @return the source file, or null if the source is not read from a file.
      */
     File getSourceFile();
+
+    /**
+     * Returns the date when the source was last modified.
+     *
+     * @return the last modification date, or null when unknown.
+     */
+    Date getLastModified();
+
+    /**
+     * Returns the checksum of the content of the source.
+     * It is not defined which checksum is returned, the only
+     * requirement is that collisions should be extremely rare,
+     * i.e it can be assumed that if the checksum is the same,
+     * the content is also the same.
+     *
+     * @return the checksum of the content of the source, or null if
+     *         it cannot be determined.
+     */
+    byte[] getContentChecksum();
 }

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/jdbc/JdbcMetadataSource.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/jdbc/JdbcMetadataSource.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/jdbc/JdbcMetadataSource.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/jdbc/JdbcMetadataSource.java
 Mon Sep  9 20:25:24 2013
@@ -28,6 +28,7 @@ import java.sql.SQLException;
 import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -118,20 +119,19 @@ public class JdbcMetadataSource extends 
     private static Log log = LogFactory.getLog(JdbcMetadataSource.class);
 
     /** The fully qualified class name of the database driver. */
-    private String driver;
+    private final String driver;
 
     /** The connection url to the database, */
-    private String url;
+    private final String url;
 
     /** The username to connect to the database. */
-    private String username;
+    private final String username;
 
     /** The password to connect to the database. */
-    private String password;
+    private final String password;
 
     /** Which database(mysql) or schema (oracle) should be read. */
-    private String schema;
-
+    private final String schema;
 
     /**
      * Constructor.
@@ -143,11 +143,11 @@ public class JdbcMetadataSource extends 
      * @param schema the schema to read.
      */
     public JdbcMetadataSource(
-            String driver,
-            String url,
-            String username,
-            String password,
-            String schema)
+            final String driver,
+            final String url,
+            final String username,
+            final String password,
+            final String schema)
     {
         this.driver = driver;
         this.url = url;
@@ -187,7 +187,7 @@ public class JdbcMetadataSource extends 
             for (int i = 0; i < tableList.size(); i++)
             {
                 // Add Table.
-                String tableName = (String) tableList.get(i);
+                String tableName = tableList.get(i);
                 log.debug("Processing table: " + tableName);
 
                 SourceElement table = new SourceElement("table");
@@ -320,7 +320,7 @@ public class JdbcMetadataSource extends 
      * @return The list of all the tables in a database.
      * @throws SQLException
      */
-    List<String> getTableNames(DatabaseMetaData dbMeta, String dbSchema)
+    List<String> getTableNames(final DatabaseMetaData dbMeta, final String 
dbSchema)
         throws SQLException
     {
         log.debug("Getting table list...");
@@ -360,9 +360,9 @@ public class JdbcMetadataSource extends 
      * @throws SQLException if an sql error occurs during information 
retrieval.
      */
     List<ColumnMetadata> getColumns(
-            DatabaseMetaData dbMeta,
-            String tableName,
-            String dbSchema)
+            final DatabaseMetaData dbMeta,
+            final String tableName,
+            final String dbSchema)
             throws SQLException
     {
         List<ColumnMetadata> columns = new ArrayList<ColumnMetadata>();
@@ -415,9 +415,9 @@ public class JdbcMetadataSource extends 
      * @throws SQLException
      */
     Set<String> getPrimaryKeys(
-                DatabaseMetaData dbMeta,
-                String tableName,
-                String schemaName)
+                final DatabaseMetaData dbMeta,
+                final String tableName,
+                final String schemaName)
             throws SQLException
     {
         Set<String> pk = new HashSet<String>();
@@ -450,9 +450,9 @@ public class JdbcMetadataSource extends 
      * @throws SQLException
      */
     Collection<ForeignKeyMetadata> getForeignKeys(
-                DatabaseMetaData dbMeta,
-                String tableName,
-                String schemaName)
+                final DatabaseMetaData dbMeta,
+                final String tableName,
+                final String schemaName)
             throws SQLException
     {
         Map<String, ForeignKeyMetadata> foreignKeys
@@ -504,4 +504,27 @@ public class JdbcMetadataSource extends 
         }
         return foreignKeys.values();
     }
+
+    /**
+     * Returns the last modification date of the source files.
+     *
+     * @return always null because no source file exist.
+     */
+    public Date getLastModified()
+    {
+        return null;
+    }
+
+    /**
+     * Returns the checksum of the content.
+     *
+     * @return always null.
+     */
+    public byte[] getContentChecksum()
+    {
+        // Although we could determine a checksum for the content,
+        // doing so makes no sense because we cannot determine
+        // al last modified date.
+        return null;
+    }
 }

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/CombinedFileSource.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/CombinedFileSource.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/CombinedFileSource.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/CombinedFileSource.java
 Mon Sep  9 20:25:24 2013
@@ -22,6 +22,7 @@ package org.apache.torque.generator.sour
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 
 import org.apache.commons.logging.Log;
@@ -66,7 +67,7 @@ public class CombinedFileSource extends 
     /**
      * The list of contained file sources, not null..
      */
-    private List<FileSource> fileSources;
+    private final List<FileSource> fileSources;
 
     /**
      * Constructor.
@@ -76,7 +77,7 @@ public class CombinedFileSource extends 
      * @throws NullPointerException if path or format is null.
      */
     public CombinedFileSource(
-            Collection<FileSource> fileSources)
+            final Collection<FileSource> fileSources)
     {
         if (fileSources == null)
         {
@@ -151,9 +152,73 @@ public class CombinedFileSource extends 
         return null;
     }
 
+    /**
+     * Returns the earliest date when any of the source files was last 
modified.
+     *
+     * @return the last modification date,
+     *         or null when unknown for at least one of the files.
+     */
+    public Date getLastModified()
+    {
+        Date result = null;
+        for (FileSource fileSource : fileSources)
+        {
+            Date fileLastModified = fileSource.getLastModified();
+            if (fileLastModified == null)
+            {
+                return null;
+            }
+            if (result == null || fileLastModified.before(result))
+            {
+                result = fileLastModified;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Returns the checksum of all files.
+     * All bytes are added so order of the files does not matter.
+     *
+     * @return a checksum for all files, or null if one of the checksums
+     *         of the file sources is null.
+     */
+    public byte[] getContentChecksum()
+    {
+        byte[] result = new byte[] {};
+
+        for (FileSource fileSource : fileSources)
+        {
+            byte[] fileChecksum = fileSource.getContentChecksum();
+            if (fileChecksum == null)
+            {
+                return null;
+            }
+            byte[] lastResult = result;
+            result = new byte[Math.max(lastResult.length, 
fileChecksum.length)];
+            for (int i = 0; i < result.length; ++i)
+            {
+                if (i < lastResult.length && i < fileChecksum.length)
+                {
+                    result[i] = (byte) (lastResult[i] + fileChecksum[i]);
+                }
+                else if (i < lastResult.length)
+                {
+                    result[i] = lastResult[i];
+                }
+                else
+                {
+                    result[i] = fileChecksum[i];
+                }
+            }
+        }
+        return result;
+    }
+
     @Override
     public String toString()
     {
         return getDescription();
     }
+
 }

Modified: 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/FileSource.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/FileSource.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/FileSource.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/main/java/org/apache/torque/generator/source/stream/FileSource.java
 Mon Sep  9 20:25:24 2013
@@ -24,6 +24,10 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -58,6 +62,11 @@ public class FileSource extends SourceIm
     private final ControllerState controllerState;
 
     /**
+     * The md5sum of the file content.
+     */
+    private byte[] contentMd5Sum;
+
+    /**
      * Constructor.
      *
      * @param format the source format, not null.
@@ -67,9 +76,9 @@ public class FileSource extends SourceIm
      * @throws NullPointerException if path or format is null.
      */
     public FileSource(
-            StreamSourceFormat format,
-            File path,
-            ControllerState controllerState)
+            final StreamSourceFormat format,
+            final File path,
+            final ControllerState controllerState)
     {
         if (path == null)
         {
@@ -127,11 +136,15 @@ public class FileSource extends SourceIm
         try
         {
             inputStream = new FileInputStream(path);
+            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+            DigestInputStream digestInputStream
+                    = new DigestInputStream(inputStream, messageDigest);
             log.debug("Reading file "
                     + path.getAbsolutePath()
                     + " of type "
                     + format.getKey());
-            result = format.parse(inputStream, controllerState);
+            result = format.parse(digestInputStream, controllerState);
+            contentMd5Sum = messageDigest.digest();
         }
         catch (FileNotFoundException e)
         {
@@ -139,6 +152,12 @@ public class FileSource extends SourceIm
                     "File not found: " + path.getAbsolutePath(),
                     e);
         }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new SourceException(
+                    "MD5 message Digest not implemented",
+                    e);
+        }
         finally
         {
             if (inputStream != null)
@@ -185,6 +204,42 @@ public class FileSource extends SourceIm
         return path;
     }
 
+    /**
+     * Returns the date when the source was last modified.
+     *
+     * @return the last modification date, or null when unknown.
+     */
+    public Date getLastModified()
+    {
+        long lastModified = path.lastModified();
+        if (lastModified == 0)
+        {
+            return null;
+        }
+        return new Date(lastModified);
+    }
+
+    /**
+     * Returns the checksum of the content.
+     *
+     * @return always null.
+     */
+    public byte[] getContentChecksum()
+    {
+        if (contentMd5Sum == null)
+        {
+            try
+            {
+                getRootElement();
+            }
+            catch (SourceException e)
+            {
+                // do nothing, contentMd5Sum remains null
+            }
+        }
+        return contentMd5Sum;
+    }
+
     @Override
     public String toString()
     {

Modified: 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/control/PropertyToJavaGenerationTest.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/control/PropertyToJavaGenerationTest.java?rev=1521281&r1=1521280&r2=1521281&view=diff
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/control/PropertyToJavaGenerationTest.java
 (original)
+++ 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/control/PropertyToJavaGenerationTest.java
 Mon Sep  9 20:25:24 2013
@@ -21,6 +21,7 @@ package org.apache.torque.generator.cont
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;
@@ -35,6 +36,14 @@ import org.apache.torque.generator.confi
 import 
org.apache.torque.generator.configuration.paths.Maven2DirectoryProjectPaths;
 import org.junit.Test;
 
+/**
+ * A test case for a more complex generation.
+ * Checks that we can use different generator types in one generation,
+ * that debugging output works
+ * and that the runOnlyOnSchemaChange detection works.
+ *
+ * @version $Id$
+ */
 public class PropertyToJavaGenerationTest extends BaseTest
 {
     /**
@@ -125,4 +134,169 @@ public class PropertyToJavaGenerationTes
         assertEquals(FileUtils.readFileToString(propertiesExpectedFile),
                 FileUtils.readFileToString(propertiesResultFile));
     }
+
+    /**
+     * Tests that runOnlyOnSchemaChange set true and an unchanged source
+     * results in not generating a second time.
+     *
+     * @throws Exception if the test fails.
+     */
+    @Test
+    public void testPropertyToJavaRunOnlyOnSchemChangeNoChange()
+            throws Exception
+    {
+        // prepare
+        File targetDir = new File("target/test/propertyToJava");
+        File workDir = new File("target/work/propertyToJava");
+        File sourceDir = new File("target/source/propertyToJava");
+        FileUtils.deleteDirectory(targetDir);
+        FileUtils.deleteDirectory(workDir);
+        FileUtils.deleteDirectory(sourceDir);
+        FileUtils.copyDirectory(
+                new File("src/test/propertyToJava/src/main/torque-gen/src"),
+                sourceDir);
+        Controller controller = new Controller();
+        List<UnitDescriptor> unitDescriptors = new ArrayList<UnitDescriptor>();
+        CustomProjectPaths projectPaths = new CustomProjectPaths(
+                new Maven2DirectoryProjectPaths(
+                        new File("src/test/propertyToJava")));
+        projectPaths.setOutputDirectory(null, targetDir);
+        projectPaths.setWorkDir(workDir);
+        projectPaths.setSourceDir(sourceDir);
+        UnitDescriptor unitDescriptor = new UnitDescriptor(
+                UnitDescriptor.Packaging.DIRECTORY,
+                projectPaths,
+                new DefaultTorqueGeneratorPaths());
+        unitDescriptor.setRunOnlyOnSchemaChange(true);
+        unitDescriptors.add(unitDescriptor);
+
+        // run first time
+        controller.run(unitDescriptors);
+        File propertiesResultFile
+            = new File(targetDir, "Properties.properties");
+        assertTrue(propertiesResultFile.exists());
+        long firstLastModified = propertiesResultFile.lastModified();
+
+        // execute
+        controller.run(unitDescriptors);
+
+        // verify
+        assertTrue(propertiesResultFile.exists());
+        assertEquals(firstLastModified, propertiesResultFile.lastModified());
+    }
+
+    /**
+     * Tests that runOnlyOnSchemaChange set true and a different checksum
+     * results in generating a second time.
+     *
+     * @throws Exception if the test fails.
+     */
+    @Test
+    public void testPropertyToJavaRunOnlyOnSchemChangeChecksumChange()
+            throws Exception
+    {
+        // prepare
+        File targetDir = new File("target/test/propertyToJava");
+        File workDir = new File("target/work/propertyToJava");
+        File sourceDir = new File("target/source/propertyToJava");
+        FileUtils.deleteDirectory(targetDir);
+        FileUtils.deleteDirectory(workDir);
+        FileUtils.deleteDirectory(sourceDir);
+        FileUtils.copyDirectory(
+                new File("src/test/propertyToJava/src/main/torque-gen/src"),
+                sourceDir);
+        Controller controller = new Controller();
+        List<UnitDescriptor> unitDescriptors = new ArrayList<UnitDescriptor>();
+        CustomProjectPaths projectPaths = new CustomProjectPaths(
+                new Maven2DirectoryProjectPaths(
+                        new File("src/test/propertyToJava")));
+        projectPaths.setOutputDirectory(null, targetDir);
+        projectPaths.setWorkDir(workDir);
+        projectPaths.setSourceDir(sourceDir);
+        UnitDescriptor unitDescriptor = new UnitDescriptor(
+                UnitDescriptor.Packaging.DIRECTORY,
+                projectPaths,
+                new DefaultTorqueGeneratorPaths());
+        unitDescriptor.setRunOnlyOnSchemaChange(true);
+        unitDescriptors.add(unitDescriptor);
+
+        // run first time
+        controller.run(unitDescriptors);
+        File propertiesResultFile
+            = new File(targetDir, "Properties.properties");
+        assertTrue(propertiesResultFile.exists());
+        long firstLastModified = propertiesResultFile.lastModified();
+
+        // change checksum file
+        File checksumFile = new File(
+                workDir,
+                "last-source-changes/propertiesData.properties.checksum");
+        long checksumFileLastModified = checksumFile.lastModified();
+        FileUtils.writeStringToFile(checksumFile, "abc", "ISO-8859-1");
+        assertTrue(checksumFile.setLastModified(checksumFileLastModified));
+
+        // execute
+        controller.run(unitDescriptors);
+
+        // verify
+        assertTrue(propertiesResultFile.exists());
+        assertFalse(firstLastModified == propertiesResultFile.lastModified());
+    }
+
+    /**
+     * Tests that runOnlyOnSchemaChange set true and a different modification
+     * date results in generating a second time.
+     *
+     * @throws Exception if the test fails.
+     */
+    @Test
+    public void testPropertyToJavaRunOnlyOnSchemChangeModificationDateChange()
+            throws Exception
+    {
+        // prepare
+        File targetDir = new File("target/test/propertyToJava");
+        File workDir = new File("target/work/propertyToJava");
+        File sourceDir = new File("target/source/propertyToJava");
+        FileUtils.deleteDirectory(targetDir);
+        FileUtils.deleteDirectory(workDir);
+        FileUtils.deleteDirectory(sourceDir);
+        FileUtils.copyDirectory(
+                new File("src/test/propertyToJava/src/main/torque-gen/src"),
+                sourceDir);
+        Controller controller = new Controller();
+        List<UnitDescriptor> unitDescriptors = new ArrayList<UnitDescriptor>();
+        CustomProjectPaths projectPaths = new CustomProjectPaths(
+                new Maven2DirectoryProjectPaths(
+                        new File("src/test/propertyToJava")));
+        projectPaths.setOutputDirectory(null, targetDir);
+        projectPaths.setWorkDir(workDir);
+        projectPaths.setSourceDir(sourceDir);
+        UnitDescriptor unitDescriptor = new UnitDescriptor(
+                UnitDescriptor.Packaging.DIRECTORY,
+                projectPaths,
+                new DefaultTorqueGeneratorPaths());
+        unitDescriptor.setRunOnlyOnSchemaChange(true);
+        unitDescriptors.add(unitDescriptor);
+
+        // run first time
+        controller.run(unitDescriptors);
+        File propertiesResultFile
+            = new File(targetDir, "Properties.properties");
+        assertTrue(propertiesResultFile.exists());
+        long firstLastModified = propertiesResultFile.lastModified();
+
+        // change modification date of source file
+        File sourceFile = new File(
+                sourceDir,
+                "propertiesData.properties");
+        assertTrue(sourceFile.setLastModified(
+                System.currentTimeMillis() + 1000L));
+
+        // execute
+        controller.run(unitDescriptors);
+
+        // verify
+        assertTrue(propertiesResultFile.exists());
+        assertFalse(firstLastModified == propertiesResultFile.lastModified());
+    }
 }

Added: 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/stream/CombinedFileSourceTest.java
URL: 
http://svn.apache.org/viewvc/db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/stream/CombinedFileSourceTest.java?rev=1521281&view=auto
==============================================================================
--- 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/stream/CombinedFileSourceTest.java
 (added)
+++ 
db/torque/torque4/trunk/torque-generator/src/test/java/org/apache/torque/generator/source/stream/CombinedFileSourceTest.java
 Mon Sep  9 20:25:24 2013
@@ -0,0 +1,109 @@
+package org.apache.torque.generator.source.stream;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit tests for CombinedFileSource.
+ * @version $Id: $
+ */
+public class CombinedFileSourceTest
+{
+    @Mock
+    private FileSource fileSource1;
+
+    @Mock
+    private FileSource fileSource2;
+
+    @Mock
+    private FileSource fileSource3;
+
+    /** System under test. */
+    private CombinedFileSource combinedFileSource;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        MockitoAnnotations.initMocks(this);
+        List<FileSource> fileSources = new ArrayList<FileSource>();
+        fileSources.add(fileSource1);
+        fileSources.add(fileSource2);
+        fileSources.add(fileSource3);
+        combinedFileSource = new CombinedFileSource(fileSources);
+    }
+
+    @Test
+    public void testGetLastModifiedAllDatesSet()
+    {
+        when(fileSource1.getLastModified()).thenReturn(new Date(100000));
+        when(fileSource2.getLastModified()).thenReturn(new Date(99999));
+        when(fileSource3.getLastModified()).thenReturn(new Date(100001));
+        assertEquals(new Date(99999), combinedFileSource.getLastModified());
+    }
+
+    @Test
+    public void testGetLastModifiedNoDateSet()
+    {
+        when(fileSource1.getLastModified()).thenReturn(null);
+        when(fileSource2.getLastModified()).thenReturn(null);
+        when(fileSource3.getLastModified()).thenReturn(null);
+        assertEquals(null, combinedFileSource.getLastModified());
+    }
+
+    @Test
+    public void testGetLastModifiedOneDateNotSet()
+    {
+        when(fileSource1.getLastModified()).thenReturn(new Date(100000));
+        when(fileSource2.getLastModified()).thenReturn(null);
+        when(fileSource3.getLastModified()).thenReturn(new Date(100001));
+        assertEquals(null, combinedFileSource.getLastModified());
+    }
+
+    @Test
+    public void testGetContentChecksum()
+    {
+        when(fileSource1.getContentChecksum()).thenReturn(new byte[] {1, 2, 
100, -100, 100});
+        when(fileSource2.getContentChecksum()).thenReturn(new byte[] {2, 4});
+        when(fileSource3.getContentChecksum()).thenReturn(new byte[] {4, 8, 
100, -100, -100});
+        assertArrayEquals(new byte[] {7, 14, -56, 56, 0}, 
combinedFileSource.getContentChecksum());
+    }
+
+    @Test
+    public void testGetContentChecksumOneNull()
+    {
+        when(fileSource1.getContentChecksum()).thenReturn(new byte[] {1, 2, 
100, -100});
+        when(fileSource2.getContentChecksum()).thenReturn(null);
+        when(fileSource3.getContentChecksum()).thenReturn(new byte[] {4, 8, 
100, -100});
+        assertEquals(null, combinedFileSource.getContentChecksum());
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: torque-dev-unsubscr...@db.apache.org
For additional commands, e-mail: torque-dev-h...@db.apache.org

Reply via email to