Added generate.entities.quick task which only generates entities if the Application Dictionary has changed since the last time the entities were generated.
authorMartin Taal <martin.taal@openbravo.com>
Thu, 29 Jan 2009 18:34:05 +0000
changeset 2830 9bed44d3b95c
parent 2829 b06d30cc9f1e
child 2831 1a540b0e3c21
Added generate.entities.quick task which only generates entities if the Application Dictionary has changed since the last time the entities were generated.
Added generate.entities.quick as a dependency of update.database, is also executed after update.database
fixes issue 7186 update.database does use some generated/to be compiled classes but the ant dependencies do not reflect this
build.xml
src-test/org/openbravo/test/ant/AntTasksTest.java
src-test/org/openbravo/test/ant/CompileCompleteTest.java
src-test/org/openbravo/test/base/BaseTest.java
src/build.xml
src/org/openbravo/base/gen/GenerateEntitiesTask.java
src/org/openbravo/base/model/Column.hbm.xml
src/org/openbravo/base/model/ModelObject.java
src/org/openbravo/base/model/ModelProvider.java
src/org/openbravo/base/model/Module.hbm.xml
src/org/openbravo/base/model/Package.hbm.xml
src/org/openbravo/base/model/RefList.hbm.xml
src/org/openbravo/base/model/RefSearch.hbm.xml
src/org/openbravo/base/model/RefTable.hbm.xml
src/org/openbravo/base/model/Reference.hbm.xml
src/org/openbravo/base/model/Table.hbm.xml
src/org/openbravo/service/db/ReferenceDataTask.java
src/org/openbravo/service/system/SystemService.java
--- a/build.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/build.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -287,6 +287,10 @@
 		<ant dir="${base.src}" target="generate.entities" inheritAll="true" inheritRefs="true" />
 	</target>
 
+	<target name="generate.entities.quick">
+		<ant dir="${base.src}" target="generate.entities.quick" inheritAll="true" inheritRefs="true" />
+	</target>
+
 	<target name="export.sample.data" depends="code.rev">
 		<ant dir="${base.src}" target="export.sample.data" inheritAll="true" inheritRefs="true" />
 	</target>
@@ -418,11 +422,12 @@
 		<antcall target="db.apply.modules.sampledata" />
 	</target>
 
-	<target name="update.database" depends="init,code.rev">
+	<target name="update.database" depends="init,code.rev,generate.entities.quick">
 		<antcall target="database.lib" />
 		<antcall target="core.lib" />
 		<ant dir="${base.db}" target="update.database" inheritAll="true" inheritRefs="true" />
 		<antcall target="db.apply.modules" />
+		<antcall target="generate.entities.quick" />
 	</target>
 
 	<target name="update.database.mod" depends="init,code.rev">
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src-test/org/openbravo/test/ant/AntTasksTest.java	Thu Jan 29 18:34:05 2009 +0000
@@ -0,0 +1,37 @@
+/*
+ *************************************************************************
+ * The contents of this file are subject to the Openbravo  Public  License
+ * Version  1.0  (the  "License"),  being   the  Mozilla   Public  License
+ * Version 1.1  with a permitted attribution clause; you may not  use this
+ * file except in compliance with the License. You  may  obtain  a copy of
+ * the License at http://www.openbravo.com/legal/license.html 
+ * Software distributed under the License  is  distributed  on  an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific  language  governing  rights  and  limitations
+ * under the License. 
+ * The Original Code is Openbravo ERP. 
+ * The Initial Developer of the Original Code is Openbravo SL 
+ * All portions are Copyright (C) 2009 Openbravo SL 
+ * All Rights Reserved. 
+ * Contributor(s):  ______________________________________.
+ ************************************************************************
+ */
+
+package org.openbravo.test.ant;
+
+/**
+ * Tests an ant task.
+ * 
+ * @author mtaal
+ */
+
+public class AntTasksTest extends BaseAntTest {
+
+    public void _testCompileComplete() {
+	doTest("compile.complete");
+    }
+
+    public void testUpdateDatabase() {
+	doTest("update.database");
+    }
+}
\ No newline at end of file
--- a/src-test/org/openbravo/test/ant/CompileCompleteTest.java	Thu Jan 29 17:16:13 2009 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-/*
- *************************************************************************
- * The contents of this file are subject to the Openbravo  Public  License
- * Version  1.0  (the  "License"),  being   the  Mozilla   Public  License
- * Version 1.1  with a permitted attribution clause; you may not  use this
- * file except in compliance with the License. You  may  obtain  a copy of
- * the License at http://www.openbravo.com/legal/license.html 
- * Software distributed under the License  is  distributed  on  an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
- * License for the specific  language  governing  rights  and  limitations
- * under the License. 
- * The Original Code is Openbravo ERP. 
- * The Initial Developer of the Original Code is Openbravo SL 
- * All portions are Copyright (C) 2008 Openbravo SL 
- * All Rights Reserved. 
- * Contributor(s):  ______________________________________.
- ************************************************************************
- */
-
-package org.openbravo.test.ant;
-
-/**
- * Tests an ant task.
- * 
- * @author mtaal
- */
-
-public class CompileCompleteTest extends BaseAntTest {
-
-    public void testCompileComplete() {
-        doTest("compile.complete");
-    }
-}
\ No newline at end of file
--- a/src-test/org/openbravo/test/base/BaseTest.java	Thu Jan 29 17:16:13 2009 +0000
+++ b/src-test/org/openbravo/test/base/BaseTest.java	Thu Jan 29 18:34:05 2009 +0000
@@ -47,104 +47,104 @@
 
     @Override
     protected void setUp() throws Exception {
-        initializeDalLayer();
-        // clear the session otherwise it keeps the old model
-        setBigBazaarUserContext();
-        super.setUp();
+	initializeDalLayer();
+	// clear the session otherwise it keeps the old model
+	setBigBazaarUserContext();
+	super.setUp();
     }
 
     protected void initializeDalLayer() throws Exception {
-        if (!DalLayerInitializer.getInstance().isInitialized()) {
-            setConfigPropertyFiles();
-            DalLayerInitializer.getInstance().initialize(true);
-        }
+	if (!DalLayerInitializer.getInstance().isInitialized()) {
+	    setConfigPropertyFiles();
+	    DalLayerInitializer.getInstance().initialize(true, true);
+	}
     }
 
     protected void setConfigPropertyFiles() {
 
-        // get the location of the current class file
-        final URL url = this.getClass().getResource(
-                getClass().getSimpleName() + ".class");
-        File f = new File(url.getPath());
-        // go up 7 levels
-        for (int i = 0; i < 7; i++) {
-            f = f.getParentFile();
-        }
-        final File configDirectory = new File(f, "config");
-        f = new File(configDirectory, "Openbravo.properties");
-        if (!f.exists()) {
-            throw new OBException("The testrun assumes that it is run from "
-                    + "within eclipse and that the Openbravo.properties "
-                    + "file is located as a grandchild of the 7th ancestor "
-                    + "of this class");
-        }
-        OBPropertiesProvider.getInstance().setProperties(f.getAbsolutePath());
-        OBConfigFileProvider.getInstance().setFileLocation(
-                configDirectory.getAbsolutePath());
+	// get the location of the current class file
+	final URL url = this.getClass().getResource(
+		getClass().getSimpleName() + ".class");
+	File f = new File(url.getPath());
+	// go up 7 levels
+	for (int i = 0; i < 7; i++) {
+	    f = f.getParentFile();
+	}
+	final File configDirectory = new File(f, "config");
+	f = new File(configDirectory, "Openbravo.properties");
+	if (!f.exists()) {
+	    throw new OBException("The testrun assumes that it is run from "
+		    + "within eclipse and that the Openbravo.properties "
+		    + "file is located as a grandchild of the 7th ancestor "
+		    + "of this class");
+	}
+	OBPropertiesProvider.getInstance().setProperties(f.getAbsolutePath());
+	OBConfigFileProvider.getInstance().setFileLocation(
+		configDirectory.getAbsolutePath());
     }
 
     protected void setSystemAdministratorContext() {
-        setUserContext("0");
+	setUserContext("0");
     }
 
     protected void setBigBazaarUserContext() {
-        setUserContext("1000000");
+	setUserContext("1000000");
     }
 
     protected void setUserContext(String userId) {
-        OBContext.setOBContext(userId);
+	OBContext.setOBContext(userId);
     }
 
     protected void setBigBazaarAdminContext() {
-        setUserContext("100");
+	setUserContext("100");
     }
 
     @Override
     protected void tearDown() throws Exception {
-        try {
-            if (SessionHandler.isSessionHandlerPresent()) {
-                if (SessionHandler.getInstance().getDoRollback()) {
-                    SessionHandler.getInstance().rollback();
-                } else if (isErrorOccured()) {
-                    SessionHandler.getInstance().rollback();
-                } else {
-                    SessionHandler.getInstance().commitAndClose();
-                }
-            }
-        } catch (final Exception e) {
-            SessionHandler.getInstance().rollback();
-            reportException(e);
-            throw e;
-        } finally {
-            SessionHandler.deleteSessionHandler();
-            OBContext.setOBContext((OBContext) null);
-        }
-        super.tearDown();
+	try {
+	    if (SessionHandler.isSessionHandlerPresent()) {
+		if (SessionHandler.getInstance().getDoRollback()) {
+		    SessionHandler.getInstance().rollback();
+		} else if (isErrorOccured()) {
+		    SessionHandler.getInstance().rollback();
+		} else {
+		    SessionHandler.getInstance().commitAndClose();
+		}
+	    }
+	} catch (final Exception e) {
+	    SessionHandler.getInstance().rollback();
+	    reportException(e);
+	    throw e;
+	} finally {
+	    SessionHandler.deleteSessionHandler();
+	    OBContext.setOBContext((OBContext) null);
+	}
+	super.tearDown();
     }
 
     protected void reportException(Exception e) {
-        if (e == null)
-            return;
-        e.printStackTrace(System.err);
-        if (e instanceof SQLException) {
-            reportException(((SQLException) e).getNextException());
-        }
+	if (e == null)
+	    return;
+	e.printStackTrace(System.err);
+	if (e instanceof SQLException) {
+	    reportException(((SQLException) e).getNextException());
+	}
     }
 
     public boolean isErrorOccured() {
-        return errorOccured;
+	return errorOccured;
     }
 
     public void setErrorOccured(boolean errorOccured) {
-        this.errorOccured = errorOccured;
+	this.errorOccured = errorOccured;
     }
 
     protected <T extends BaseOBObject> T getOneInstance(Class<T> clz) {
-        final OBCriteria<T> obc = OBDal.getInstance().createCriteria(clz);
-        if (obc.list().size() == 0) {
-            throw new OBException("There are zero instances for class "
-                    + clz.getName());
-        }
-        return obc.list().get(0);
+	final OBCriteria<T> obc = OBDal.getInstance().createCriteria(clz);
+	if (obc.list().size() == 0) {
+	    throw new OBException("There are zero instances for class "
+		    + clz.getName());
+	}
+	return obc.list().get(0);
     }
 }
