You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/09/29 17:38:48 UTC

[02/15] cayenne git commit: CAY-2116 Split schema synchronization code in a separate module

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensReversTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensReversTest.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensReversTest.java
deleted file mode 100644
index e13531e..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensReversTest.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge;
-
-import org.apache.cayenne.dba.hsqldb.HSQLMergerFactory;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.junit.Assert;
-import org.junit.Test;
-
-import java.util.Collections;
-
-import static org.apache.cayenne.merge.builders.ObjectMother.dbAttr;
-import static org.apache.cayenne.merge.builders.ObjectMother.dbEntity;
-
-/**
- * @since 4.0.
- */
-public class TokensReversTest {
-
-    @Test
-    public void testReverses() {
-        DbAttribute attr = dbAttr().build();
-        DbEntity entity = dbEntity().attributes(attr).build();
-        DbRelationship rel = new DbRelationship("rel");
-        rel.setSourceEntity(entity);
-        rel.addJoin(new DbJoin(rel, attr.getName(), "dontKnow"));
-
-        test(factory().createAddColumnToDb(entity, attr));
-        test(factory().createAddColumnToModel(entity, attr));
-        test(factory().createDropColumnToDb(entity, attr));
-        test(factory().createDropColumnToModel(entity, attr));
-
-        test(factory().createAddRelationshipToDb(entity, rel));
-        test(factory().createAddRelationshipToModel(entity, rel));
-        test(factory().createDropRelationshipToDb(entity, rel));
-        test(factory().createDropRelationshipToModel(entity, rel));
-
-        test(factory().createCreateTableToDb(entity));
-        test(factory().createCreateTableToModel(entity));
-        test(factory().createDropTableToDb(entity));
-        test(factory().createDropTableToModel(entity));
-
-        test(factory().createSetAllowNullToDb(entity, attr));
-        test(factory().createSetAllowNullToModel(entity, attr));
-        test(factory().createSetNotNullToDb(entity, attr));
-        test(factory().createSetNotNullToModel(entity, attr));
-
-        DbAttribute attr2 = dbAttr().build();
-        test(factory().createSetColumnTypeToDb(entity, attr, attr2));
-        test(factory().createSetColumnTypeToModel(entity, attr, attr2));
-
-        test(factory().createSetPrimaryKeyToDb(entity, Collections.singleton(attr), Collections.singleton(attr2), "PK"));
-        test(factory().createSetPrimaryKeyToModel(entity, Collections.singleton(attr), Collections.singleton(attr2), "PK"));
-
-        test(factory().createSetValueForNullToDb(entity, attr, new DefaultValueForNullProvider()));
-    }
-
-    private void test(MergerToken token1) {
-        MergerToken token2 = token1.createReverse(factory()).createReverse(factory());
-
-        Assert.assertEquals(token1.getTokenName(), token2.getTokenName());
-        Assert.assertEquals(token1.getTokenValue(), token2.getTokenValue());
-        Assert.assertEquals(token1.getDirection(), token2.getDirection());
-    }
-
-    private MergerFactory factory() {
-        return new HSQLMergerFactory();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensToModelExecution.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensToModelExecution.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensToModelExecution.java
deleted file mode 100644
index 094914b..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/TokensToModelExecution.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge;
-
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.junit.Test;
-
-import static org.apache.cayenne.merge.builders.ObjectMother.dataMap;
-import static org.apache.cayenne.merge.builders.ObjectMother.dbAttr;
-import static org.apache.cayenne.merge.builders.ObjectMother.dbEntity;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-/**
- * @since 4.0.
- */
-public class TokensToModelExecution {
-
-    @Test
-    public void testCreateAndDropTable() throws Exception {
-        DbEntity entity = dbEntity().build();
-
-        DataMap dataMap = dataMap().build();
-        assertTrue(dataMap.getDbEntityMap().isEmpty());
-        assertTrue(dataMap.getObjEntityMap().isEmpty());
-
-        MergerContext context = MergerContext.builder(dataMap).dataNode(new DataNode()).build();
-        factory().createCreateTableToModel(entity).execute(context);
-
-        assertEquals(1, dataMap.getDbEntityMap().size());
-        assertEquals(1, dataMap.getObjEntities().size());
-        assertEquals(entity, dataMap.getDbEntity(entity.getName()));
-
-        factory().createDropTableToModel(entity).execute(context);
-        assertTrue(dataMap.getDbEntityMap().isEmpty());
-        assertTrue(dataMap.getObjEntityMap().isEmpty());
-    }
-
-    @Test
-    public void testCreateAndDropColumn() throws Exception {
-        DbAttribute attr = dbAttr("attr").build();
-        DbEntity entity = dbEntity().build();
-
-        DataMap dataMap = dataMap().with(entity).build();
-        assertEquals(1, dataMap.getDbEntityMap().size());
-        assertTrue(dataMap.getObjEntityMap().isEmpty());
-
-        MergerContext context = MergerContext.builder(dataMap).dataNode(new DataNode()).build();
-        factory().createAddColumnToModel(entity, attr).execute(context);
-
-        assertEquals(1, dataMap.getDbEntityMap().size());
-        assertEquals(1, entity.getAttributes().size());
-        assertEquals(attr, entity.getAttribute(attr.getName()));
-
-        factory().createDropColumnToModel(entity, attr).execute(context);
-        assertEquals(1, dataMap.getDbEntityMap().size());
-        assertTrue(entity.getAttributes().isEmpty());
-        assertTrue(dataMap.getObjEntityMap().isEmpty());
-    }
-
-    private MergerFactory factory() {
-        return new MergerFactory();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/ValueForNullIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/ValueForNullIT.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/ValueForNullIT.java
deleted file mode 100644
index fb43eb3..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/ValueForNullIT.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.sql.Types;
-import java.util.List;
-
-import junit.framework.AssertionFailedError;
-
-import org.apache.cayenne.DataObject;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.access.DataContext;
-import org.apache.cayenne.access.jdbc.SQLParameterBinding;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.query.SelectQuery;
-import org.junit.Test;
-
-public class ValueForNullIT extends MergeCase {
-
-	private static final String DEFAULT_VALUE_STRING = "DEFSTRING";
-
-	@Inject
-	private DataContext context;
-
-	@Test
-	public void test() throws Exception {
-		DbEntity dbEntity = map.getDbEntity("PAINTING");
-		assertNotNull(dbEntity);
-		ObjEntity objEntity = map.getObjEntity("Painting");
-		assertNotNull(objEntity);
-
-		// insert some rows before adding "not null" column
-		final int nrows = 10;
-		for (int i = 0; i < nrows; i++) {
-			DataObject o = (DataObject) context.newObject("Painting");
-			o.writeProperty("paintingTitle", "ptitle" + i);
-		}
-		context.commitChanges();
-
-		// create and add new column to model and db
-		DbAttribute column = new DbAttribute("NEWCOL2", Types.VARCHAR, dbEntity);
-
-		column.setMandatory(false);
-		column.setMaxLength(10);
-		dbEntity.addAttribute(column);
-		assertTrue(dbEntity.getAttributes().contains(column));
-		assertEquals(column, dbEntity.getAttribute(column.getName()));
-		assertTokensAndExecute(1, 0);
-
-		// need obj attr to be able to query
-		ObjAttribute objAttr = new ObjAttribute("newcol2");
-		objAttr.setDbAttributePath(column.getName());
-		objEntity.addAttribute(objAttr);
-
-		// check that is was merged
-		assertTokensAndExecute(0, 0);
-
-		// set not null
-		column.setMandatory(true);
-
-		// merge to db
-		assertTokensAndExecute(2, 0);
-
-		// check that is was merged
-		assertTokensAndExecute(0, 0);
-
-		// check values for null
-		Expression qual = ExpressionFactory.matchExp(objAttr.getName(), DEFAULT_VALUE_STRING);
-		SelectQuery query = new SelectQuery("Painting", qual);
-		List<Persistent> rows = context.performQuery(query);
-		assertEquals(nrows, rows.size());
-
-		// clean up
-		dbEntity.removeAttribute(column.getName());
-		assertTokensAndExecute(1, 0);
-		assertTokensAndExecute(0, 0);
-	}
-
-	@Override
-	protected DbMerger createMerger(MergerFactory mergerFactory, final ValueForNullProvider valueForNullProvider) {
-		return super.createMerger(mergerFactory, new DefaultValueForNullProvider() {
-
-			@Override
-			protected SQLParameterBinding get(DbEntity entity, DbAttribute column) {
-				int type = column.getType();
-				switch (type) {
-				case Types.VARCHAR:
-					return new SQLParameterBinding(DEFAULT_VALUE_STRING, type, -1);
-				default:
-					throw new AssertionFailedError("should not get here");
-				}
-			}
-
-			@Override
-			public boolean hasValueFor(DbEntity entity, DbAttribute column) {
-				return true;
-			}
-
-		});
-	}
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/Builder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/Builder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/Builder.java
deleted file mode 100644
index fd379c7..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/Builder.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-/**
- * Base interface for all domain builders
- *
- * @since 4.0.
- */
-public interface Builder<T> {
-
-    /**
-     * Build valid object. If some required data omitted it will be filled with random data.
-     * */
-    T build();
-
-    /**
-     * Build valid object and add some optional fields randomly.
-     * */
-    T random();
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DataMapBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DataMapBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DataMapBuilder.java
deleted file mode 100644
index 662ba2a..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DataMapBuilder.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.EntityResolver;
-import org.apache.cayenne.map.ObjEntity;
-
-import java.util.Collections;
-
-/**
- * @since 4.0.
- */
-public class DataMapBuilder extends DefaultBuilder<DataMap> {
-
-    public DataMapBuilder() {
-        this(new DataMap());
-    }
-
-    public DataMapBuilder(DataMap dataMap) {
-        super(dataMap);
-    }
-
-    public DataMapBuilder with(DbEntity ... entities) {
-        for (DbEntity entity : entities) {
-            obj.addDbEntity(entity);
-        }
-
-        return this;
-    }
-
-    public DataMapBuilder with(DbEntityBuilder ... entities) {
-        for (DbEntityBuilder entity : entities) {
-            obj.addDbEntity(entity.build());
-        }
-
-        return this;
-    }
-
-    public DataMapBuilder withDbEntities(int count) {
-        for (int i = 0; i < count; i++) {
-            obj.addDbEntity(ObjectMother.dbEntity().random());
-        }
-
-        return this;
-    }
-
-    public DataMapBuilder with(ObjEntity... entities) {
-        for (ObjEntity entity : entities) {
-            obj.addObjEntity(entity);
-        }
-
-        return this;
-    }
-
-    public DataMapBuilder with(ObjEntityBuilder ... entities) {
-        for (ObjEntityBuilder entity : entities) {
-            obj.addObjEntity(entity.build());
-        }
-
-        return this;
-    }
-
-    public DataMapBuilder withObjEntities(int count) {
-        for (int i = 0; i < count; i++) {
-            obj.addObjEntity(ObjectMother.objEntity().random());
-        }
-
-        return this;
-    }
-
-    public DataMapBuilder join(String from, String to) {
-        return join(null, from, to);
-    }
-
-    public DataMapBuilder join(String name, String from, String to) {
-        String[] fromSplit = from.split("\\.");
-        DbEntity fromEntity = obj.getDbEntity(fromSplit[0]);
-        if (fromEntity == null) {
-            throw new IllegalArgumentException("Entity '" + fromSplit[0] + "' is undefined");
-        }
-
-        String[] toSplit = to.split("\\.");
-
-        fromEntity.addRelationship(new DbRelationshipBuilder(name)
-                .from(fromEntity, fromSplit[1])
-                .to(toSplit[0], toSplit[1])
-
-                .build());
-
-        return this;
-    }
-
-    public DataMap build() {
-        if (obj.getNamespace() == null) {
-            obj.setNamespace(new EntityResolver(Collections.singleton(obj)));
-        }
-
-        return obj;
-    }
-
-    @Override
-    public DataMap random() {
-        if (dataFactory.chance(90)) {
-            withDbEntities(dataFactory.getNumberUpTo(10));
-        }
-
-
-        return build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbAttributeBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbAttributeBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbAttributeBuilder.java
deleted file mode 100644
index 1682b50..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbAttributeBuilder.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.datafactory.DictionaryValueProvider;
-import org.apache.cayenne.datafactory.ValueProvider;
-import org.apache.cayenne.dba.TypesMapping;
-import org.apache.cayenne.map.DbAttribute;
-
-import static org.apache.commons.lang.StringUtils.isEmpty;
-
-/**
- * @since 4.0.
- */
-public class DbAttributeBuilder extends DefaultBuilder<DbAttribute> {
-
-    private static final ValueProvider<String> TYPES_RANDOM = new DictionaryValueProvider<String>(ValueProvider.RANDOM) {
-        @Override
-        protected String[] values() {
-            return TypesMapping.getDatabaseTypes();
-        }
-    };
-
-    public DbAttributeBuilder() {
-        super(new DbAttribute());
-    }
-
-    public DbAttributeBuilder name() {
-        return name(getRandomJavaName());
-    }
-
-    public DbAttributeBuilder name(String name) {
-        obj.setName(name);
-
-        return this;
-    }
-
-    public DbAttributeBuilder type() {
-        return type(TYPES_RANDOM.randomValue());
-    }
-
-    public DbAttributeBuilder type(String item) {
-        obj.setType(TypesMapping.getSqlTypeByName(item));
-
-        return this;
-    }
-
-    public DbAttributeBuilder typeInt() {
-        return type(TypesMapping.SQL_INTEGER);
-    }
-
-    public DbAttributeBuilder typeBigInt() {
-        return type(TypesMapping.SQL_BIGINT);
-    }
-
-    public DbAttributeBuilder typeVarchar(int length) {
-        type(TypesMapping.SQL_VARCHAR);
-        length(length);
-
-        return this;
-    }
-
-    private DbAttributeBuilder length(int length) {
-        obj.setMaxLength(length);
-
-        return this;
-    }
-
-    public DbAttributeBuilder primaryKey() {
-        obj.setPrimaryKey(true);
-
-        return this;
-    }
-
-    public DbAttributeBuilder mandatory() {
-        obj.setMandatory(true);
-
-        return this;
-    }
-
-    @Override
-    public DbAttribute build() {
-        if (isEmpty(obj.getName())) {
-            name();
-        }
-
-        if (obj.getType() == TypesMapping.NOT_DEFINED) {
-            type();
-        }
-
-        return obj;
-    }
-
-    @Override
-    public DbAttribute random() {
-        return build();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbEntityBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbEntityBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbEntityBuilder.java
deleted file mode 100644
index 9cbd456..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbEntityBuilder.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.commons.lang.StringUtils;
-
-/**
- * @since 4.0.
- */
-public class DbEntityBuilder extends DefaultBuilder<DbEntity> {
-
-    public DbEntityBuilder() {
-        super(new DbEntity());
-    }
-
-    public DbEntityBuilder name() {
-        return name(getRandomJavaName());
-    }
-
-    public DbEntityBuilder name(String name) {
-        obj.setName(name);
-
-        return this;
-    }
-
-    public DbEntityBuilder attributes(DbAttribute ... attributes) {
-        for (DbAttribute attribute : attributes) {
-            obj.addAttribute(attribute);
-        }
-
-        return this;
-    }
-
-    public DbEntityBuilder attributes(DbAttributeBuilder ... attributes) {
-        for (DbAttributeBuilder attribute : attributes) {
-            obj.addAttribute(attribute.build());
-        }
-
-        return this;
-    }
-
-    public DbEntityBuilder attributes(int numberUpTo) {
-        for (int i = 0; i < numberUpTo; i++) {
-            try {
-                obj.addAttribute(new DbAttributeBuilder().random());
-            } catch (IllegalArgumentException e) {
-                i--; // try again
-            }
-        }
-
-        return this;
-    }
-
-
-    @Override
-    public DbEntity build() {
-        if (obj.getName() == null) {
-            obj.setName(StringUtils.capitalize(getRandomJavaName()));
-        }
-
-        return obj;
-    }
-
-    @Override
-    public DbEntity random() {
-        if (dataFactory.chance(99)) {
-            attributes(dataFactory.getNumberUpTo(20));
-        }
-
-        return build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbRelationshipBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbRelationshipBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbRelationshipBuilder.java
deleted file mode 100644
index 2bf5dba..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DbRelationshipBuilder.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-
-/**
- * @since 4.0.
- */
-public class DbRelationshipBuilder extends DefaultBuilder<DbRelationship> {
-
-    private String[] from;
-    private String[] to;
-
-    public DbRelationshipBuilder() {
-        super(new DbRelationship());
-    }
-
-    public DbRelationshipBuilder(String name) {
-        super(new DbRelationship(name));
-    }
-
-    public DbRelationshipBuilder(DbRelationship obj) {
-        super(obj);
-    }
-
-    public DbRelationshipBuilder name() {
-        return name(getRandomJavaName());
-    }
-
-    public DbRelationshipBuilder name(String name) {
-        obj.setName(name);
-
-        return this;
-    }
-
-    public DbRelationshipBuilder from(DbEntity entity, String ... columns) {
-        obj.setSourceEntity(entity);
-        this.from = columns;
-
-        return this;
-    }
-
-    public DbRelationshipBuilder to(String entityName, String ... columns) {
-        obj.setTargetEntityName(entityName);
-        this.to = columns;
-
-        return this;
-    }
-
-    @Override
-    public DbRelationship build() {
-        if (obj.getName() == null) {
-            name();
-        }
-
-        if (from.length != to.length) {
-            throw new IllegalStateException("from and to columns name size mismatch");
-        }
-
-        for (int i = 0; i < from.length; i++) {
-            obj.addJoin(new DbJoin(obj, from[i], to[i]));
-        }
-
-        return obj;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DefaultBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DefaultBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DefaultBuilder.java
deleted file mode 100644
index 5e9cea2..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/DefaultBuilder.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.datafactory.DataFactory;
-import org.apache.commons.lang.StringUtils;
-
-/**
- * @since 4.0.
- */
-public abstract class DefaultBuilder<T> implements Builder<T> {
-
-    protected final DataFactory dataFactory;
-    protected final T obj;
-
-
-    protected DefaultBuilder(T obj) {
-        this.dataFactory = new DataFactory();
-        this.obj = obj;
-    }
-
-    public String getRandomJavaName() {
-        int count = dataFactory.getNumberBetween(1, 5);
-        StringBuilder res = new StringBuilder();
-        for (int i = 0; i < count; i++) {
-            res.append(StringUtils.capitalize(dataFactory.getRandomWord()));
-        }
-
-        return StringUtils.uncapitalize(res.toString());
-    }
-
-    @Override
-    public T build() {
-        return obj;
-    }
-
-    @Override
-    public T random() {
-        return build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjAttributeBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjAttributeBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjAttributeBuilder.java
deleted file mode 100644
index 6a74936..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjAttributeBuilder.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.map.ObjAttribute;
-
-/**
- * @since 4.0.
- */
-public class ObjAttributeBuilder extends DefaultBuilder<ObjAttribute> {
-
-    public ObjAttributeBuilder() {
-        super(new ObjAttribute());
-    }
-
-    public ObjAttributeBuilder name() {
-        return name(getRandomJavaName());
-    }
-
-    public ObjAttributeBuilder name(String name) {
-        obj.setName(name);
-
-        return this;
-    }
-
-    public ObjAttributeBuilder type(Class type) {
-        obj.setType(type.getCanonicalName());
-
-        return this;
-    }
-
-    public ObjAttributeBuilder dbPath(String path) {
-        obj.setDbAttributePath(path);
-
-        return this;
-    }
-
-    @Override
-    public ObjAttribute build() {
-        if (obj.getName() == null) {
-            name();
-        }
-
-        return obj;
-    }
-
-    @Override
-    public ObjAttribute random() {
-        return build();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjEntityBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjEntityBuilder.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjEntityBuilder.java
deleted file mode 100644
index dc78b29..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjEntityBuilder.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.map.ObjAttribute;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.commons.lang.StringUtils;
-
-/**
- * @since 4.0.
- */
-public class ObjEntityBuilder extends DefaultBuilder<ObjEntity> {
-
-    public ObjEntityBuilder() {
-        super(new ObjEntity());
-    }
-
-    public ObjEntityBuilder name() {
-        return name(getRandomJavaName());
-    }
-
-    public ObjEntityBuilder name(String name) {
-        obj.setName(name);
-
-        return this;
-    }
-
-    public ObjEntityBuilder attributes(ObjAttribute... attributes) {
-        for (ObjAttribute attribute : attributes) {
-            obj.addAttribute(attribute);
-        }
-
-        return this;
-    }
-
-    public ObjEntityBuilder attributes(ObjAttributeBuilder ... attributes) {
-        for (ObjAttributeBuilder attribute : attributes) {
-            obj.addAttribute(attribute.build());
-        }
-
-        return this;
-    }
-
-    public ObjEntityBuilder attributes(int numberUpTo) {
-        for (int i = 0; i < numberUpTo; i++) {
-            obj.addAttribute(new ObjAttributeBuilder().random());
-        }
-
-        return this;
-    }
-
-
-    @Override
-    public ObjEntity build() {
-        if (obj.getName() == null) {
-            obj.setName(StringUtils.capitalize(getRandomJavaName()));
-        }
-
-        return obj;
-    }
-
-    @Override
-    public ObjEntity random() {
-        if (dataFactory.chance(99)) {
-            attributes(dataFactory.getNumberUpTo(20));
-        }
-
-        return build();
-    }
-
-    public ObjEntityBuilder clazz(String s) {
-        obj.setClassName(s);
-
-        return this;
-    }
-
-    public ObjEntityBuilder dbEntity(String table) {
-        obj.setDbEntityName(table);
-
-        return this;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjectMother.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjectMother.java b/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjectMother.java
deleted file mode 100644
index 76ed761..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/merge/builders/ObjectMother.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.merge.builders;
-
-import org.apache.cayenne.map.DataMap;
-
-/**
- * Factory for test data see pattern definition:
- * http://martinfowler.com/bliki/ObjectMother.html
- *
- * @since 4.0.
- */
-public class ObjectMother {
-
-    public static DataMapBuilder dataMap() {
-        return new DataMapBuilder();
-    }
-
-    public static DataMapBuilder dataMap(DataMap dataMap) {
-        return new DataMapBuilder(dataMap);
-    }
-
-    public static DbEntityBuilder dbEntity() {
-        return new DbEntityBuilder();
-    }
-
-    public static DbEntityBuilder dbEntity(String name) {
-        return new DbEntityBuilder().name(name);
-    }
-
-    public static ObjEntityBuilder objEntity() {
-        return new ObjEntityBuilder();
-    }
-
-    public static ObjEntityBuilder objEntity(String packageName, String className, String table) {
-        return new ObjEntityBuilder()
-                .name(className)
-                .clazz(packageName + "." + className)
-                .dbEntity(table);
-    }
-
-    public static ObjAttributeBuilder objAttr(String name) {
-        return new ObjAttributeBuilder().name(name);
-    }
-
-    public static DbAttributeBuilder dbAttr(String name) {
-        return dbAttr().name(name);
-    }
-
-    public static DbAttributeBuilder dbAttr() {
-        return new DbAttributeBuilder();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerRuntimeProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerRuntimeProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerRuntimeProvider.java
index 29820e0..79c02cf 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerRuntimeProvider.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerRuntimeProvider.java
@@ -29,6 +29,9 @@ import org.apache.cayenne.di.Module;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.unit.UnitDbAdapter;
 
+import java.util.Collection;
+import java.util.Collections;
+
 public class ServerRuntimeProvider implements Provider<ServerRuntime> {
 
     private ServerCaseProperties properties;
@@ -48,6 +51,7 @@ public class ServerRuntimeProvider implements Provider<ServerRuntime> {
         this.unitDbAdapter = unitDbAdapter;
     }
 
+    @Override
     public ServerRuntime get() throws ConfigurationException {
 
         String configurationLocation = properties.getConfigurationLocation();
@@ -56,11 +60,18 @@ public class ServerRuntimeProvider implements Provider<ServerRuntime> {
                     + "annotate your test case with @UseServerRuntime");
         }
 
-        return new ServerRuntime(configurationLocation, new ServerExtraModule());
+        Collection<? extends Module> modules = getExtraModules();
+
+        return new ServerRuntime(configurationLocation, modules.toArray(new Module[modules.size()]));
+    }
+
+    protected Collection<? extends Module> getExtraModules() {
+        return Collections.singleton(new ServerExtraModule());
     }
 
     class ServerExtraModule implements Module {
 
+        @Override
         public void configure(Binder binder) {
 
             // these are the objects overriding standard ServerModule definitions or

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/java/org/apache/cayenne/util/EntityMergeSupportIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/util/EntityMergeSupportIT.java b/cayenne-server/src/test/java/org/apache/cayenne/util/EntityMergeSupportIT.java
deleted file mode 100644
index e3f1bc3..0000000
--- a/cayenne-server/src/test/java/org/apache/cayenne/util/EntityMergeSupportIT.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*****************************************************************
- *   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.
- ****************************************************************/
-package org.apache.cayenne.util;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
-import java.sql.Types;
-import java.util.Arrays;
-
-import org.apache.cayenne.map.DbAttribute;
-import org.apache.cayenne.map.DbEntity;
-import org.apache.cayenne.map.DbJoin;
-import org.apache.cayenne.map.DbRelationship;
-import org.apache.cayenne.map.DeleteRule;
-import org.apache.cayenne.map.ObjEntity;
-import org.apache.cayenne.merge.MergeCase;
-import org.junit.Test;
-
-public class EntityMergeSupportIT extends MergeCase {
-
-	@Test
-	public void testMerging() {
-		DbEntity dbEntity1 = new DbEntity("NEW_TABLE");
-
-		DbAttribute e1col1 = new DbAttribute("ID", Types.INTEGER, dbEntity1);
-		e1col1.setMandatory(true);
-		e1col1.setPrimaryKey(true);
-		dbEntity1.addAttribute(e1col1);
-
-		DbAttribute e1col2 = new DbAttribute("NAME", Types.VARCHAR, dbEntity1);
-		e1col2.setMaxLength(10);
-		e1col2.setMandatory(false);
-		dbEntity1.addAttribute(e1col2);
-
-		map.addDbEntity(dbEntity1);
-
-		DbEntity dbEntity2 = new DbEntity("NEW_TABLE2");
-		DbAttribute e2col1 = new DbAttribute("ID", Types.INTEGER, dbEntity2);
-		e2col1.setMandatory(true);
-		e2col1.setPrimaryKey(true);
-		dbEntity2.addAttribute(e2col1);
-		DbAttribute e2col2 = new DbAttribute("FK", Types.INTEGER, dbEntity2);
-		dbEntity2.addAttribute(e2col2);
-
-		map.addDbEntity(dbEntity2);
-
-		// create db relationships
-		DbRelationship rel1To2 = new DbRelationship("rel1To2");
-		rel1To2.setSourceEntity(dbEntity1);
-		rel1To2.setTargetEntityName(dbEntity2);
-		rel1To2.setToMany(true);
-		rel1To2.addJoin(new DbJoin(rel1To2, e1col1.getName(), e2col2.getName()));
-		dbEntity1.addRelationship(rel1To2);
-		DbRelationship rel2To1 = new DbRelationship("rel2To1");
-		rel2To1.setSourceEntity(dbEntity2);
-		rel2To1.setTargetEntityName(dbEntity1);
-		rel2To1.setToMany(false);
-		rel2To1.addJoin(new DbJoin(rel2To1, e2col2.getName(), e1col1.getName()));
-		dbEntity2.addRelationship(rel2To1);
-		assertSame(rel1To2, rel2To1.getReverseRelationship());
-		assertSame(rel2To1, rel1To2.getReverseRelationship());
-
-		ObjEntity objEntity1 = new ObjEntity("NewTable");
-		objEntity1.setDbEntity(dbEntity1);
-		map.addObjEntity(objEntity1);
-
-		ObjEntity objEntity2 = new ObjEntity("NewTable2");
-		objEntity2.setDbEntity(dbEntity2);
-		map.addObjEntity(objEntity2);
-
-		assertTrue(new EntityMergeSupport(map).synchronizeWithDbEntities(Arrays.asList(objEntity1, objEntity2)));
-		assertNotNull(objEntity1.getAttribute("name"));
-		assertNotNull(objEntity1.getRelationship("rel1To2"));
-		assertNotNull(objEntity2.getRelationship("rel2To1"));
-
-		assertEquals(objEntity1.getRelationship("rel1To2").getDeleteRule(), DeleteRule.DEFAULT_DELETE_RULE_TO_MANY);
-		assertEquals(objEntity2.getRelationship("rel2To1").getDeleteRule(), DeleteRule.DEFAULT_DELETE_RULE_TO_ONE);
-
-		map.removeObjEntity(objEntity2.getName());
-		map.removeObjEntity(objEntity1.getName());
-		map.removeDbEntity(dbEntity2.getName());
-		map.removeDbEntity(dbEntity1.getName());
-	}
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/cayenne-relationship-optimisation.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/cayenne-relationship-optimisation.xml b/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/cayenne-relationship-optimisation.xml
deleted file mode 100644
index d4fea49..0000000
--- a/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/cayenne-relationship-optimisation.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<domain project-version="6">
-	<map name="relationship-optimisation"/>
-</domain>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/relationship-optimisation.map.xml
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/relationship-optimisation.map.xml b/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/relationship-optimisation.map.xml
deleted file mode 100644
index e68645f..0000000
--- a/cayenne-server/src/test/resources/org/apache/cayenne/access/loader/relationship-optimisation.map.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap"
-	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="http://cayenne.apache.org/schema/3.0/modelMap http://cayenne.apache.org/schema/3.0/modelMap.xsd"
-	 project-version="6">
-	<property name="defaultPackage" value="com.objectstyle"/>
-	<db-entity name="table1" catalog="many_to_many_test">
-		<db-attribute name="id1" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="10"/>
-		<db-attribute name="table1col" type="VARCHAR" length="45"/>
-	</db-entity>
-	<db-entity name="table1_table2" catalog="many_to_many_test">
-		<db-attribute name="fk1" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="10"/>
-		<db-attribute name="fk2" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="10"/>
-	</db-entity>
-	<db-entity name="table2" catalog="many_to_many_test">
-		<db-attribute name="id2" type="INTEGER" isPrimaryKey="true" isMandatory="true" length="10"/>
-		<db-attribute name="table2col" type="VARCHAR" length="45"/>
-	</db-entity>
-	<obj-entity name="Table1" className="com.objectstyle.Table1" dbEntityName="table1">
-		<obj-attribute name="table1col" type="java.lang.String" db-attribute-path="table1col"/>
-	</obj-entity>
-	<obj-entity name="Table1Table2" className="com.objectstyle.Table1Table2" dbEntityName="table1_table2">
-	</obj-entity>
-	<obj-entity name="Table2" className="com.objectstyle.Table2" dbEntityName="table2">
-		<obj-attribute name="table2col" type="java.lang.String" db-attribute-path="table2col"/>
-	</obj-entity>
-	<db-relationship name="table1Table2Array" source="table1" target="table1_table2" toDependentPK="true" toMany="true">
-		<db-attribute-pair source="id1" target="fk1"/>
-	</db-relationship>
-	<db-relationship name="toTable1" source="table1_table2" target="table1" toMany="false">
-		<db-attribute-pair source="fk1" target="id1"/>
-	</db-relationship>
-	<db-relationship name="toTable2" source="table1_table2" target="table2" toMany="false">
-		<db-attribute-pair source="fk2" target="id2"/>
-	</db-relationship>
-	<db-relationship name="table1Table2Array" source="table2" target="table1_table2" toDependentPK="true" toMany="true">
-		<db-attribute-pair source="id2" target="fk2"/>
-	</db-relationship>
-	<obj-relationship name="table1Table2Array" source="Table1" target="Table1Table2" deleteRule="Deny" db-relationship-path="table1Table2Array"/>
-	<obj-relationship name="toTable1" source="Table1Table2" target="Table1" deleteRule="Nullify" db-relationship-path="toTable1"/>
-	<obj-relationship name="toTable2" source="Table1Table2" target="Table2" deleteRule="Nullify" db-relationship-path="toTable2"/>
-	<obj-relationship name="table1Table2Array" source="Table2" target="Table1Table2" deleteRule="Deny" db-relationship-path="table1Table2Array"/>
-</data-map>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-tools/pom.xml b/cayenne-tools/pom.xml
index 581c7df..15816c5 100644
--- a/cayenne-tools/pom.xml
+++ b/cayenne-tools/pom.xml
@@ -42,6 +42,13 @@
             <scope>test</scope>
             <type>test-jar</type>
         </dependency>
+        <dependency>
+            <groupId>org.apache.cayenne</groupId>
+            <artifactId>cayenne-dbsync</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+            <type>test-jar</type>
+        </dependency>
 
         <dependency>
 			<groupId>org.apache.cayenne.build-tools</groupId>
@@ -94,6 +101,13 @@
 			<version>${project.version}</version>
 		</dependency>
 
+        <dependency>
+            <groupId>org.apache.cayenne</groupId>
+            <artifactId>cayenne-dbsync</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+        </dependency>
+
 		<dependency>
 			<groupId>foundrylogic.vpp</groupId>
 			<artifactId>vpp</artifactId>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java b/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
index f7471a6..e8b6b76 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
@@ -18,18 +18,8 @@
  ****************************************************************/
 package org.apache.cayenne.gen;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.loader.NamePatternMatcher;
+import org.apache.cayenne.dbsync.reverse.NamePatternMatcher;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.Embeddable;
 import org.apache.cayenne.map.ObjEntity;
@@ -41,6 +31,16 @@ import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.runtime.RuntimeConstants;
 import org.apache.velocity.runtime.log.NullLogSystem;
 
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
 public class ClassGenerationAction {
 	static final String TEMPLATES_DIR_NAME = "templates/v1_2/";
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/AntDataPortDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/AntDataPortDelegate.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/AntDataPortDelegate.java
index 828d744..3e98829 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/AntDataPortDelegate.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/AntDataPortDelegate.java
@@ -19,19 +19,19 @@
 
 package org.apache.cayenne.tools;
 
-import java.util.Iterator;
-import java.util.List;
-import java.util.regex.Pattern;
-
 import org.apache.cayenne.access.DataPort;
 import org.apache.cayenne.access.DataPortDelegate;
-import org.apache.cayenne.access.loader.NamePatternMatcher;
+import org.apache.cayenne.dbsync.reverse.NamePatternMatcher;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.query.Query;
 import org.apache.tools.ant.Project;
 import org.apache.tools.ant.Task;
 
+import java.util.Iterator;
+import java.util.List;
+import java.util.regex.Pattern;
+
 /**
  * DataPortDelegate implementation that works in the context of Ant DataPortTask
  * task execution, performing entity filtering and logging functions.

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
index 49329a7..08a39df 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
@@ -18,16 +18,16 @@
  ****************************************************************/
 package org.apache.cayenne.tools;
 
+import org.apache.cayenne.dbsync.reverse.NameFilter;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.map.ObjEntity;
+
 import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 
-import org.apache.cayenne.access.loader.NameFilter;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.Embeddable;
-import org.apache.cayenne.map.ObjEntity;
-
 /**
  * Performs entity filtering to build a collection of entities that should be used in
  * class generation.

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
index 6ed29cb..6edcd6c 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
@@ -19,7 +19,7 @@
 package org.apache.cayenne.tools;
 
 import foundrylogic.vpp.VPPConfig;
-import org.apache.cayenne.access.loader.NamePatternMatcher;
+import org.apache.cayenne.dbsync.reverse.NamePatternMatcher;
 import org.apache.cayenne.gen.ArtifactsGenerationMode;
 import org.apache.cayenne.gen.ClassGenerationAction;
 import org.apache.cayenne.gen.ClientClassGenerationAction;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
index 5e0ab99..faa3653 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbGeneratorTask.java
@@ -19,12 +19,10 @@
 
 package org.apache.cayenne.tools;
 
-import java.sql.Driver;
-import java.util.Collections;
-
 import org.apache.cayenne.access.DbGenerator;
 import org.apache.cayenne.datasource.DriverDataSource;
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.CayenneDbSyncModule;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.log.NoopJdbcEventLogger;
@@ -36,6 +34,9 @@ import org.apache.commons.logging.Log;
 import org.apache.tools.ant.BuildException;
 import org.apache.tools.ant.Project;
 
+import java.sql.Driver;
+import java.util.Collections;
+
 /**
  * An Ant Task that is a frontend to Cayenne DbGenerator allowing schema
  * generation from DataMap using Ant.
@@ -68,7 +69,7 @@ public class DbGeneratorTask extends CayenneTask {
 		validateAttributes();
 
 		ClassLoader loader = null;
-		Injector injector = DIBootstrap.createInjector(new ToolsModule(logger));
+		Injector injector = DIBootstrap.createInjector(new CayenneDbSyncModule(), new ToolsModule(logger));
 		try {
 			loader = Thread.currentThread().getContextClassLoader();
 			Thread.currentThread().setContextClassLoader(DbGeneratorTask.class.getClassLoader());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbImporterTask.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbImporterTask.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbImporterTask.java
index e4fa545..f1797f1 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbImporterTask.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/DbImporterTask.java
@@ -18,7 +18,6 @@
  ****************************************************************/
 package org.apache.cayenne.tools;
 
-import org.apache.cayenne.access.loader.filters.LegacyFilterConfigBridge;
 import org.apache.cayenne.configuration.ConfigurationNameMapper;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.configuration.XMLDataMapLoader;
@@ -32,12 +31,14 @@ import org.apache.cayenne.dbimport.DefaultReverseEngineeringLoader;
 import org.apache.cayenne.dbimport.ExcludeColumn;
 import org.apache.cayenne.dbimport.ExcludeProcedure;
 import org.apache.cayenne.dbimport.ExcludeTable;
-import org.apache.cayenne.dbimport.FiltersConfigBuilder;
 import org.apache.cayenne.dbimport.IncludeColumn;
 import org.apache.cayenne.dbimport.IncludeProcedure;
 import org.apache.cayenne.dbimport.IncludeTable;
 import org.apache.cayenne.dbimport.ReverseEngineering;
 import org.apache.cayenne.dbimport.Schema;
+import org.apache.cayenne.dbsync.CayenneDbSyncModule;
+import org.apache.cayenne.dbsync.reverse.FiltersConfigBuilder;
+import org.apache.cayenne.dbsync.reverse.filters.LegacyFilterConfigBridge;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.map.DataMap;
@@ -91,7 +92,7 @@ public class DbImporterTask extends Task {
         config.setTableTypes(reverseEngineering.getTableTypes());
 
         if (isReverseEngineeringDefined) {
-            Injector injector = DIBootstrap.createInjector(new ToolsModule(logger), new DbImportModule());
+            Injector injector = DIBootstrap.createInjector(new CayenneDbSyncModule(), new ToolsModule(logger), new DbImportModule());
 
             validateDbImportConfiguration(config, injector);
 
@@ -120,7 +121,7 @@ public class DbImporterTask extends Task {
                     XMLDataMapLoader xmlDataMapLoader = new XMLDataMapLoader();
                     DataMap dataMap = xmlDataMapLoader.load(resource);
                     if (dataMap.getReverseEngineering() != null) {
-                        Injector injector = DIBootstrap.createInjector(new ToolsModule(logger), new DbImportModule());
+                        Injector injector = DIBootstrap.createInjector(new CayenneDbSyncModule(), new ToolsModule(logger), new DbImportModule());
                         try {
                             ConfigurationNameMapper nameMapper = injector.getInstance(ConfigurationNameMapper.class);
                             String reverseEngineeringLocation = nameMapper.configurationLocation(ReverseEngineering.class, dataMap.getReverseEngineering().getName());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
index 0914fb5..e69905a 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportConfiguration.java
@@ -19,28 +19,28 @@
 package org.apache.cayenne.tools.dbimport;
 
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.DbLoader;
-import org.apache.cayenne.access.loader.DbLoaderConfiguration;
-import org.apache.cayenne.access.DbLoaderDelegate;
-import org.apache.cayenne.access.loader.DefaultDbLoaderDelegate;
-import org.apache.cayenne.access.loader.LoggingDbLoaderDelegate;
-import org.apache.cayenne.access.loader.NameFilter;
-import org.apache.cayenne.access.loader.filters.CatalogFilter;
-import org.apache.cayenne.access.loader.filters.FiltersConfig;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.conn.DataSourceInfo;
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.merge.DbMergerConfig;
+import org.apache.cayenne.dbsync.merge.DefaultModelMergeDelegate;
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
+import org.apache.cayenne.dbsync.merge.ModelMergeDelegate;
+import org.apache.cayenne.dbsync.reverse.DbLoader;
+import org.apache.cayenne.dbsync.reverse.DbLoaderConfiguration;
+import org.apache.cayenne.dbsync.reverse.DbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.DefaultDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.LoggingDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.NameFilter;
+import org.apache.cayenne.dbsync.reverse.NamePatternMatcher;
+import org.apache.cayenne.dbsync.reverse.filters.CatalogFilter;
+import org.apache.cayenne.dbsync.reverse.filters.FiltersConfig;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.naming.LegacyNameGenerator;
 import org.apache.cayenne.map.naming.ObjectNameGenerator;
-import org.apache.cayenne.merge.DbMergerConfig;
-import org.apache.cayenne.merge.DefaultModelMergeDelegate;
-import org.apache.cayenne.merge.ModelMergeDelegate;
 import org.apache.cayenne.resource.URLResource;
-import org.apache.cayenne.access.loader.NamePatternMatcher;
-import org.apache.cayenne.util.EntityMergeSupport;
 import org.apache.commons.logging.Log;
 
 import java.io.File;
@@ -48,7 +48,6 @@ import java.io.IOException;
 import java.net.MalformedURLException;
 import java.sql.Connection;
 import java.util.Collections;
-import java.util.List;
 
 import static org.apache.commons.lang.StringUtils.isNotEmpty;
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportDbLoaderDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportDbLoaderDelegate.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportDbLoaderDelegate.java
index 7772b73..bc6abab 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportDbLoaderDelegate.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportDbLoaderDelegate.java
@@ -19,7 +19,7 @@
 
 package org.apache.cayenne.tools.dbimport;
 
-import org.apache.cayenne.access.loader.DefaultDbLoaderDelegate;
+import org.apache.cayenne.dbsync.reverse.DefaultDbLoaderDelegate;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.ObjEntity;
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportModule.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportModule.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportModule.java
index 18cc197..754071e 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportModule.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DbImportModule.java
@@ -29,8 +29,8 @@ import org.apache.cayenne.tools.configuration.ToolsModule;
 
 /**
  * A DI module that bootstraps {@link DbImportAction}. Should be used in
- * conjunction with {@link ToolsModule}.
- * 
+ * conjunction with {@link ToolsModule} and {@link org.apache.cayenne.dbsync.CayenneDbSyncModule}.
+ *
  * @since 4.0
  */
 public class DbImportModule implements Module {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
index c51300f..d344946 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/DefaultDbImportAction.java
@@ -18,26 +18,27 @@
  */
 package org.apache.cayenne.tools.dbimport;
 
-import org.apache.cayenne.access.DbLoader;
 import org.apache.cayenne.configuration.ConfigurationTree;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.configuration.server.DataSourceFactory;
 import org.apache.cayenne.configuration.server.DbAdapterFactory;
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.merge.AbstractToModelToken;
+import org.apache.cayenne.dbsync.merge.AddRelationshipToDb;
+import org.apache.cayenne.dbsync.merge.DbMerger;
+import org.apache.cayenne.dbsync.merge.MergerContext;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
+import org.apache.cayenne.dbsync.merge.MergerToken;
+import org.apache.cayenne.dbsync.merge.ModelMergeDelegate;
+import org.apache.cayenne.dbsync.merge.ProxyModelMergeDelegate;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactory;
+import org.apache.cayenne.dbsync.reverse.DbLoader;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.MapLoader;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.ObjRelationship;
-import org.apache.cayenne.merge.AbstractToModelToken;
-import org.apache.cayenne.merge.AddRelationshipToDb;
-import org.apache.cayenne.merge.DbMerger;
-import org.apache.cayenne.merge.MergerContext;
-import org.apache.cayenne.merge.MergerFactory;
-import org.apache.cayenne.merge.MergerToken;
-import org.apache.cayenne.merge.ModelMergeDelegate;
-import org.apache.cayenne.merge.ProxyModelMergeDelegate;
 import org.apache.cayenne.project.Project;
 import org.apache.cayenne.project.ProjectSaver;
 import org.apache.cayenne.resource.URLResource;
@@ -73,17 +74,20 @@ public class DefaultDbImportAction implements DbImportAction {
     private final DataSourceFactory dataSourceFactory;
     private final DbAdapterFactory adapterFactory;
     private final MapLoader mapLoader;
+    private final MergerTokenFactoryProvider mergerTokenFactoryProvider;
 
     public DefaultDbImportAction(@Inject Log logger,
                                  @Inject ProjectSaver projectSaver,
                                  @Inject DataSourceFactory dataSourceFactory,
                                  @Inject DbAdapterFactory adapterFactory,
-                                 @Inject MapLoader mapLoader) {
+                                 @Inject MapLoader mapLoader,
+                                 @Inject MergerTokenFactoryProvider mergerTokenFactoryProvider) {
         this.logger = logger;
         this.projectSaver = projectSaver;
         this.dataSourceFactory = dataSourceFactory;
         this.adapterFactory = adapterFactory;
         this.mapLoader = mapLoader;
+        this.mergerTokenFactoryProvider = mergerTokenFactoryProvider;
     }
 
     protected static List<MergerToken> sort(List<MergerToken> reverse) {
@@ -135,9 +139,9 @@ public class DefaultDbImportAction implements DbImportAction {
 
             saveLoaded(config.initializeDataMap(loadedFomDb));
         } else {
-            MergerFactory mergerFactory = adapter.mergerFactory();
+            MergerTokenFactory mergerTokenFactory = mergerTokenFactoryProvider.get(adapter);
 
-            List<MergerToken> mergeTokens = new DbMerger(mergerFactory)
+            List<MergerToken> mergeTokens = new DbMerger(mergerTokenFactory)
                     .createMergeTokens(existing, loadedFomDb, config.getDbLoaderConfig());
             if (mergeTokens.isEmpty()) {
                 logger.info("");
@@ -157,7 +161,7 @@ public class DefaultDbImportAction implements DbImportAction {
                     super.objEntityAdded(ent);
                 }
 
-            }, existing, log(sort(reverse(mergerFactory, mergeTokens))));
+            }, existing, log(sort(reverse(mergerTokenFactory, mergeTokens))));
 
             DbLoader.flattenManyToManyRelationships(executed, loadedObjEntities, config.getNameGenerator());
             relationshipsSanity(executed);
@@ -207,14 +211,14 @@ public class DefaultDbImportAction implements DbImportAction {
     }
 
     private List<MergerToken> reverse(
-            MergerFactory mergerFactory,
+            MergerTokenFactory mergerTokenFactory,
             Iterable<MergerToken> mergeTokens) throws IOException {
         List<MergerToken> tokens = new LinkedList<>();
         for (MergerToken token : mergeTokens) {
             if (token instanceof AbstractToModelToken) {
                 continue;
             }
-            tokens.add(token.createReverse(mergerFactory));
+            tokens.add(token.createReverse(mergerTokenFactory));
         }
         return tokens;
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/config/DefaultTypeMapperBuilder.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/config/DefaultTypeMapperBuilder.java b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/config/DefaultTypeMapperBuilder.java
index 52fc3d0..c8cab3a 100644
--- a/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/config/DefaultTypeMapperBuilder.java
+++ b/cayenne-tools/src/main/java/org/apache/cayenne/tools/dbimport/config/DefaultTypeMapperBuilder.java
@@ -18,9 +18,9 @@
  ****************************************************************/
 package org.apache.cayenne.tools.dbimport.config;
 
-import org.apache.cayenne.access.loader.mapper.DbType;
-import org.apache.cayenne.access.loader.mapper.DefaultJdbc2JavaTypeMapper;
-import org.apache.cayenne.access.loader.mapper.Jdbc2JavaTypeMapper;
+import org.apache.cayenne.dbsync.reverse.mapper.DbType;
+import org.apache.cayenne.dbsync.reverse.mapper.DefaultJdbc2JavaTypeMapper;
+import org.apache.cayenne.dbsync.reverse.mapper.Jdbc2JavaTypeMapper;
 import org.apache.commons.lang.ClassUtils;
 import org.apache.commons.logging.Log;
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/test/java/org/apache/cayenne/tools/NamePatternMatcherTest.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/NamePatternMatcherTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/NamePatternMatcherTest.java
index 161f44e..3482843 100644
--- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/NamePatternMatcherTest.java
+++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/NamePatternMatcherTest.java
@@ -19,12 +19,12 @@
 
 package org.apache.cayenne.tools;
 
-import static org.apache.cayenne.access.loader.NamePatternMatcher.replaceWildcardInStringWithString;
-import static org.junit.Assert.assertEquals;
-
-import org.apache.cayenne.access.loader.NamePatternMatcher;
+import org.apache.cayenne.dbsync.reverse.NamePatternMatcher;
 import org.junit.Test;
 
+import static org.apache.cayenne.dbsync.reverse.NamePatternMatcher.replaceWildcardInStringWithString;
+import static org.junit.Assert.assertEquals;
+
 public class NamePatternMatcherTest {
 
 	/**

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DbImportModuleTest.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DbImportModuleTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DbImportModuleTest.java
index 62b65ea..1e34d4e 100644
--- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DbImportModuleTest.java
+++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DbImportModuleTest.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.cayenne.tools.dbimport;
 
+import org.apache.cayenne.dbsync.CayenneDbSyncModule;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.tools.configuration.ToolsModule;
@@ -33,7 +34,7 @@ public class DbImportModuleTest {
     public void testModuleContents() {
 
         Log log = mock(Log.class);
-        Injector i = DIBootstrap.createInjector(new ToolsModule(log), new DbImportModule());
+        Injector i = DIBootstrap.createInjector(new CayenneDbSyncModule(), new ToolsModule(log), new DbImportModule());
         assertTrue(i.getInstance(DbImportAction.class) instanceof DbImportAction);
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
index 474b827..5a7c357 100644
--- a/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
+++ b/cayenne-tools/src/test/java/org/apache/cayenne/tools/dbimport/DefaultDbImportActionTest.java
@@ -19,26 +19,28 @@
 package org.apache.cayenne.tools.dbimport;
 
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.access.DbLoader;
-import org.apache.cayenne.access.DbLoaderDelegate;
-import org.apache.cayenne.access.loader.DbLoaderConfiguration;
 import org.apache.cayenne.configuration.DataNodeDescriptor;
 import org.apache.cayenne.configuration.server.DataSourceFactory;
 import org.apache.cayenne.configuration.server.DbAdapterFactory;
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.dbsync.CayenneDbSyncModule;
+import org.apache.cayenne.dbsync.merge.AddColumnToDb;
+import org.apache.cayenne.dbsync.merge.AddRelationshipToDb;
+import org.apache.cayenne.dbsync.merge.CreateTableToDb;
+import org.apache.cayenne.dbsync.merge.CreateTableToModel;
+import org.apache.cayenne.dbsync.merge.DefaultModelMergeDelegate;
+import org.apache.cayenne.dbsync.merge.factory.MergerTokenFactoryProvider;
+import org.apache.cayenne.dbsync.merge.MergerToken;
+import org.apache.cayenne.dbsync.merge.builders.DataMapBuilder;
+import org.apache.cayenne.dbsync.merge.factory.DefaultMergerTokenFactory;
+import org.apache.cayenne.dbsync.reverse.DbLoader;
+import org.apache.cayenne.dbsync.reverse.DbLoaderConfiguration;
+import org.apache.cayenne.dbsync.reverse.DbLoaderDelegate;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.MapLoader;
-import org.apache.cayenne.merge.AddColumnToDb;
-import org.apache.cayenne.merge.AddRelationshipToDb;
-import org.apache.cayenne.merge.CreateTableToDb;
-import org.apache.cayenne.merge.CreateTableToModel;
-import org.apache.cayenne.merge.DefaultModelMergeDelegate;
-import org.apache.cayenne.merge.MergerFactory;
-import org.apache.cayenne.merge.MergerToken;
-import org.apache.cayenne.merge.builders.DataMapBuilder;
 import org.apache.cayenne.project.FileProjectSaver;
 import org.apache.cayenne.project.Project;
 import org.apache.cayenne.resource.URLResource;
@@ -57,10 +59,10 @@ import java.util.LinkedList;
 import java.util.List;
 
 import static java.util.Arrays.asList;
-import static org.apache.cayenne.merge.builders.ObjectMother.dbAttr;
-import static org.apache.cayenne.merge.builders.ObjectMother.dbEntity;
-import static org.apache.cayenne.merge.builders.ObjectMother.objAttr;
-import static org.apache.cayenne.merge.builders.ObjectMother.objEntity;
+import static org.apache.cayenne.dbsync.merge.builders.ObjectMother.dbAttr;
+import static org.apache.cayenne.dbsync.merge.builders.ObjectMother.dbEntity;
+import static org.apache.cayenne.dbsync.merge.builders.ObjectMother.objAttr;
+import static org.apache.cayenne.dbsync.merge.builders.ObjectMother.objEntity;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -287,7 +289,6 @@ public class DefaultDbImportActionTest {
 
     private DefaultDbImportAction buildDbImportAction(Log log, FileProjectSaver projectSaver, MapLoader mapLoader) throws Exception {
         DbAdapter dbAdapter = mock(DbAdapter.class);
-        when(dbAdapter.mergerFactory()).thenReturn(new MergerFactory());
 
 		DbAdapterFactory adapterFactory = mock(DbAdapterFactory.class);
 		when(adapterFactory.createAdapter(any(DataNodeDescriptor.class), any(DataSource.class))).thenReturn(dbAdapter);
@@ -296,13 +297,16 @@ public class DefaultDbImportActionTest {
 		DataSource mock = mock(DataSource.class);
 		when(dataSourceFactory.getDataSource(any(DataNodeDescriptor.class))).thenReturn(mock);
 
-        return new DefaultDbImportAction(log, projectSaver, dataSourceFactory, adapterFactory, mapLoader);
+		MergerTokenFactoryProvider mergerTokenFactoryProvider = mock(MergerTokenFactoryProvider.class);
+		when(mergerTokenFactoryProvider.get(any(DbAdapter.class))).thenReturn(new DefaultMergerTokenFactory());
+
+        return new DefaultDbImportAction(log, projectSaver, dataSourceFactory, adapterFactory, mapLoader, mergerTokenFactoryProvider);
     }
 
 	@Test
 	public void testSaveLoaded() throws Exception {
 		Log log = mock(Log.class);
-		Injector i = DIBootstrap.createInjector(new ToolsModule(log), new DbImportModule());
+		Injector i = DIBootstrap.createInjector(new CayenneDbSyncModule(), new ToolsModule(log), new DbImportModule());
 
         DefaultDbImportAction action = (DefaultDbImportAction) i.getInstance(DbImportAction.class);
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index aa04b5f..fcd7155 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -32,6 +32,7 @@ CAY-2107 cayenne-crypto: Lazy initialization of crypto subsystem
 CAY-2111 Unbind transaction object from the current thread for iterated queries
 CAY-2112 Expose callback for "performInTransaction"
 CAY-2113 cdbimport: Reverse-engineering reinstates previously ignored columns
+CAY-2116 Split schema synchronization code in a separate module 
 
 Bug Fixes:
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Main.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Main.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Main.java
index 80f8748..838f736 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Main.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/Main.java
@@ -19,15 +19,8 @@
 
 package org.apache.cayenne.modeler;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.prefs.Preferences;
-
-import javax.swing.SwingUtilities;
-
 import org.apache.cayenne.configuration.server.ServerModule;
+import org.apache.cayenne.dbsync.CayenneDbSyncModule;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.Module;
@@ -39,6 +32,13 @@ import org.apache.cayenne.project.CayenneProjectModule;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import javax.swing.*;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.prefs.Preferences;
+
 /**
  * Main class responsible for starting CayenneModeler.
  */
@@ -105,6 +105,7 @@ public class Main {
     protected Collection<Module> appendModules(Collection<Module> modules) {
         modules.add(new ServerModule("CayenneModeler"));
         modules.add(new CayenneProjectModule());
+        modules.add(new CayenneDbSyncModule());
         modules.add(new CayenneModelerModule());
 
         return modules;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
index 7381886..a4f54fc 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/CreateObjEntityAction.java
@@ -19,10 +19,9 @@
 
 package org.apache.cayenne.modeler.action;
 
-import java.awt.event.ActionEvent;
-
 import org.apache.cayenne.configuration.ConfigurationNode;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.ObjEntity;
@@ -37,7 +36,8 @@ import org.apache.cayenne.modeler.event.EntityDisplayEvent;
 import org.apache.cayenne.modeler.undo.CreateObjEntityUndoableEdit;
 import org.apache.cayenne.modeler.util.CayenneAction;
 import org.apache.cayenne.util.DeleteRuleUpdater;
-import org.apache.cayenne.util.EntityMergeSupport;
+
+import java.awt.event.ActionEvent;
 
 public class CreateObjEntityAction extends CayenneAction {
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/2f7b1d53/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
----------------------------------------------------------------------
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
index aec4a2d..65294b5 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/action/DbEntitySyncAction.java
@@ -19,10 +19,8 @@
 
 package org.apache.cayenne.modeler.action;
 
-import java.awt.event.ActionEvent;
-import java.util.Iterator;
-
 import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.dbsync.merge.EntityMergeSupport;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.event.EntityEvent;
@@ -32,7 +30,9 @@ import org.apache.cayenne.modeler.ProjectController;
 import org.apache.cayenne.modeler.dialog.objentity.EntitySyncController;
 import org.apache.cayenne.modeler.undo.DbEntitySyncUndoableEdit;
 import org.apache.cayenne.modeler.util.CayenneAction;
-import org.apache.cayenne.util.EntityMergeSupport;
+
+import java.awt.event.ActionEvent;
+import java.util.Iterator;
 
 /**
  * Action that synchronizes all ObjEntities with the current state of the