\ No newline at end of file
--- a/src/build.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/build.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -183,7 +183,30 @@
 		<taskdef name="workflow" classpathref="project.class.path" classname="org.openbravo.base.gen.GenerateEntitiesTask" />
 		<!-- debug="true" will perform the in-memory model initialization before generating entities
 	if an error occurs then, then a stacktrace is printed. -->
-		<workflow debug="false" propertiesFile="${base.config}/Openbravo.properties" file="${base.src}/org/openbravo/base/gen/gen_entity.oaw" fork="true" maxmemory="${build.maxmemory}">
+		<workflow debug="false" srcGenPath="${base.src.gen}" propertiesFile="${base.config}/Openbravo.properties" file="${base.src}/org/openbravo/base/gen/gen_entity.oaw" fork="true" maxmemory="${build.maxmemory}">
+			<param name="ob.properties.location" value="${base.config}/Openbravo.properties" />
+			<param name="base.src.gen" value="${base.src.gen}" />
+			<classpath>
+				<path refid="project.class.path" />
+			</classpath>
+		</workflow>
+		<javac srcdir="${base.src.gen}:${base.src}/org/openbravo/base/model:${base.src}/org/openbravo/dal:${base.src}/org/openbravo/base/structure" destdir="${build}" encoding="UTF-8" fork="true" memorymaximumsize="${build.maxmemory}" debug="true" debuglevel="lines,vars,source" deprecation="on">
+			<classpath refid="project.class.path" />
+		</javac>
+	</target>
+
+	<!-- 
+		Generates entities only when the application dictionary has changed.
+		Difference with the generate.entities is that it does not clean the src-gen directory. The standard
+		GenerateEntitiesTask always checks if the AD was changed before regenerating. The check is to compare
+		the modified time of the generated sources with the updated time of the Application Dictionary. If there
+		is a source older than the last updated time of the Application Dictionary then the sources need to be regenerated.		
+	-->
+	<target name="generate.entities.quick" depends="compile.src.gen">
+		<taskdef name="workflow" classpathref="project.class.path" classname="org.openbravo.base.gen.GenerateEntitiesTask" />
+		<!-- debug="true" will perform the in-memory model initialization before generating entities
+	if an error occurs then, then a stacktrace is printed. -->
+		<workflow debug="false" srcGenPath="${base.src.gen}" propertiesFile="${base.config}/Openbravo.properties" file="${base.src}/org/openbravo/base/gen/gen_entity.oaw" fork="true" maxmemory="${build.maxmemory}">
 			<param name="ob.properties.location" value="${base.config}/Openbravo.properties" />
 			<param name="base.src.gen" value="${base.src.gen}" />
 			<classpath>
@@ -229,7 +252,6 @@
 		    <antcall target="postwad" inheritall="true" inheritrefs="true" />
 	</target>
 
-
 	<target name="postsrc" depends="postsrc.modules">
 		<copy todir="${build}">
 			<fileset dir="${basedir}" includes="**/*.properties" />
@@ -467,11 +489,9 @@
 		<antcall target="update.build.timestamp"/>
 	</target>
 	
-	<target name="build.quick" depends="generate.entities,wad.quick,compileSqlc,postsrc,translate">
+	<target name="build.quick" depends="generate.entities.quick,wad.quick,compileSqlc,postsrc,translate">
 		<antcall target="update.build.timestamp"/>
 	</target>
-	
-	
 
 	<target name="translate" if="translation">
 		<antcall inheritall="true" inheritrefs="true" target="compile.translate">
--- a/src/org/openbravo/base/gen/GenerateEntitiesTask.java	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/gen/GenerateEntitiesTask.java	Thu Jan 29 18:34:05 2009 +0000
@@ -19,6 +19,8 @@
 
 package org.openbravo.base.gen;
 
+import java.io.File;
+
 import org.apache.log4j.Logger;
 import org.openarchitectureware.workflow.ant.WorkflowAntTask;
 import org.openbravo.base.exception.OBException;
@@ -39,6 +41,7 @@
             .getLogger(GenerateEntitiesTask.class);
 
     private static String basePath;
+    private String srcGenPath;
 
     public static String getBasePath() {
         return basePath;
@@ -61,7 +64,13 @@
     }
 
     @Override
-    public final void execute() {
+    public void execute() {
+
+        if (!hasChanged()) {
+            log
+                    .info("Model has not changed since last run, not re-generating entities");
+            return;
+        }
 
         if (getBasePath() == null) {
             setBasePath(super.getProject().getBaseDir().getAbsolutePath());
@@ -92,6 +101,37 @@
         super.execute();
     }
 
+    private boolean hasChanged() {
+        // first check if there is a directory
+        // already in the src-gen
+        // if not then regenerate anyhow
+        final File modelDir = new File(getSrcGenPath(), "org");
+        if (!modelDir.exists()) {
+            return true;
+        }
+
+        // check if there is a sourcefile which was updated before the last
+        // time the model was created. In this case that sourcefile (and
+        // all source files need to be regenerated
+        final long lastModelUpdateTime = ModelProvider.getInstance()
+                .getModelLastUpdated();
+        return isSourceFileUpdatedBeforeModelChange(modelDir,
+                lastModelUpdateTime);
+    }
+
+    private boolean isSourceFileUpdatedBeforeModelChange(File file,
+            long modelUpdateTime) {
+        if (file.isDirectory()) {
+            for (File child : file.listFiles()) {
+                if (isSourceFileUpdatedBeforeModelChange(child, modelUpdateTime)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+        return file.lastModified() < modelUpdateTime;
+    }
+
     public String getProviderConfigDirectory() {
         return providerConfigDirectory;
     }
@@ -107,4 +147,12 @@
     public void setDebug(boolean debug) {
         this.debug = debug;
     }
+
+    public String getSrcGenPath() {
+        return srcGenPath;
+    }
+
+    public void setSrcGenPath(String srcGenPath) {
+        this.srcGenPath = srcGenPath;
+    }
 }
--- a/src/org/openbravo/base/model/Column.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/Column.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -53,6 +53,8 @@
 		<property name="isTransientCondition" column="istransientcondition"/>
 		                		
 		<many-to-one name="module" not-null="true" class="org.openbravo.base.model.Module" column="ad_module_id"/>
+
+		<property name="updated"/>
 		
 	</class>
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/ModelObject.java	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/ModelObject.java	Thu Jan 29 18:34:05 2009 +0000
@@ -19,6 +19,7 @@
 
 package org.openbravo.base.model;
 
+import java.util.Date;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -34,6 +35,7 @@
     private String id = null;
     private boolean active = true;
     private String name;
+    private Date updated;
 
     private Map<String, Object> data = new HashMap<String, Object>();
 
@@ -93,4 +95,12 @@
     public void setName(String name) {
         this.name = name;
     }
+
+    public Date getUpdated() {
+        return updated;
+    }
+
+    public void setUpdated(Date updated) {
+        this.updated = updated;
+    }
 }
\ No newline at end of file
--- a/src/org/openbravo/base/model/ModelProvider.java	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/ModelProvider.java	Thu Jan 29 18:34:05 2009 +0000
@@ -20,6 +20,7 @@
 package org.openbravo.base.model;
 
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -71,20 +72,22 @@
     private HashMap<String, Entity> entitiesByTableId = null;
     private List<Module> modules;
 
+    private long modelLastUpdated;
+
     /**
      * Returns the singleton instance providing the ModelProvider functionality.
      * 
      * @return the ModelProvider instance
      */
     public static ModelProvider getInstance() {
-	// set in a localInstance to prevent threading issues when
-	// reseting it in setInstance()
-	ModelProvider localInstance = instance;
-	if (localInstance == null) {
-	    localInstance = OBProvider.getInstance().get(ModelProvider.class);
-	    instance = localInstance;
-	}
-	return localInstance;
+        // set in a localInstance to prevent threading issues when
+        // reseting it in setInstance()
+        ModelProvider localInstance = instance;
+        if (localInstance == null) {
+            localInstance = OBProvider.getInstance().get(ModelProvider.class);
+            instance = localInstance;
+        }
+        return localInstance;
     }
 
     /**
@@ -95,7 +98,7 @@
      *            the custom ModelProvider
      */
     public static void setInstance(ModelProvider instance) {
-	ModelProvider.instance = instance;
+        ModelProvider.instance = instance;
     }
 
     /**
@@ -103,17 +106,17 @@
      * here.
      */
     public static void refresh() {
-	try {
-	    OBProvider.getInstance().removeInstance(ModelProvider.class);
-	    final ModelProvider localProvider = OBProvider.getInstance().get(
-		    ModelProvider.class);
-	    setInstance(localProvider);
-	    // initialize it
-	    localProvider.getModel();
-	} catch (final Exception e) {
-	    e.printStackTrace(System.err);
-	    throw new OBException(e);
-	}
+        try {
+            OBProvider.getInstance().removeInstance(ModelProvider.class);
+            final ModelProvider localProvider = OBProvider.getInstance().get(
+                    ModelProvider.class);
+            setInstance(localProvider);
+            // initialize it
+            localProvider.getModel();
+        } catch (final Exception e) {
+            e.printStackTrace(System.err);
+            throw new OBException(e);
+        }
     }
 
     /**
@@ -124,114 +127,150 @@
      * @return the list Entities
      */
     public List<Entity> getModel() {
-	if (model == null) {
-	    initialize();
-	}
+        if (model == null) {
+            initialize();
+        }
 
-	return model;
+        return model;
     }
 
     private void initialize() {
-	log.info("Building runtime model");
+        log.info("Building runtime model");
 
-	// Caching model (tables, table-references, search-references,
-	// list-references)
-	// Changed to use the SessionHandler directly because the dal
-	// layer uses the ModelProvider, so otherwise there will be a
-	// cyclic relation.
-	final SessionFactoryController sessionFactoryController = new ModelSessionFactoryController();
-	final Session session = sessionFactoryController.getSessionFactory()
-		.openSession();
-	final Transaction tx = session.beginTransaction();
-	try {
-	    log.debug("Read model from db");
-	    tables = list(session, Table.class);
-	    // read the columns in one query and assign them to the table
-	    final List<Column> cols = readColumns(session);
-	    assignColumnsToTable(cols);
+        // Caching model (tables, table-references, search-references,
+        // list-references)
+        // Changed to use the SessionHandler directly because the dal
+        // layer uses the ModelProvider, so otherwise there will be a
+        // cyclic relation.
+        final SessionFactoryController sessionFactoryController = new ModelSessionFactoryController();
+        final Session session = sessionFactoryController.getSessionFactory()
+                .openSession();
+        final Transaction tx = session.beginTransaction();
+        try {
+            log.debug("Read model from db");
+            tables = list(session, Table.class);
 
-	    refTable = list(session, RefTable.class);
-	    refSearch = list(session, RefSearch.class);
-	    refList = list(session, RefList.class);
-	    modules = retrieveModules(session);
-	    tables = removeInvalidTables(tables);
+            // read the columns in one query and assign them to the table
+            final List<Column> cols = readColumns(session);
+            assignColumnsToTable(cols);
 
-	    for (final RefTable rt : refTable) {
-		refTableMap.put(rt.getId(), rt);
-	    }
-	    for (final RefSearch rs : refSearch) {
-		// note mapped by reference id
-		refSearchMap.put(rs.getReference(), rs);
-	    }
+            refTable = list(session, RefTable.class);
+            refSearch = list(session, RefSearch.class);
+            refList = list(session, RefList.class);
+            modules = retrieveModules(session);
+            tables = removeInvalidTables(tables);
+            final List<Package> packages = list(session, Package.class);
 
-	    // this map stores the mapped tables
-	    tablesByTableName = new HashMap<String, Table>();
-	    for (final Table t : tables) {
-		// tables are stored case insensitive!
-		tablesByTableName.put(t.getTableName().toLowerCase(), t);
+            // compute the last updated time
+            long currentLastTimeUpdated = 0;
+            currentLastTimeUpdated = getLastUpdated(tables,
+                    currentLastTimeUpdated);
+            currentLastTimeUpdated = getLastUpdated(cols,
+                    currentLastTimeUpdated);
+            currentLastTimeUpdated = getLastUpdated(refTable,
+                    currentLastTimeUpdated);
+            currentLastTimeUpdated = getLastUpdated(refSearch,
+                    currentLastTimeUpdated);
+            currentLastTimeUpdated = getLastUpdated(refList,
+                    currentLastTimeUpdated);
+            currentLastTimeUpdated = getLastUpdated(modules,
+                    currentLastTimeUpdated);
+            currentLastTimeUpdated = getLastUpdated(packages,
+                    currentLastTimeUpdated);
+            setModelLastUpdated(currentLastTimeUpdated);
+            log
+                    .debug("Model was updated last time on "
+                            + getModelLastUpdated());
 
-		if (t.getName().contains("_")) {
-		    System.err.println(t.getName());
-		}
+            for (final RefTable rt : refTable) {
+                refTableMap.put(rt.getId(), rt);
+            }
+            for (final RefSearch rs : refSearch) {
+                // note mapped by reference id
+                refSearchMap.put(rs.getReference(), rs);
+            }
 
-	    }
+            // this map stores the mapped tables
+            tablesByTableName = new HashMap<String, Table>();
+            for (final Table t : tables) {
+                // tables are stored case insensitive!
+                tablesByTableName.put(t.getTableName().toLowerCase(), t);
 
-	    log.debug("Setting referencetypes for columns");
-	    for (final Table t : tablesByTableName.values()) {
-		t.setReferenceTypes(ModelProvider.instance);
-	    }
+                if (t.getName().contains("_")) {
+                    System.err.println(t.getName());
+                }
 
-	    log.debug("Setting List Values for columns");
-	    for (final RefList rl : refList) {
-		rl.setAllowedValue();
-	    }
+            }
 
-	    model = new ArrayList<Entity>();
-	    entitiesByName = new HashMap<String, Entity>();
-	    entitiesByClassName = new HashMap<String, Entity>();
-	    entitiesByTableName = new HashMap<String, Entity>();
-	    entitiesByTableId = new HashMap<String, Entity>();
-	    for (final Table t : tablesByTableName.values()) {
-		log.debug("Building model for table " + t.getTableName());
-		final Entity e = new Entity();
-		e.initialize(t);
-		model.add(e);
-		entitiesByClassName.put(e.getClassName(), e);
-		entitiesByName.put(e.getName(), e);
-		entitiesByTableName.put(t.getTableName().toUpperCase(), e);
-		entitiesByTableId.put(t.getId(), e);
-	    }
+            log.debug("Setting referencetypes for columns");
+            for (final Table t : tablesByTableName.values()) {
+                t.setReferenceTypes(ModelProvider.instance);
+            }
 
-	    // in the second pass set all the referenceProperties
-	    // and targetEntities
-	    // uses global member tablesByTableName
-	    setReferenceProperties();
+            log.debug("Setting List Values for columns");
+            for (final RefList rl : refList) {
+                rl.setAllowedValue();
+            }
 
-	    // add virtual property for the case that the
-	    // id property is also a reference (a foreign key)
-	    // In this case hibernate requires two mappings
-	    // one for the id (a string) and for the reference
-	    // in addition the id generation strategy should be set
-	    // to foreign.
-	    log.debug("Setting virtual property for many-to-one id's");
-	    setVirtualPropertiesForReferenceId();
+            model = new ArrayList<Entity>();
+            entitiesByName = new HashMap<String, Entity>();
+            entitiesByClassName = new HashMap<String, Entity>();
+            entitiesByTableName = new HashMap<String, Entity>();
+            entitiesByTableId = new HashMap<String, Entity>();
+            for (final Table t : tablesByTableName.values()) {
+                log.debug("Building model for table " + t.getTableName());
+                final Entity e = new Entity();
+                e.initialize(t);
+                model.add(e);
+                entitiesByClassName.put(e.getClassName(), e);
+                entitiesByName.put(e.getName(), e);
+                entitiesByTableName.put(t.getTableName().toUpperCase(), e);
+                entitiesByTableId.put(t.getId(), e);
+            }
 
-	    buildUniqueConstraints(session, sessionFactoryController);
-	} finally {
-	    log
-		    .debug("Closing session and sessionfactory used during model read");
-	    tx.commit();
-	    session.close();
-	    sessionFactoryController.getSessionFactory().close();
-	}
+            // in the second pass set all the referenceProperties
+            // and targetEntities
+            // uses global member tablesByTableName
+            setReferenceProperties();
 
-	// now initialize the names of the properties
-	for (final Entity e : model) {
-	    for (final Property p : e.getProperties()) {
-		p.initializeName();
-	    }
-	}
-	clearLists();
+            // add virtual property for the case that the
+            // id property is also a reference (a foreign key)
+            // In this case hibernate requires two mappings
+            // one for the id (a string) and for the reference
+            // in addition the id generation strategy should be set
+            // to foreign.
+            log.debug("Setting virtual property for many-to-one id's");
+            setVirtualPropertiesForReferenceId();
+
+            buildUniqueConstraints(session, sessionFactoryController);
+        } finally {
+            log
+                    .debug("Closing session and sessionfactory used during model read");
+            tx.commit();
+            session.close();
+            sessionFactoryController.getSessionFactory().close();
+        }
+
+        // now initialize the names of the properties
+        for (final Entity e : model) {
+            for (final Property p : e.getProperties()) {
+                p.initializeName();
+            }
+        }
+        clearLists();
+    }
+
+    private <T extends ModelObject> long getLastUpdated(List<T> modelObjects,
+            long currentLastTime) {
+        long localCurrentLastTime = currentLastTime;
+        for (ModelObject modelObject : modelObjects) {
+            final Date modelObjectUpdated = modelObject.getUpdated();
+            if (modelObjectUpdated != null
+                    && modelObjectUpdated.getTime() > localCurrentLastTime) {
+                localCurrentLastTime = modelObjectUpdated.getTime();
+            }
+        }
+        return localCurrentLastTime;
     }
 
     /**
@@ -240,323 +279,323 @@
      * @return list of tables in the database
      */
     public List<Table> getTables() {
-	final SessionFactoryController sessionFactoryController = new ModelSessionFactoryController();
-	final Session session = sessionFactoryController.getSessionFactory()
-		.openSession();
-	final Transaction tx = session.beginTransaction();
-	try {
-	    tables = list(session, Table.class);
-	    // read the columns in one query and assign them to the table
-	    final List<Column> cols = readColumns(session);
-	    assignColumnsToTable(cols);
-	    return tables;
-	} finally {
-	    log
-		    .debug("Closing session and sessionfactory used during model read");
-	    tx.commit();
-	    session.close();
-	    sessionFactoryController.getSessionFactory().close();
-	}
+        final SessionFactoryController sessionFactoryController = new ModelSessionFactoryController();
+        final Session session = sessionFactoryController.getSessionFactory()
+                .openSession();
+        final Transaction tx = session.beginTransaction();
+        try {
+            tables = list(session, Table.class);
+            // read the columns in one query and assign them to the table
+            final List<Column> cols = readColumns(session);
+            assignColumnsToTable(cols);
+            return tables;
+        } finally {
+            log
+                    .debug("Closing session and sessionfactory used during model read");
+            tx.commit();
+            session.close();
+            sessionFactoryController.getSessionFactory().close();
+        }
     }
 
     // clears some in-memory lists to save memory
     private void clearLists() {
-	tables = null;
-	tablesByTableName = null;
-	refTable = null;
-	refSearch = null;
-	refTableMap = new HashMap<String, RefTable>();
-	refSearchMap = new HashMap<String, RefSearch>();
-	refList = null;
+        tables = null;
+        tablesByTableName = null;
+        refTable = null;
+        refSearch = null;
+        refTableMap = new HashMap<String, RefTable>();
+        refSearchMap = new HashMap<String, RefSearch>();
+        refList = null;
     }
 
     @SuppressWarnings("unchecked")
     private List<Column> readColumns(Session session) {
-	final Criteria c = session.createCriteria(Column.class);
-	c.addOrder(Order.asc("position"));
-	return c.list();
+        final Criteria c = session.createCriteria(Column.class);
+        c.addOrder(Order.asc("position"));
+        return c.list();
     }
 
     private void assignColumnsToTable(List<Column> cols) {
-	for (final Column column : cols) {
-	    final Table table = column.getTable();
-	    table.getColumns().add(column);
-	}
+        for (final Column column : cols) {
+            final Table table = column.getTable();
+            table.getColumns().add(column);
+        }
     }
 
     private void setVirtualPropertiesForReferenceId() {
 
-	for (final Entity e : entitiesByName.values()) {
-	    if (e.getIdProperties().size() == 1
-		    && !e.getIdProperties().get(0).isPrimitive()) {
-		createIdReferenceProperty(e);
-	    } else if (e.getIdProperties().size() > 1) {
-		createCompositeId(e);
-	    }
-	    // add virtual property in the parent table based on
-	    // isParent columns
-	    if (e.getParentProperties().size() > 0) {
-		createPropertyInParentEntity(e);
-	    }
-	}
+        for (final Entity e : entitiesByName.values()) {
+            if (e.getIdProperties().size() == 1
+                    && !e.getIdProperties().get(0).isPrimitive()) {
+                createIdReferenceProperty(e);
+            } else if (e.getIdProperties().size() > 1) {
+                createCompositeId(e);
+            }
+            // add virtual property in the parent table based on
+            // isParent columns
+            if (e.getParentProperties().size() > 0) {
+                createPropertyInParentEntity(e);
+            }
+        }
     }
 
     private void setReferenceProperties() {
-	log.debug("Setting reference property");
-	// uses global member tablesByTableName
-	for (final Table t : tablesByTableName.values()) {
-	    for (final Column c : t.getColumns()) {
-		if (!c.isPrimitiveType()) {
-		    final Property thisProp = c.getProperty();
-		    log
-			    .debug("Setting targetEntity and reference Property for "
-				    + thisProp);
-		    final Column thatColumn = c.getReferenceType();
-		    if (thatColumn == null) {
-			log
-				.error("Property "
-					+ thisProp
-					+ " is mapped incorrectly, there is no reference column for it, removing from the mapping");
-			thisProp.getEntity().getProperties().remove(thisProp);
-			if (thisProp.getEntity().getIdProperties().remove(
-				thisProp)) {
-			    Check
-				    .fail("Incorrect mapping for property "
-					    + thisProp
-					    + " which is an id, mapping fails, stopping here");
-			}
-			thisProp.getEntity().getIdentifierProperties().remove(
-				thisProp);
-			continue;
-		    }
-		    // targetentity is set within setReferencedProperty
-		    final Property thatProperty = thatColumn.getProperty();
-		    thisProp.setReferencedProperty(thatProperty);
-		}
-	    }
-	}
+        log.debug("Setting reference property");
+        // uses global member tablesByTableName
+        for (final Table t : tablesByTableName.values()) {
+            for (final Column c : t.getColumns()) {
+                if (!c.isPrimitiveType()) {
+                    final Property thisProp = c.getProperty();
+                    log
+                            .debug("Setting targetEntity and reference Property for "
+                                    + thisProp);
+                    final Column thatColumn = c.getReferenceType();
+                    if (thatColumn == null) {
+                        log
+                                .error("Property "
+                                        + thisProp
+                                        + " is mapped incorrectly, there is no reference column for it, removing from the mapping");
+                        thisProp.getEntity().getProperties().remove(thisProp);
+                        if (thisProp.getEntity().getIdProperties().remove(
+                                thisProp)) {
+                            Check
+                                    .fail("Incorrect mapping for property "
+                                            + thisProp
+                                            + " which is an id, mapping fails, stopping here");
+                        }
+                        thisProp.getEntity().getIdentifierProperties().remove(
+                                thisProp);
+                        continue;
+                    }
+                    // targetentity is set within setReferencedProperty
+                    final Property thatProperty = thatColumn.getProperty();
+                    thisProp.setReferencedProperty(thatProperty);
+                }
+            }
+        }
 
     }
 
     private List<Table> removeInvalidTables(List<Table> allTables) {
-	final List<Table> toRemove = new ArrayList<Table>();
-	final List<Table> localTables = allTables;
-	for (final Table t : localTables) {
-	    // taking into account inactive tables for now...
-	    if (false && !t.isActive()) {
-		log
-			.debug("Table " + t.getName()
-				+ " is not active ignoring it");
-		toRemove.add(t);
-		continue;
-	    }
+        final List<Table> toRemove = new ArrayList<Table>();
+        final List<Table> localTables = allTables;
+        for (final Table t : localTables) {
+            // taking into account inactive tables for now...
+            if (false && !t.isActive()) {
+                log
+                        .debug("Table " + t.getName()
+                                + " is not active ignoring it");
+                toRemove.add(t);
+                continue;
+            }
 
-	    if (t.getPrimaryKeyColumns().size() == 0) {
-		log.debug("Ignoring table " + t.getName()
-			+ " because it has no primary key columns");
-		toRemove.add(t);
-		continue;
-	    }
-	}
-	allTables.removeAll(toRemove);
-	return tables;
+            if (t.getPrimaryKeyColumns().size() == 0) {
+                log.debug("Ignoring table " + t.getName()
+                        + " because it has no primary key columns");
+                toRemove.add(t);
+                continue;
+            }
+        }
+        allTables.removeAll(toRemove);
+        return tables;
     }
 
     // Build unique constraints
     private void buildUniqueConstraints(Session session,
-	    SessionFactoryController sessionFactoryController) {
-	final List<UniqueConstraintColumn> uniqueConstraintColumns = getUniqueConstraintColumns(
-		session, sessionFactoryController);
-	Entity entity = null;
-	UniqueConstraint uniqueConstraint = null;
-	for (final UniqueConstraintColumn uniqueConstraintColumn : uniqueConstraintColumns) {
-	    // get the entity
-	    if (entity == null
-		    || !entity.getTableName().equalsIgnoreCase(
-			    uniqueConstraintColumn.getTableName())) {
-		entity = getEntityByTableName(uniqueConstraintColumn
-			.getTableName());
-		uniqueConstraint = null;
-	    }
-	    if (entity == null) {
-		log.warn("No entity found for "
-			+ uniqueConstraintColumn.getTableName()
-			+ " table, for uniqueconstraint computation");
-		continue;
-	    }
+            SessionFactoryController sessionFactoryController) {
+        final List<UniqueConstraintColumn> uniqueConstraintColumns = getUniqueConstraintColumns(
+                session, sessionFactoryController);
+        Entity entity = null;
+        UniqueConstraint uniqueConstraint = null;
+        for (final UniqueConstraintColumn uniqueConstraintColumn : uniqueConstraintColumns) {
+            // get the entity
+            if (entity == null
+                    || !entity.getTableName().equalsIgnoreCase(
+                            uniqueConstraintColumn.getTableName())) {
+                entity = getEntityByTableName(uniqueConstraintColumn
+                        .getTableName());
+                uniqueConstraint = null;
+            }
+            if (entity == null) {
+                log.warn("No entity found for "
+                        + uniqueConstraintColumn.getTableName()
+                        + " table, for uniqueconstraint computation");
+                continue;
+            }
 
-	    // the uniqueconstraint
-	    if (uniqueConstraint == null
-		    || !uniqueConstraint.getName().equalsIgnoreCase(
-			    uniqueConstraintColumn.getUniqueConstraintName())) {
-		// note uniqueconstraint should be set to null, because the
-		// for loop my not find another one
-		uniqueConstraint = null;
-		// get a new one, walk through all of them of the entity
-		for (final UniqueConstraint uc : entity.getUniqueConstraints()) {
-		    if (uc.getName().equalsIgnoreCase(
-			    uniqueConstraintColumn.getUniqueConstraintName())) {
-			uniqueConstraint = uc;
-			break;
-		    }
-		}
-	    }
-	    if (uniqueConstraint == null) {
-		uniqueConstraint = new UniqueConstraint();
-		uniqueConstraint.setEntity(entity);
-		uniqueConstraint.setName(uniqueConstraintColumn
-			.getUniqueConstraintName());
-		entity.getUniqueConstraints().add(uniqueConstraint);
-	    }
-	    uniqueConstraint.addPropertyForColumn(uniqueConstraintColumn
-		    .getColumnName());
-	}
+            // the uniqueconstraint
+            if (uniqueConstraint == null
+                    || !uniqueConstraint.getName().equalsIgnoreCase(
+                            uniqueConstraintColumn.getUniqueConstraintName())) {
+                // note uniqueconstraint should be set to null, because the
+                // for loop my not find another one
+                uniqueConstraint = null;
+                // get a new one, walk through all of them of the entity
+                for (final UniqueConstraint uc : entity.getUniqueConstraints()) {
+                    if (uc.getName().equalsIgnoreCase(
+                            uniqueConstraintColumn.getUniqueConstraintName())) {
+                        uniqueConstraint = uc;
+                        break;
+                    }
+                }
+            }
+            if (uniqueConstraint == null) {
+                uniqueConstraint = new UniqueConstraint();
+                uniqueConstraint.setEntity(entity);
+                uniqueConstraint.setName(uniqueConstraintColumn
+                        .getUniqueConstraintName());
+                entity.getUniqueConstraints().add(uniqueConstraint);
+            }
+            uniqueConstraint.addPropertyForColumn(uniqueConstraintColumn
+                    .getColumnName());
+        }
 
-	// dumpUniqueConstraints();
+        // dumpUniqueConstraints();
     }
 
     // returns a list of uniqueconstraint columns containing all
     // uniqueconstraints from the database
     private List<UniqueConstraintColumn> getUniqueConstraintColumns(
-	    Session session, SessionFactoryController sessionFactoryController) {
-	final List<UniqueConstraintColumn> result = new ArrayList<UniqueConstraintColumn>();
-	final SQLQuery sqlQuery = session
-		.createSQLQuery(sessionFactoryController
-			.getUniqueConstraintQuery());
-	for (final Object row : sqlQuery.list()) {
-	    // cast to an array of strings!
-	    // 0: tablename
-	    // 1: columnname
-	    // 2: uniqueconstraintname
-	    final Object[] values = (Object[]) row;
-	    Check.isTrue(values.length == 3,
-		    "Unexpected value length for constraint query, should be 3, but is "
-			    + values.length);
-	    final UniqueConstraintColumn uniqueConstraintColumn = new UniqueConstraintColumn();
-	    uniqueConstraintColumn.setTableName((String) values[0]);
-	    uniqueConstraintColumn.setColumnName((String) values[1]);
-	    uniqueConstraintColumn.setUniqueConstraintName((String) values[2]);
-	    result.add(uniqueConstraintColumn);
-	}
-	return result;
+            Session session, SessionFactoryController sessionFactoryController) {
+        final List<UniqueConstraintColumn> result = new ArrayList<UniqueConstraintColumn>();
+        final SQLQuery sqlQuery = session
+                .createSQLQuery(sessionFactoryController
+                        .getUniqueConstraintQuery());
+        for (final Object row : sqlQuery.list()) {
+            // cast to an array of strings!
+            // 0: tablename
+            // 1: columnname
+            // 2: uniqueconstraintname
+            final Object[] values = (Object[]) row;
+            Check.isTrue(values.length == 3,
+                    "Unexpected value length for constraint query, should be 3, but is "
+                            + values.length);
+            final UniqueConstraintColumn uniqueConstraintColumn = new UniqueConstraintColumn();
+            uniqueConstraintColumn.setTableName((String) values[0]);
+            uniqueConstraintColumn.setColumnName((String) values[1]);
+            uniqueConstraintColumn.setUniqueConstraintName((String) values[2]);
+            result.add(uniqueConstraintColumn);
+        }
+        return result;
     }
 
     // expects that there is only one property
     private void createIdReferenceProperty(Entity e) {
-	Check
-		.isTrue(e.getIdProperties().size() == 1
-			&& !e.getIdProperties().get(0).isPrimitive(),
-			"Expect one id property for the entity and it should be a reference type");
-	final Property p = e.getIdProperties().get(0);
-	log.debug("Handling many-to-one reference for " + p);
-	Check.isTrue(e.getIdProperties().size() == 1,
-		"Foreign-key id-properties are only handled if there is one in an entity "
-			+ e.getName());
-	// create a reference property
-	final Property newProp = new Property();
-	newProp.setEntity(e);
-	newProp.setId(false);
-	newProp.setIdentifier(p.isIdentifier());
-	newProp.setMandatory(true);
-	newProp.setPrimitive(false);
-	newProp.setTargetEntity(p.getTargetEntity());
-	newProp.setOneToOne(true);
+        Check
+                .isTrue(e.getIdProperties().size() == 1
+                        && !e.getIdProperties().get(0).isPrimitive(),
+                        "Expect one id property for the entity and it should be a reference type");
+        final Property p = e.getIdProperties().get(0);
+        log.debug("Handling many-to-one reference for " + p);
+        Check.isTrue(e.getIdProperties().size() == 1,
+                "Foreign-key id-properties are only handled if there is one in an entity "
+                        + e.getName());
+        // create a reference property
+        final Property newProp = new Property();
+        newProp.setEntity(e);
+        newProp.setId(false);
+        newProp.setIdentifier(p.isIdentifier());
+        newProp.setMandatory(true);
+        newProp.setPrimitive(false);
+        newProp.setTargetEntity(p.getTargetEntity());
+        newProp.setOneToOne(true);
 
-	// the name is the name of the class of the target without
-	// the package part and with the first character lowercased
-	final String propName = p.getSimpleTypeName().substring(0, 1)
-		.toLowerCase()
-		+ p.getSimpleTypeName().substring(1);
-	newProp.setName(propName);
-	e.addProperty(newProp);
+        // the name is the name of the class of the target without
+        // the package part and with the first character lowercased
+        final String propName = p.getSimpleTypeName().substring(0, 1)
+                .toLowerCase()
+                + p.getSimpleTypeName().substring(1);
+        newProp.setName(propName);
+        e.addProperty(newProp);
 
-	// and change the old id property to a primitive one
-	final Property targetIdProp = p.getTargetEntity().getIdProperties()
-		.get(0);
-	Check
-		.isTrue(
-			targetIdProp.isPrimitive(),
-			"Entity "
-				+ e
-				+ ", The ID property of the referenced class should be primitive, an other case is not supported");
-	p.setPrimitive(true);
-	p.setIdBasedOnProperty(newProp);
-	p.setIdentifier(false);
-	p.setTargetEntity(null);
-	p.setPrimitiveType(targetIdProp.getPrimitiveType());
+        // and change the old id property to a primitive one
+        final Property targetIdProp = p.getTargetEntity().getIdProperties()
+                .get(0);
+        Check
+                .isTrue(
+                        targetIdProp.isPrimitive(),
+                        "Entity "
+                                + e
+                                + ", The ID property of the referenced class should be primitive, an other case is not supported");
+        p.setPrimitive(true);
+        p.setIdBasedOnProperty(newProp);
+        p.setIdentifier(false);
+        p.setTargetEntity(null);
+        p.setPrimitiveType(targetIdProp.getPrimitiveType());
     }
 
     private void createCompositeId(Entity e) {
-	Check.isTrue(e.getIdProperties().size() > 1, "Expect that entity " + e
-		+ " has more than one id property ");
-	final Property compId = new Property();
-	compId.setEntity(e);
-	compId.setId(true);
-	compId.setIdentifier(false);
-	compId.setMandatory(true);
-	compId.setPrimitive(false);
-	compId.setCompositeId(true);
-	compId.setName("id");
-	// compId is added to the entity below
+        Check.isTrue(e.getIdProperties().size() > 1, "Expect that entity " + e
+                + " has more than one id property ");
+        final Property compId = new Property();
+        compId.setEntity(e);
+        compId.setId(true);
+        compId.setIdentifier(false);
+        compId.setMandatory(true);
+        compId.setPrimitive(false);
+        compId.setCompositeId(true);
+        compId.setName("id");
+        // compId is added to the entity below
 
-	final List<Property> toRemove = new ArrayList<Property>();
-	for (final Property p : e.getIdProperties()) {
-	    compId.getIdParts().add(p);
-	    p.setPartOfCompositeId(true);
-	    p.setId(false);
-	    toRemove.add(p);
-	}
-	e.getIdProperties().removeAll(toRemove);
-	Check.isTrue(e.getIdProperties().size() == 0,
-		"There should not be any id properties (entity " + e
-			+ ") at this point");
+        final List<Property> toRemove = new ArrayList<Property>();
+        for (final Property p : e.getIdProperties()) {
+            compId.getIdParts().add(p);
+            p.setPartOfCompositeId(true);
+            p.setId(false);
+            toRemove.add(p);
+        }
+        e.getIdProperties().removeAll(toRemove);
+        Check.isTrue(e.getIdProperties().size() == 0,
+                "There should not be any id properties (entity " + e
+                        + ") at this point");
 
-	// and now add the id property again
-	e.addProperty(compId);
+        // and now add the id property again
+        e.addProperty(compId);
     }
 
     private void createPropertyInParentEntity(Entity e) {
-	for (final Property p : e.getParentProperties()) {
-	    if (p.getReferencedProperty() == null) {
-		continue;
-	    }
-	    final Entity parent = p.getReferencedProperty().getEntity();
-	    createChildProperty(parent, p);
-	}
+        for (final Property p : e.getParentProperties()) {
+            if (p.getReferencedProperty() == null) {
+                continue;
+            }
+            final Entity parent = p.getReferencedProperty().getEntity();
+            createChildProperty(parent, p);
+        }
     }
 
     private void createChildProperty(Entity parentEntity, Property childProperty) {
-	final Property newProp = new Property();
+        final Property newProp = new Property();
 
-	newProp.setEntity(parentEntity);
-	newProp.setId(false);
-	newProp.setIdentifier(false);
-	newProp.setMandatory(false);
-	newProp.setPrimitive(false);
-	newProp.setTargetEntity(childProperty.getEntity());
-	newProp.setReferencedProperty(childProperty);
-	newProp.setOneToOne(false);
-	newProp.setOneToMany(true);
+        newProp.setEntity(parentEntity);
+        newProp.setId(false);
+        newProp.setIdentifier(false);
+        newProp.setMandatory(false);
+        newProp.setPrimitive(false);
+        newProp.setTargetEntity(childProperty.getEntity());
+        newProp.setReferencedProperty(childProperty);
+        newProp.setOneToOne(false);
+        newProp.setOneToMany(true);
 
-	parentEntity.addProperty(newProp);
+        parentEntity.addProperty(newProp);
     }
 
     @SuppressWarnings("unchecked")
     public <T extends Object> List<T> list(Session s, Class<T> clazz) {
-	final Criteria c = s.createCriteria(clazz);
-	return c.list();
+        final Criteria c = s.createCriteria(clazz);
+        return c.list();
     }
 
     public List<Module> getModules() {
-	return modules;
+        return modules;
     }
 
     @SuppressWarnings("unchecked")
     private List<Module> retrieveModules(Session s) {
-	final Criteria c = s.createCriteria(Module.class);
-	c.addOrder(Order.asc("seqno"));
-	c.add(Expression.eq("active", true));
-	return c.list();
+        final Criteria c = s.createCriteria(Module.class);
+        c.addOrder(Order.asc("seqno"));
+        c.add(Expression.eq("active", true));
+        return c.list();
     }
 
     /**
@@ -568,14 +607,14 @@
      * @throws CheckException
      */
     private Table getTable(String tableName) throws CheckException {
-	if (tablesByTableName == null)
-	    getModel();
-	// search case insensitive!
-	final Table table = tablesByTableName.get(tableName.toLowerCase());
-	if (table == null)
-	    Check.fail("Table: " + tableName
-		    + " not found in runtime model, is it maybe inactive?");
-	return table;
+        if (tablesByTableName == null)
+            getModel();
+        // search case insensitive!
+        final Table table = tablesByTableName.get(tableName.toLowerCase());
+        if (table == null)
+            Check.fail("Table: " + tableName
+                    + " not found in runtime model, is it maybe inactive?");
+        return table;
     }
 
     /**
@@ -588,13 +627,13 @@
      * @throws CheckException
      */
     public Entity getEntity(String entityName) throws CheckException {
-	if (model == null)
-	    getModel();
-	final Entity entity = entitiesByName.get(entityName);
-	if (entity == null)
-	    Check.fail("Mapping name: " + entityName
-		    + " not found in runtime model");
-	return entity;
+        if (model == null)
+            getModel();
+        final Entity entity = entitiesByName.get(entityName);
+        if (entity == null)
+            Check.fail("Mapping name: " + entityName
+                    + " not found in runtime model");
+        return entity;
     }
 
     /**
@@ -607,15 +646,15 @@
      * @return the Entity or null if not found
      */
     public Entity getEntityByTableName(String tableName) {
-	if (model == null)
-	    getModel();
-	final Entity entity = entitiesByTableName.get(tableName.toUpperCase());
-	if (entity == null) {
-	    log
-		    .warn("Table name: " + tableName
-			    + " not found in runtime model");
-	}
-	return entity;
+        if (model == null)
+            getModel();
+        final Entity entity = entitiesByTableName.get(tableName.toUpperCase());
+        if (entity == null) {
+            log
+                    .warn("Table name: " + tableName
+                            + " not found in runtime model");
+        }
+        return entity;
     }
 
     /**
@@ -629,80 +668,88 @@
      * @throws CheckException
      */
     public Entity getEntity(Class<?> clz) throws CheckException {
-	if (model == null)
-	    getModel();
-	// TODO: handle subclasses, so if not found then try to find superclass!
-	final Entity entity = entitiesByClassName.get(clz.getName());
-	if (entity == null)
-	    Check.fail("Class name: " + clz.getName()
-		    + " not found in runtime model");
-	return entity;
+        if (model == null)
+            getModel();
+        // TODO: handle subclasses, so if not found then try to find superclass!
+        final Entity entity = entitiesByClassName.get(clz.getName());
+        if (entity == null)
+            Check.fail("Class name: " + clz.getName()
+                    + " not found in runtime model");
+        return entity;
     }
 
     protected Column getColumnByReference(String reference,
-	    String referenceValue, char validationType, String columnName)
-	    throws CheckException {
-	Column c = null;
+            String referenceValue, char validationType, String columnName)
+            throws CheckException {
+        Column c = null;
 
-	if (tablesByTableName == null)
-	    getModel();
+        if (tablesByTableName == null)
+            getModel();
 
-	if (reference.equals(Reference.TABLEDIR)
-		|| (reference.equals(Reference.SEARCH) && referenceValue
-			.equals(Reference.NO_REFERENCE))
-		|| reference.equals(Reference.IMAGE)
-		|| reference.equals(Reference.PRODUCT_ATTRIBUTE)
-		|| reference.equals(Reference.RESOURCE_ASSIGNMENT)) {
+        if (reference.equals(Reference.TABLEDIR)
+                || (reference.equals(Reference.SEARCH) && referenceValue
+                        .equals(Reference.NO_REFERENCE))
+                || reference.equals(Reference.IMAGE)
+                || reference.equals(Reference.PRODUCT_ATTRIBUTE)
+                || reference.equals(Reference.RESOURCE_ASSIGNMENT)) {
 
-	    // Removing _ID from tableName based on Openbravo's naming
-	    // convention
-	    String sTable = columnName.substring(0, columnName.length() - 3);
+            // Removing _ID from tableName based on Openbravo's naming
+            // convention
+            String sTable = columnName.substring(0, columnName.length() - 3);
 
-	    // TODO: solve references in the application dictionary
-	    // Special Cases
-	    if (sTable.equals("Ref_OrderLine"))
-		sTable = "C_OrderLine";
+            // TODO: solve references in the application dictionary
+            // Special Cases
+            if (sTable.equals("Ref_OrderLine"))
+                sTable = "C_OrderLine";
 
-	    if (columnName.equals("C_Settlement_Cancel_ID")
-		    || columnName.equals("C_Settlement_Generate_ID"))
-		sTable = "C_Settlement";
+            if (columnName.equals("C_Settlement_Cancel_ID")
+                    || columnName.equals("C_Settlement_Generate_ID"))
+                sTable = "C_Settlement";
 
-	    if (columnName.equals("Fact_Acct_Ref_ID"))
-		sTable = "Fact_Acct";
+            if (columnName.equals("Fact_Acct_Ref_ID"))
+                sTable = "Fact_Acct";
 
-	    if (columnName.equals("Account_ID"))
-		sTable = "C_ElementValue";
+            if (columnName.equals("Account_ID"))
+                sTable = "C_ElementValue";
 
-	    if (columnName.equalsIgnoreCase("CreatedBy")
-		    || columnName.equalsIgnoreCase("UpdatedBy"))
-		sTable = "AD_User";
+            if (columnName.equalsIgnoreCase("CreatedBy")
+                    || columnName.equalsIgnoreCase("UpdatedBy"))
+                sTable = "AD_User";
 
-	    try {
-		c = getTable(sTable).getPrimaryKeyColumns().get(0);
-	    } catch (final Exception e) {
-		e.printStackTrace();
-	    }
+            try {
+                c = getTable(sTable).getPrimaryKeyColumns().get(0);
+            } catch (final Exception e) {
+                e.printStackTrace();
+            }
 
-	} else if (reference.equals(Reference.TABLE)) {
-	    if (validationType == Reference.TABLE_VALIDATION) {
-		final RefTable rt = refTableMap.get(referenceValue);
-		if (rt != null) {
-		    c = rt.getColumn();
-		}
-	    }
-	} else if (reference.equals(Reference.SEARCH)
-		&& !referenceValue.equals(Reference.NO_REFERENCE)) {
-	    if (validationType == Reference.SEARCH_VALIDATION) {
-		final RefSearch rs = refSearchMap.get(referenceValue);
-		if (rs != null) {
-		    c = rs.getColumn();
-		}
-	    }
-	}
-	if (c == null)
-	    Check.fail("Reference column for " + columnName
-		    + " not found in runtime model [ref: " + reference
-		    + ", refval: " + referenceValue + "]");
-	return c;
+        } else if (reference.equals(Reference.TABLE)) {
+            if (validationType == Reference.TABLE_VALIDATION) {
+                final RefTable rt = refTableMap.get(referenceValue);
+                if (rt != null) {
+                    c = rt.getColumn();
+                }
+            }
+        } else if (reference.equals(Reference.SEARCH)
+                && !referenceValue.equals(Reference.NO_REFERENCE)) {
+            if (validationType == Reference.SEARCH_VALIDATION) {
+                final RefSearch rs = refSearchMap.get(referenceValue);
+                if (rs != null) {
+                    c = rs.getColumn();
+                }
+            }
+        }
+        if (c == null)
+            Check.fail("Reference column for " + columnName
+                    + " not found in runtime model [ref: " + reference
+                    + ", refval: " + referenceValue + "]");
+        return c;
+    }
+
+    public long getModelLastUpdated() {
+        return modelLastUpdated;
+    }
+
+    public void setModelLastUpdated(long modelLastUpdated) {
+        this.modelLastUpdated = modelLastUpdated;
     }
 }
--- a/src/org/openbravo/base/model/Module.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/Module.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -31,5 +31,7 @@
 		<property name="seqno" not-null="false"/>
 		<property name="javaPackage" not-null="false"/>
 
+		<property name="updated"/>
+
 	</class>
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/Package.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/Package.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -33,5 +33,7 @@
 				                		
 		<many-to-one name="module" not-null="true" class="org.openbravo.base.model.Module" column="ad_module_id"/>
 		
+		<property name="updated"/>
+		
 	</class>
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/RefList.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/RefList.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -29,6 +29,9 @@
 		<property name="value" type="string" column="value" />		
 		 
 		<many-to-one name="reference" not-null="true" class="org.openbravo.base.model.Reference" column="ad_reference_id" />
+		
+		<property name="updated"/>
+		
 	</class>
 
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/RefSearch.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/RefSearch.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -29,6 +29,9 @@
 		<property name="active" type="org.openbravo.base.session.OBYesNoType" not-null="true" column="isactive"/>
 		<property name="reference" type="string" column="ad_reference_id" />		
 		<many-to-one name="column" not-null="true" class="org.openbravo.base.model.Column" column="ad_column_id"/>
+		
+		<property name="updated"/>
+		
 	</class>
 
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/RefTable.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/RefTable.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -29,6 +29,8 @@
 		<property name="active" type="org.openbravo.base.session.OBYesNoType" not-null="true" column="isactive"/>				
 		<many-to-one name="column" not-null="true" class="org.openbravo.base.model.Column" column="ad_key"/>				
 		
+		<property name="updated"/>
+		
 	</class>
 
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/Reference.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/Reference.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -30,5 +30,7 @@
 		<property name="name" not-null="true"/>
 		<property name="validationType"/>
 		
+		<property name="updated"/>
+		
 	</class>
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/base/model/Table.hbm.xml	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/base/model/Table.hbm.xml	Thu Jan 29 18:34:05 2009 +0000
@@ -38,5 +38,7 @@
                 		
 		<many-to-one name="thePackage" not-null="true" class="org.openbravo.base.model.Package" column="ad_package_id"/>
 		       
+		<property name="updated"/>
+		       
 	</class>
 </hibernate-mapping>
\ No newline at end of file
--- a/src/org/openbravo/service/db/ReferenceDataTask.java	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/service/db/ReferenceDataTask.java	Thu Jan 29 18:34:05 2009 +0000
@@ -29,6 +29,7 @@
  * installation of Openbravo. The files are read and exported from and to the
  * src-db/database/referencedata directory.
  * 
+ * @author mtaal
  */
 public class ReferenceDataTask extends DalInitializingTask {
     public static final String REFERENCE_DATA_DIRECTORY = "/referencedata/sampledata";
--- a/src/org/openbravo/service/system/SystemService.java	Thu Jan 29 17:16:13 2009 +0000
+++ b/src/org/openbravo/service/system/SystemService.java	Thu Jan 29 18:34:05 2009 +0000
@@ -42,14 +42,14 @@
     private static SystemService instance;
 
     public static SystemService getInstance() {
-	if (instance == null) {
-	    instance = OBProvider.getInstance().get(SystemService.class);
-	}
-	return instance;
+        if (instance == null) {
+            instance = OBProvider.getInstance().get(SystemService.class);
+        }
+        return instance;
     }
 
     public static void setInstance(SystemService instance) {
-	SystemService.instance = instance;
+        SystemService.instance = instance;
     }
 
     /**
@@ -63,16 +63,16 @@
      *         afterDate, false otherwise
      */
     public boolean hasChanged(Class<?>[] clzs, Date afterDate) {
-	for (Class<?> clz : clzs) {
-	    final OBCriteria<?> obc = OBDal.getInstance().createCriteria(
-		    (Class<BaseOBObject>) clz);
-	    obc.add(Expression.gt(Organization.PROPERTY_UPDATED, afterDate));
-	    // todo: count is slower than exists, is exists possible?
-	    if (obc.count() > 0) {
-		return true;
-	    }
-	}
-	return false;
+        for (Class<?> clz : clzs) {
+            final OBCriteria<?> obc = OBDal.getInstance().createCriteria(
+                    (Class<BaseOBObject>) clz);
+            obc.add(Expression.gt(Organization.PROPERTY_UPDATED, afterDate));
+            // todo: count is slower than exists, is exists possible?
+            if (obc.count() > 0) {
+                return true;
+            }
+        }
+        return false;
     }
 
     /**
@@ -89,19 +89,19 @@
      *         afterDate, false afterwards
      */
     public <T extends BaseOBObject> boolean hasChanged(DataSet dataSet,
-	    Date afterDate) {
-	for (DataSetTable dataSetTable : dataSet.getDataSetTableList()) {
-	    final Entity entity = ModelProvider.getInstance()
-		    .getEntityByTableName(
-			    dataSetTable.getTable().getTableName());
-	    final OBCriteria<T> obc = OBDal.getInstance().createCriteria(
-		    entity.getName());
-	    obc.add(Expression.gt(Organization.PROPERTY_UPDATED, afterDate));
-	    // todo: count is slower than exists, is exists possible?
-	    if (obc.count() > 0) {
-		return true;
-	    }
-	}
-	return false;
+            Date afterDate) {
+        for (DataSetTable dataSetTable : dataSet.getDataSetTableList()) {
+            final Entity entity = ModelProvider.getInstance()
+                    .getEntityByTableName(
+                            dataSetTable.getTable().getTableName());
+            final OBCriteria<T> obc = OBDal.getInstance().createCriteria(
+                    entity.getName());
+            obc.add(Expression.gt(Organization.PROPERTY_UPDATED, afterDate));
+            // todo: count is slower than exists, is exists possible?
+            if (obc.count() > 0) {
+                return true;
+            }
+        }
+        return false;
     }
 }