You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/11/14 14:27:49 UTC

[18/32] cayenne git commit: Cgen tab, cgen configuration, cgen in maven, ant, gradle.

Cgen tab, cgen configuration, cgen in maven, ant, gradle.


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/52ea45b5
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/52ea45b5
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/52ea45b5

Branch: refs/heads/master
Commit: 52ea45b5d72b5a6b1466e7779e03753c74ebaf3b
Parents: 6a43436
Author: Arseni Bulatski <an...@gmail.com>
Authored: Wed Oct 31 16:33:52 2018 +0300
Committer: Arseni Bulatski <an...@gmail.com>
Committed: Thu Nov 8 17:08:08 2018 +0300

----------------------------------------------------------------------
 .../cayenne/tools/CayenneGeneratorTask.java     |  141 ++-
 .../cayenne/tools/CgenWithConfigTest.java       |   41 +-
 cayenne-ant/src/test/resources/cgenTest.map.xml |   19 +-
 .../apache/cayenne/gen/CgenConfiguration.java   |  363 ++++++
 .../cayenne/gen/ClassGenerationAction.java      |  669 +++--------
 .../gen/ClientClassGenerationAction.java        |   39 +-
 .../cayenne/gen/xml/CgenConfigHandler.java      |   32 +-
 .../cayenne/gen/xml/CgenSaverDelegate.java      |   14 +-
 .../CayenneGeneratorEmbeddableFilterAction.java |   29 +
 .../CayenneGeneratorEntityFilterAction.java     |   22 +-
 .../cayenne/gen/ClassGenerationActionTest.java  |   37 +-
 .../java/org/apache/cayenne/tools/CgenTask.java |  137 ++-
 .../org/apache/cayenne/tools/CgenTaskIT.java    |   60 +-
 .../org/apache/cayenne/tools/CgenTaskTest.java  |   43 +-
 .../cayenne/tools/CgenTaskWithConfigIT.java     |   71 --
 .../org/apache/cayenne/tools/cgenConfig.map.xml |   22 +
 .../org/apache/cayenne/tools/cgenMap.map.xml    |   19 +-
 .../cayenne/tools/cgen_with_config.gradle       |    3 +-
 .../cayenne/tools/cgen_with_configs.gradle      |   32 +
 .../cayenne/tools/CayenneGeneratorMojo.java     |  135 ++-
 .../cayenne/tools/CayenneGeneratorMojoTest.java |   48 +
 .../cayenne/tools/CgenWithConfigMojoTest.java   |   51 -
 .../resources/cgen/project-to-test/cgen-pom.xml |    2 -
 .../cgen/project-to-test/datamap-and-pom.xml    |   54 +
 .../src/test/resources/cgen/testCgen.map.xml    |   22 +
 .../src/test/resources/cgen/testCgenMap.map.xml |   19 +-
 .../modeler/action/GenerateCodeAction.java      |   12 +-
 .../dialog/codegen/ClassesTabController.java    |  406 +++----
 .../modeler/dialog/codegen/ClassesTabPanel.java |  282 ++---
 .../dialog/codegen/ClientModeController.java    |  162 +--
 .../dialog/codegen/CodeGeneratorController.java |  338 +++---
 .../codegen/CodeGeneratorControllerBase.java    |  760 ++++++------
 .../dialog/codegen/CodeGeneratorDialog.java     |  198 +--
 .../dialog/codegen/CustomModeController.java    |  470 ++++----
 .../modeler/dialog/codegen/CustomModePanel.java |  274 ++---
 .../codegen/CustomPreferencesUpdater.java       |  418 +++----
 .../dialog/codegen/GeneratorController.java     | 1123 +++++++++---------
 .../codegen/GeneratorControllerPanel.java       |  110 +-
 .../dialog/codegen/GeneratorTabController.java  |  230 ++--
 .../dialog/codegen/GeneratorTabPanel.java       |  130 +-
 .../dialog/codegen/StandardModeController.java  |  164 +--
 .../dialog/codegen/StandardModePanel.java       |   84 +-
 .../dialog/codegen/StandardPanelComponent.java  |  162 +--
 .../modeler/editor/DataDomainTabbedView.java    |  183 +--
 .../modeler/editor/DataMapTabbedView.java       |   12 +-
 .../editor/cgen/ClientModeController.java       |   12 +-
 .../editor/cgen/CodeGeneratorController.java    |   51 +-
 .../cgen/CodeGeneratorControllerBase.java       |   37 +-
 .../editor/cgen/CustomModeController.java       |   58 +-
 .../editor/cgen/GeneratorController.java        |   88 +-
 .../editor/cgen/GeneratorControllerPanel.java   |    6 +-
 .../editor/cgen/GeneratorTabController.java     |   51 +-
 .../editor/cgen/StandardModeController.java     |   17 +-
 .../modeler/editor/cgen/domain/CgenPanel.java   |   59 +
 .../modeler/editor/cgen/domain/CgenTab.java     |   89 ++
 .../editor/cgen/domain/CgenTabController.java   |  197 +++
 .../cayenne/modeler/util/ModelerUtil.java       |   43 +
 57 files changed, 4547 insertions(+), 3803 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-ant/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
----------------------------------------------------------------------
diff --git a/cayenne-ant/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java b/cayenne-ant/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
index a82931e..02cc0bf 100644
--- a/cayenne-ant/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
+++ b/cayenne-ant/src/main/java/org/apache/cayenne/tools/CayenneGeneratorTask.java
@@ -24,6 +24,7 @@ import org.apache.cayenne.dbsync.filter.NamePatternMatcher;
 import org.apache.cayenne.dbsync.reverse.configuration.ToolsModule;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
+import org.apache.cayenne.gen.CgenConfiguration;
 import org.apache.cayenne.gen.CgenModule;
 import org.apache.cayenne.gen.ClassGenerationAction;
 import org.apache.cayenne.gen.ClientClassGenerationAction;
@@ -34,6 +35,8 @@ import org.apache.velocity.VelocityContext;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 
 /**
  * An Ant task to perform class generation based on CayenneDataMap.
@@ -44,6 +47,7 @@ public class CayenneGeneratorTask extends CayenneTask {
 
     protected String includeEntitiesPattern;
     protected String excludeEntitiesPattern;
+    protected String excludeEmbeddablesPattern;
     protected VPPConfig vppConfig;
 
     protected File map;
@@ -63,7 +67,11 @@ public class CayenneGeneratorTask extends CayenneTask {
     protected String querytemplate;
     protected String querysupertemplate;
     protected Boolean usepkgpath;
-    protected Boolean createpropertynames;
+    protected boolean createpropertynames;
+
+    private boolean force;
+
+    private boolean useConfigFromDataMap;
 
     private transient Injector injector;
 
@@ -82,36 +90,6 @@ public class CayenneGeneratorTask extends CayenneTask {
         return vppConfig.getVelocityContext();
     }
 
-    protected ClassGenerationAction createGeneratorAction(DataMap dataMap) {
-        ClassGenerationAction action = injector.getInstance(DataChannelMetaData.class).get(dataMap, ClassGenerationAction.class);
-
-        if (client) {
-            action = new ClientClassGenerationAction();
-        } else {
-            if(action == null) {
-                action = new ClassGenerationAction();
-            }
-        }
-
-        action.setContext(getVppContext());
-        action.setDestDir(destDir);
-        action.setEncoding(encoding != null ? encoding : action.getEncoding());
-        action.setMakePairs(makepairs != null ? makepairs : action.isMakePairs());
-        action.setArtifactsGenerationMode(mode != null ? mode : action.getArtifactsGenerationMode());
-        action.setOutputPattern(outputPattern != null ? outputPattern : action.getOutputPattern());
-        action.setOverwrite(overwrite != null ? overwrite : action.isOverwrite());
-        action.setSuperPkg(superpkg != null ? superpkg : action.getSuperPkg());
-        action.setSuperTemplate(supertemplate != null ? supertemplate : action.getSuperclassTemplate());
-        action.setTemplate(template != null ? template : action.getTemplate());
-        action.setEmbeddableSuperTemplate(embeddablesupertemplate != null ? embeddablesupertemplate : action.getEmbeddableSuperTemplate());
-        action.setEmbeddableTemplate(embeddabletemplate != null ? embeddabletemplate : action.getEmbeddableTemplate());
-        action.setUsePkgPath(usepkgpath != null ? usepkgpath : action.isUsePkgPath());
-        action.setCreatePropertyNames(createpropertynames != null ? createpropertynames : action.isCreatePropertyNames());
-        action.setQueryTemplate(querytemplate != null ? querytemplate : action.getQueryTemplate());
-        action.setQuerySuperTemplate(querysupertemplate != null ? querysupertemplate : action.getQuerySuperTemplate());
-        return action;
-    }
-
     /**
      * Executes the task. It will be called by ant framework.
      */
@@ -127,23 +105,28 @@ public class CayenneGeneratorTask extends CayenneTask {
         loadAction.setMainDataMapFile(map);
         loadAction.setAdditionalDataMapFiles(additionalMaps);
 
-        CayenneGeneratorEntityFilterAction filterAction = new CayenneGeneratorEntityFilterAction();
-        filterAction.setClient(client);
-        filterAction.setNameFilter(NamePatternMatcher.build(logger, includeEntitiesPattern, excludeEntitiesPattern));
+        CayenneGeneratorEntityFilterAction filterEntityAction = new CayenneGeneratorEntityFilterAction();
+        filterEntityAction.setClient(client);
+        filterEntityAction.setNameFilter(NamePatternMatcher.build(logger, includeEntitiesPattern, excludeEntitiesPattern));
 
+        CayenneGeneratorEmbeddableFilterAction filterEmbeddableAction = new CayenneGeneratorEmbeddableFilterAction();
+        filterEmbeddableAction.setNameFilter(NamePatternMatcher.build(logger, null, excludeEmbeddablesPattern));
         try {
 
             DataMap dataMap = loadAction.getMainDataMap();
 
-            ClassGenerationAction generatorAction = createGeneratorAction(dataMap);
+            ClassGenerationAction generatorAction = createGenerator(dataMap);
             generatorAction.setLogger(logger);
-            generatorAction.setTimestamp(map.lastModified());
-            generatorAction.setDataMap(dataMap);
-            if(!generatorAction.getEntities().isEmpty() || !generatorAction.getEmbeddables().isEmpty()){
+            if(force) {
+                // will (re-)generate all files
+                generatorAction.getCgenConfiguration().setForce(true);
+            }
+            generatorAction.getCgenConfiguration().setTimestamp(map.lastModified());
+            if(!hasConfig() && useConfigFromDataMap) {
                 generatorAction.prepareArtifacts();
             } else {
-                generatorAction.addEntities(filterAction.getFilteredEntities(dataMap));
-                generatorAction.addEmbeddables(filterAction.getFilteredEmbeddables(dataMap));
+                generatorAction.addEntities(filterEntityAction.getFilteredEntities(dataMap));
+                generatorAction.addEmbeddables(filterEmbeddableAction.getFilteredEmbeddables(dataMap));
                 generatorAction.addQueries(dataMap.getQueryDescriptors());
             }
             generatorAction.execute();
@@ -153,6 +136,76 @@ public class CayenneGeneratorTask extends CayenneTask {
         }
     }
 
+    private ClassGenerationAction createGenerator(DataMap dataMap) {
+        CgenConfiguration cgenConfiguration = buildConfiguration(dataMap);
+        ClassGenerationAction classGenerationAction = cgenConfiguration.isClient() ? new ClientClassGenerationAction(cgenConfiguration) :
+                new ClassGenerationAction(cgenConfiguration);
+        injector.injectMembers(classGenerationAction);
+
+        return classGenerationAction;
+    }
+
+    private boolean hasConfig() {
+        return destDir != null || encoding != null || client || excludeEntitiesPattern != null || excludeEmbeddablesPattern != null || includeEntitiesPattern != null ||
+                makepairs != null || mode != null || outputPattern != null || overwrite != null || superpkg != null ||
+                supertemplate != null || template != null || embeddabletemplate != null || embeddablesupertemplate != null ||
+                usepkgpath != null || createpropertynames || querytemplate != null ||
+                querysupertemplate != null || createpkproperties || force;
+    }
+
+    private CgenConfiguration buildConfiguration(DataMap dataMap) {
+        CgenConfiguration cgenConfiguration = injector.getInstance(DataChannelMetaData.class).get(dataMap, CgenConfiguration.class);
+        if(hasConfig()) {
+            return cgenConfigFromPom(dataMap);
+        } else if(cgenConfiguration != null) {
+            useConfigFromDataMap = true;
+            java.nio.file.Path resourcePath = Paths.get(map.getPath());
+            if(Files.isRegularFile(resourcePath)) {
+                resourcePath = resourcePath.getParent();
+            }
+            cgenConfiguration.setRelPath(resourcePath.resolve(cgenConfiguration.getRelPath()));
+            return cgenConfiguration;
+        } else {
+            cgenConfiguration = new CgenConfiguration();
+            cgenConfiguration.setDataMap(dataMap);
+            return cgenConfiguration;
+        }
+    }
+
+    private CgenConfiguration cgenConfigFromPom(DataMap dataMap){
+        CgenConfiguration cgenConfiguration = new CgenConfiguration();
+        cgenConfiguration.setDataMap(dataMap);
+        cgenConfiguration.setRelPath(destDir != null ? destDir.getPath() : cgenConfiguration.getRelPath());
+        cgenConfiguration.setEncoding(encoding != null ? encoding : cgenConfiguration.getEncoding());
+        cgenConfiguration.setMakePairs(makepairs != null ? makepairs : cgenConfiguration.isMakePairs());
+        cgenConfiguration.setArtifactsGenerationMode(mode != null ? mode : cgenConfiguration.getArtifactsGenerationMode());
+        cgenConfiguration.setOutputPattern(outputPattern != null ? outputPattern : cgenConfiguration.getOutputPattern());
+        cgenConfiguration.setOverwrite(overwrite != null ? overwrite : cgenConfiguration.isOverwrite());
+        cgenConfiguration.setSuperPkg(superpkg != null ? superpkg : cgenConfiguration.getSuperPkg());
+        cgenConfiguration.setSuperTemplate(supertemplate != null ? supertemplate : cgenConfiguration.getSuperTemplate());
+        cgenConfiguration.setTemplate(template != null ? template :  cgenConfiguration.getTemplate());
+        cgenConfiguration.setEmbeddableSuperTemplate(embeddablesupertemplate != null ? embeddablesupertemplate : cgenConfiguration.getEmbeddableSuperTemplate());
+        cgenConfiguration.setEmbeddableTemplate(embeddabletemplate != null ? embeddabletemplate : cgenConfiguration.getEmbeddableTemplate());
+        cgenConfiguration.setUsePkgPath(usepkgpath != null ? usepkgpath : cgenConfiguration.isUsePkgPath());
+        cgenConfiguration.setCreatePropertyNames(createpropertynames);
+        cgenConfiguration.setQueryTemplate(querytemplate != null ? querytemplate : cgenConfiguration.getQueryTemplate());
+        cgenConfiguration.setQuerySuperTemplate(querysupertemplate != null ? querysupertemplate : cgenConfiguration.getQuerySuperTemplate());
+        cgenConfiguration.setCreatePKProperties(createpkproperties);
+        cgenConfiguration.setClient(client);
+        if(!cgenConfiguration.isMakePairs()) {
+            if(template == null) {
+                cgenConfiguration.setTemplate(client ? ClientClassGenerationAction.SINGLE_CLASS_TEMPLATE : ClassGenerationAction.SINGLE_CLASS_TEMPLATE);
+            }
+            if(embeddabletemplate == null) {
+                cgenConfiguration.setEmbeddableTemplate(ClassGenerationAction.EMBEDDABLE_SINGLE_CLASS_TEMPLATE);
+            }
+            if(querytemplate == null) {
+                cgenConfiguration.setQueryTemplate(client ? ClientClassGenerationAction.DATAMAP_SINGLE_CLASS_TEMPLATE : ClassGenerationAction.DATAMAP_SINGLE_CLASS_TEMPLATE);
+            }
+        }
+        return cgenConfiguration;
+    }
+
     /**
      * Validates attributes that are not related to internal DefaultClassGenerator. Throws
      * BuildException if attributes are invalid.
@@ -278,6 +331,10 @@ public class CayenneGeneratorTask extends CayenneTask {
         this.includeEntitiesPattern = includeEntitiesPattern;
     }
 
+    public void setExcludeEmbeddablesPattern(String excludeEmbeddablesPattern) {
+        this.excludeEmbeddablesPattern = excludeEmbeddablesPattern;
+    }
+
     /**
      * Sets <code>outputPattern</code> property.
      */
@@ -314,6 +371,10 @@ public class CayenneGeneratorTask extends CayenneTask {
         this.createpkproperties = createpkproperties;
     }
 
+    public void setForce(boolean force) {
+        this.force = force;
+    }
+
     /**
      * Provides a <code>VPPConfig</code> object to configure. (Written with createConfig()
      * instead of addConfig() to avoid run-time dependency on VPP).

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-ant/src/test/java/org/apache/cayenne/tools/CgenWithConfigTest.java
----------------------------------------------------------------------
diff --git a/cayenne-ant/src/test/java/org/apache/cayenne/tools/CgenWithConfigTest.java b/cayenne-ant/src/test/java/org/apache/cayenne/tools/CgenWithConfigTest.java
index cdccd49..4241105 100644
--- a/cayenne-ant/src/test/java/org/apache/cayenne/tools/CgenWithConfigTest.java
+++ b/cayenne-ant/src/test/java/org/apache/cayenne/tools/CgenWithConfigTest.java
@@ -64,25 +64,58 @@ public class CgenWithConfigTest {
         File mapDir = new File(baseDir, "cgenConfigTest");
         assertTrue(mapDir.mkdirs());
 
+        task.setMap(map);
+
+        // run task
+        task.execute();
+
+        // check results
+        File entity = new File(mapDir, convertPath("ObjEntity1.txt"));
+        assertTrue(entity.isFile());
+
+        File datamap = new File(mapDir, convertPath("Antmap_cgen_xml.txt"));
+        assertTrue(datamap.isFile());
+
+        File notIncludedEntity = new File(mapDir, "ObjEntity.txt");
+        assertFalse(notIncludedEntity.exists());
+
+        File notIncludeSuperDatamap = new File("_Antmap_cgen_xml.txt");
+        assertFalse(notIncludeSuperDatamap.exists());
+    }
+
+    @Test
+    public void testCgenWithDmAndPomConfigs() throws Exception {
+        File mapDir = new File(baseDir, "cgenDmPomTest");
+        assertTrue(mapDir.mkdirs());
+
         task.setDestDir(mapDir);
         task.setMap(map);
+        task.setExcludeEntities("ObjEntity1");
         task.setMode("entity");
+        task.setMakepairs(false);
+        task.setOutputPattern("*.txt");
 
         // run task
         task.execute();
 
         // check results
-        File entity = new File(mapDir, convertPath("ObjEntity1.txt"));
+        File entity = new File(mapDir, convertPath("ObjEntity.txt"));
         assertTrue(entity.isFile());
 
-        File datamap = new File(mapDir, convertPath("TestCgenMap.txt"));
+        File embeddable = new File(mapDir, convertPath("Embeddable.txt"));
+        assertTrue(embeddable.isFile());
+
+        File datamap = new File(mapDir, convertPath("Antmap_cgen_xml.txt"));
         assertFalse(datamap.exists());
 
-        File notIncludedEntity = new File(mapDir, "ObjEntity.txt");
+        File notIncludedEntity = new File(mapDir, "ObjEntity1.txt");
         assertFalse(notIncludedEntity.exists());
 
-        File notIncludeSuperDatamap = new File("_TestCgenMap.txt");
+        File notIncludeSuperDatamap = new File("_Antmap_cgen_xml.txt");
         assertFalse(notIncludeSuperDatamap.exists());
+
+        File notIncludedSuperEntity = new File(mapDir, convertPath("_ObjEntity.txt"));
+        assertFalse(notIncludedSuperEntity.exists());
     }
 
     private String convertPath(String unixPath) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-ant/src/test/resources/cgenTest.map.xml
----------------------------------------------------------------------
diff --git a/cayenne-ant/src/test/resources/cgenTest.map.xml b/cayenne-ant/src/test/resources/cgenTest.map.xml
index 930acbc..d249f0f 100644
--- a/cayenne-ant/src/test/resources/cgenTest.map.xml
+++ b/cayenne-ant/src/test/resources/cgenTest.map.xml
@@ -7,21 +7,16 @@
     <obj-entity name="ObjEntity" className="ObjEntity"/>
     <obj-entity name="ObjEntity1" className="ObjEntity1"/>
     <cgen xmlns="http://cayenne.apache.org/schema/10/cgen">
-        <objEntity>
-            <name>ObjEntity1</name>
-        </objEntity>
-        <generationMode>all</generationMode>
-        <dataMapTemplate>templates/v4_1/datamap-subclass.vm</dataMapTemplate>
-        <dataMapSuperclassTemplate>templates/v4_1/datamap-superclass.vm</dataMapSuperclassTemplate>
-        <subclassTemplate>templates/v4_1/subclass.vm</subclassTemplate>
-        <superclassTemplate>templates/v4_1/superclass.vm</superclassTemplate>
-        <embeddableTemplate>templates/v4_1/embeddable-subclass.vm</embeddableTemplate>
-        <embeddableSuperclassTemplate>templates/v4_1/embeddable-superclass.vm</embeddableSuperclassTemplate>
+        <destDir>cgenConfigTest</destDir>
+        <excludeEntities>ObjEntity</excludeEntities>
+        <excludeEmbeddables>Embeddable</excludeEmbeddables>
+        <mode>all</mode>
+        <template>templates/v4_1/subclass.vm</template>
+        <superTemplate>templates/v4_1/superclass.vm</superTemplate>
         <outputPattern>*.txt</outputPattern>
         <makePairs>false</makePairs>
         <usePkgPath>true</usePkgPath>
-        <overwriteSubclasses>false</overwriteSubclasses>
+        <overwrite>false</overwrite>
         <createPropertyNames>false</createPropertyNames>
-        <encoding>UTF-8</encoding>
     </cgen>
 </data-map>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java
new file mode 100644
index 0000000..8d4157d
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/CgenConfiguration.java
@@ -0,0 +1,363 @@
+package org.apache.cayenne.gen;
+
+import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
+import org.apache.cayenne.gen.xml.CgenExtension;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.util.XMLEncoder;
+import org.apache.cayenne.util.XMLSerializable;
+
+import java.io.Serializable;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+public class CgenConfiguration implements Serializable, XMLSerializable {
+
+    private Collection<Artifact> artifacts;
+    private Collection<String> entityArtifacts;
+    private Collection<String> excludeEntityArtifacts;
+    private Collection<String> embeddableArtifacts;
+    private Collection<String> excludeEmbeddableArtifacts;
+
+    private String superPkg;
+    private DataMap dataMap;
+
+    private ArtifactsGenerationMode artifactsGenerationMode;
+    private boolean makePairs;
+
+    private Path rootPath;
+    private Path relPath;
+    private boolean overwrite;
+    private boolean usePkgPath;
+
+    private String template;
+    private String superTemplate;
+    private String embeddableTemplate;
+    private String embeddableSuperTemplate;
+    private String queryTemplate;
+    private String querySuperTemplate;
+    private long timestamp;
+    private String outputPattern;
+    private String encoding;
+    private boolean createPropertyNames;
+    private boolean force; // force run generator
+    /**
+     * @since 4.1
+     */
+    private boolean createPKProperties;
+
+    private boolean client;
+
+    public CgenConfiguration() {
+        this.outputPattern = "*.java";
+        this.timestamp = 0L;
+        this.usePkgPath = true;
+        this.makePairs = true;
+
+        this.artifacts = new ArrayList<>();
+        this.entityArtifacts = new ArrayList<>();
+        this.excludeEntityArtifacts = new ArrayList<>();
+        this.embeddableArtifacts = new ArrayList<>();
+        this.excludeEmbeddableArtifacts = new ArrayList<>();
+        this.artifactsGenerationMode = ArtifactsGenerationMode.ENTITY;
+
+        this.template = ClassGenerationAction.SUBCLASS_TEMPLATE;
+        this.superTemplate = ClassGenerationAction.SUPERCLASS_TEMPLATE;
+        this.embeddableTemplate = ClassGenerationAction.EMBEDDABLE_SUBCLASS_TEMPLATE;
+        this.embeddableSuperTemplate = ClassGenerationAction.EMBEDDABLE_SUPERCLASS_TEMPLATE;
+        this.queryTemplate = ClassGenerationAction.DATAMAP_SUBCLASS_TEMPLATE;
+        this.querySuperTemplate = ClassGenerationAction.DATAMAP_SUPERCLASS_TEMPLATE;
+    }
+
+    public void resetCollections(){
+        embeddableArtifacts.clear();
+        entityArtifacts.clear();
+    }
+
+    public String getSuperPkg() {
+        return superPkg;
+    }
+
+    public void setSuperPkg(String superPkg) {
+        this.superPkg = superPkg;
+    }
+
+    public DataMap getDataMap() {
+        return dataMap;
+    }
+
+    public void setDataMap(DataMap dataMap) {
+        this.dataMap = dataMap;
+    }
+
+    public void setArtifactsGenerationMode(String mode) {
+        if (ArtifactsGenerationMode.ENTITY.getLabel().equalsIgnoreCase(mode)) {
+            this.artifactsGenerationMode = ArtifactsGenerationMode.ENTITY;
+        } else {
+            this.artifactsGenerationMode = ArtifactsGenerationMode.ALL;
+        }
+    }
+
+    public String getArtifactsGenerationMode(){
+        return artifactsGenerationMode.getLabel();
+    }
+
+
+    public boolean isMakePairs() {
+        return makePairs;
+    }
+
+    public void setMakePairs(boolean makePairs) {
+        this.makePairs = makePairs;
+    }
+
+    public Path getRootPath() {
+        return rootPath;
+    }
+
+    public void setRootPath(Path rootPath) {
+        this.rootPath = rootPath;
+    }
+
+    public void setRelPath(Path relPath) {
+        this.relPath = relPath;
+    }
+
+    public void setRelPath(String path) {
+		this.relPath = rootPath != null ? rootPath.relativize(Paths.get(path)) : Paths.get(path);
+	}
+
+    public boolean isOverwrite() {
+        return overwrite;
+    }
+
+    public void setOverwrite(boolean overwrite) {
+        this.overwrite = overwrite;
+    }
+
+    public boolean isUsePkgPath() {
+        return usePkgPath;
+    }
+
+    public void setUsePkgPath(boolean usePkgPath) {
+        this.usePkgPath = usePkgPath;
+    }
+
+    public String getTemplate() {
+        return template;
+    }
+
+    public void setTemplate(String template) {
+        this.template = template;
+    }
+
+    public String getSuperTemplate() {
+        return superTemplate;
+    }
+
+    public void setSuperTemplate(String superTemplate) {
+        this.superTemplate = superTemplate;
+    }
+
+    public String getEmbeddableTemplate() {
+        return embeddableTemplate;
+    }
+
+    public void setEmbeddableTemplate(String embeddableTemplate) {
+        this.embeddableTemplate = embeddableTemplate;
+    }
+
+    public String getEmbeddableSuperTemplate() {
+        return embeddableSuperTemplate;
+    }
+
+    public void setEmbeddableSuperTemplate(String embeddableSuperTemplate) {
+        this.embeddableSuperTemplate = embeddableSuperTemplate;
+    }
+
+    public String getQueryTemplate() {
+        return queryTemplate;
+    }
+
+    public void setQueryTemplate(String queryTemplate) {
+        this.queryTemplate = queryTemplate;
+    }
+
+    public String getQuerySuperTemplate() {
+        return querySuperTemplate;
+    }
+
+    public void setQuerySuperTemplate(String querySuperTemplate) {
+        this.querySuperTemplate = querySuperTemplate;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(long timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getOutputPattern() {
+        return outputPattern;
+    }
+
+    public void setOutputPattern(String outputPattern) {
+        this.outputPattern = outputPattern;
+    }
+
+    public String getEncoding() {
+        return encoding;
+    }
+
+    public void setEncoding(String encoding) {
+        this.encoding = encoding;
+    }
+
+    public boolean isCreatePropertyNames() {
+        return createPropertyNames;
+    }
+
+    public void setCreatePropertyNames(boolean createPropertyNames) {
+        this.createPropertyNames = createPropertyNames;
+    }
+
+    public boolean isForce() {
+        return force;
+    }
+
+    public void setForce(boolean force) {
+        this.force = force;
+    }
+
+    public boolean isCreatePKProperties() {
+        return createPKProperties;
+    }
+
+    public void setCreatePKProperties(boolean createPKProperties) {
+        this.createPKProperties = createPKProperties;
+    }
+
+    public String getRelPath() {
+        if(relPath == null || relPath.toString().isEmpty()) {
+            return ".";
+        }
+        return relPath.toString();
+    }
+
+    public String getDir(){
+        return rootPath != null ? relPath != null ? rootPath.resolve(relPath).toAbsolutePath().normalize().toString() : rootPath.toString() : null;
+    }
+
+    public Collection<Artifact> getArtifacts() {
+        return artifacts;
+    }
+
+    public Collection<String> getEntities() {
+        return entityArtifacts;
+    }
+
+    public Collection<String> getEmbeddables() {
+        return embeddableArtifacts;
+    }
+
+    public Path buildPath() {
+		return rootPath != null ? relPath != null ? rootPath.resolve(relPath).toAbsolutePath().normalize() : rootPath : relPath;
+	}
+
+    /**
+     * @since 4.1
+     */
+    public void loadEntity(String name) {
+        entityArtifacts.add(name);
+    }
+
+    /**
+     * @since 4.1
+     */
+    public void loadEmbeddable(String name) {
+        embeddableArtifacts.add(name);
+    }
+
+    public void loadEntities(String entities) {
+        excludeEntityArtifacts.addAll(Arrays.asList(entities.split(",")));
+    }
+
+    private String getExcludeEntites() {
+        Collection<String> excludeEntities = dataMap.getObjEntities()
+                .stream()
+                .filter(entity -> !entityArtifacts.contains(entity.getName()))
+                .map(ObjEntity::getName)
+                .collect(Collectors.toList());
+        return org.apache.commons.lang3.StringUtils.join(excludeEntities, ",");
+    }
+
+    public void loadEmbeddables(String embeddables) {
+        excludeEmbeddableArtifacts.addAll(Arrays.asList(embeddables.split(",")));
+    }
+
+    private String getExcludeEmbeddables() {
+        Collection<String> excludeEmbeddable = dataMap.getEmbeddables()
+                .stream()
+                .filter(embeddable -> !embeddableArtifacts.contains(embeddable.getClassName()))
+                .map(Embeddable::getClassName)
+                .collect(Collectors.toList());
+        return org.apache.commons.lang3.StringUtils.join(excludeEmbeddable, ",");
+    }
+
+	public void resolveExcludeEntities() {
+		entityArtifacts = dataMap.getObjEntities()
+				.stream()
+				.filter(entity -> !excludeEntityArtifacts.contains(entity.getName()))
+				.map(ObjEntity::getName)
+				.collect(Collectors.toList());
+	}
+
+	public void resolveExcludeEmbeddables() {
+    	embeddableArtifacts = dataMap.getEmbeddables()
+				.stream()
+				.filter(embeddable -> !excludeEmbeddableArtifacts.contains(embeddable.getClassName()))
+				.map(Embeddable::getClassName)
+				.collect(Collectors.toList());
+	}
+
+    public boolean isClient() {
+        return client;
+    }
+
+    public void setClient(boolean client) {
+        this.client = client;
+    }
+
+    public void addArtifact(Artifact artifact) {
+        artifacts.add(artifact);
+    }
+
+    @Override
+    public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) {
+        encoder.start("cgen")
+                .attribute("xmlns", CgenExtension.NAMESPACE)
+                .simpleTag("excludeEntities", getExcludeEntites())
+                .simpleTag("excludeEmbeddables",getExcludeEmbeddables())
+                .simpleTag("destDir", getRelPath())
+                .simpleTag("mode", this.artifactsGenerationMode.getLabel())
+                .simpleTag("template", this.template)
+                .simpleTag("superTemplate", this.superTemplate)
+                .simpleTag("outputPattern", this.outputPattern)
+                .simpleTag("makePairs", Boolean.toString(this.makePairs))
+                .simpleTag("usePkgPath", Boolean.toString(this.usePkgPath))
+                .simpleTag("overwrite", Boolean.toString(this.overwrite))
+                .simpleTag("createPropertyNames", Boolean.toString(this.createPropertyNames))
+                .simpleTag("superPkg", this.superPkg)
+                .simpleTag("createPKProperties", Boolean.toString(this.createPKProperties))
+                .simpleTag("client", Boolean.toString(client))
+                .end();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
index 434421f..36ba514 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
@@ -20,14 +20,9 @@
 package org.apache.cayenne.gen;
 
 import org.apache.cayenne.CayenneRuntimeException;
-import org.apache.cayenne.configuration.ConfigurationNodeVisitor;
-import org.apache.cayenne.gen.xml.CgenExtension;
-import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.Embeddable;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.map.QueryDescriptor;
-import org.apache.cayenne.util.XMLEncoder;
-import org.apache.cayenne.util.XMLSerializable;
 import org.apache.velocity.Template;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
@@ -36,12 +31,12 @@ import org.slf4j.Logger;
 import java.io.*;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.util.*;
 import java.util.stream.Collectors;
 
-public class ClassGenerationAction implements Serializable, XMLSerializable {
-	static final String TEMPLATES_DIR_NAME = "templates/v4_1/";
+public class ClassGenerationAction {
+
+	private static final String TEMPLATES_DIR_NAME = "templates/v4_1/";
 
 	public static final String SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "singleclass.vm";
 	public static final String SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "subclass.vm";
@@ -58,159 +53,105 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 	public static final String SUPERCLASS_PREFIX = "_";
 	private static final String WILDCARD = "*";
 
-	Collection<Artifact> artifacts;
-	private Collection<String> entityArtifacts;
-	private Collection<String> excludeEntityArtifacts;
-	private Collection<String> embeddableArtifacts;
-	private Collection<String> excludeEmbeddableArtifacts;
-
-	protected String superPkg;
-	protected DataMap dataMap;
-
-	protected ArtifactsGenerationMode artifactsGenerationMode;
-	protected boolean makePairs;
-
+	protected CgenConfiguration cgenConfiguration;
 	protected Logger logger;
 
-	protected Path rootPath;
-	protected Path relPath;
+    // runtime ivars
+    protected VelocityContext context;
+    protected Map<String, Template> templateCache;
 
-	protected boolean overwrite;
-	protected boolean usePkgPath;
-
-	protected String template;
-	protected String superTemplate;
-	protected String embeddableTemplate;
-	protected String embeddableSuperTemplate;
-	protected String queryTemplate;
-	protected String querySuperTemplate;
-	protected long timestamp;
-	protected String outputPattern;
-	protected String encoding;
-	protected boolean createPropertyNames;
-	protected boolean force; // force run generator
-
-	/**
-	 * @since 4.1
-	 */
-	protected boolean createPKProperties;
-
-	// runtime ivars
-	protected VelocityContext context;
-	protected Map<String, Template> templateCache;
-
-
-	public ClassGenerationAction() {
-        this.outputPattern = "*.java";
-        this.timestamp = 0L;
-        this.usePkgPath = true;
-        this.makePairs = true;
-        this.context = new VelocityContext();
-        this.templateCache = new HashMap<>(5);
-
-        this.artifacts = new ArrayList<>();
-        this.entityArtifacts = new ArrayList<>();
-        this.excludeEntityArtifacts = new ArrayList<>();
-        this.embeddableArtifacts = new ArrayList<>();
-        this.excludeEmbeddableArtifacts = new ArrayList<>();
-        this.artifactsGenerationMode = ArtifactsGenerationMode.ENTITY;
-
-        this.overwrite = false;
-		this.template = SUBCLASS_TEMPLATE;
-		this.superTemplate = SUPERCLASS_TEMPLATE;
-		this.embeddableTemplate = EMBEDDABLE_SUBCLASS_TEMPLATE;
-		this.embeddableSuperTemplate = EMBEDDABLE_SUPERCLASS_TEMPLATE;
-
-		this.queryTemplate = DATAMAP_SUBCLASS_TEMPLATE;
-		this.querySuperTemplate = DATAMAP_SUPERCLASS_TEMPLATE;
+	public ClassGenerationAction(CgenConfiguration cgenConfiguration) {
+		this.context = new VelocityContext();
+		this.templateCache = new HashMap<>(5);
+		this.cgenConfiguration = cgenConfiguration;
 	}
 
-	protected String defaultTemplateName(TemplateType type) {
+	public String defaultTemplateName(TemplateType type) {
 		switch (type) {
-		case ENTITY_SINGLE_CLASS:
-			return ClassGenerationAction.SINGLE_CLASS_TEMPLATE;
-		case ENTITY_SUBCLASS:
-			return ClassGenerationAction.SUBCLASS_TEMPLATE;
-		case ENTITY_SUPERCLASS:
-			return ClassGenerationAction.SUPERCLASS_TEMPLATE;
-		case EMBEDDABLE_SUBCLASS:
-			return ClassGenerationAction.EMBEDDABLE_SUBCLASS_TEMPLATE;
-		case EMBEDDABLE_SUPERCLASS:
-			return ClassGenerationAction.EMBEDDABLE_SUPERCLASS_TEMPLATE;
-		case EMBEDDABLE_SINGLE_CLASS:
-			return ClassGenerationAction.EMBEDDABLE_SINGLE_CLASS_TEMPLATE;
-		case DATAMAP_SINGLE_CLASS:
-			return ClassGenerationAction.DATAMAP_SINGLE_CLASS_TEMPLATE;
-		case DATAMAP_SUPERCLASS:
-			return ClassGenerationAction.DATAMAP_SUPERCLASS_TEMPLATE;
-		case DATAMAP_SUBCLASS:
-			return ClassGenerationAction.DATAMAP_SUBCLASS_TEMPLATE;
-		default:
-			throw new IllegalArgumentException("Invalid template type: " + type);
+			case ENTITY_SINGLE_CLASS:
+				return SINGLE_CLASS_TEMPLATE;
+			case ENTITY_SUBCLASS:
+				return SUBCLASS_TEMPLATE;
+			case ENTITY_SUPERCLASS:
+				return SUPERCLASS_TEMPLATE;
+			case EMBEDDABLE_SUBCLASS:
+				return EMBEDDABLE_SUBCLASS_TEMPLATE;
+			case EMBEDDABLE_SUPERCLASS:
+				return EMBEDDABLE_SUPERCLASS_TEMPLATE;
+			case EMBEDDABLE_SINGLE_CLASS:
+				return EMBEDDABLE_SINGLE_CLASS_TEMPLATE;
+			case DATAMAP_SINGLE_CLASS:
+				return DATAMAP_SINGLE_CLASS_TEMPLATE;
+			case DATAMAP_SUPERCLASS:
+				return DATAMAP_SUPERCLASS_TEMPLATE;
+			case DATAMAP_SUBCLASS:
+				return DATAMAP_SUBCLASS_TEMPLATE;
+			default:
+				throw new IllegalArgumentException("Invalid template type: " + type);
 		}
 	}
 
-	private String customTemplateName(TemplateType type) {
+	public String customTemplateName(TemplateType type) {
 		switch (type) {
-		case ENTITY_SINGLE_CLASS:
-			return template;
-		case ENTITY_SUBCLASS:
-			return template;
-		case ENTITY_SUPERCLASS:
-			return superTemplate;
-		case EMBEDDABLE_SINGLE_CLASS:
-			return embeddableTemplate;
-		case EMBEDDABLE_SUBCLASS:
-			return embeddableTemplate;
-		case EMBEDDABLE_SUPERCLASS:
-			return embeddableSuperTemplate;
-		case DATAMAP_SINGLE_CLASS:
-			return queryTemplate;
-		case DATAMAP_SUPERCLASS:
-			return querySuperTemplate;
-		case DATAMAP_SUBCLASS:
-			return queryTemplate;
-		default:
-			throw new IllegalArgumentException("Invalid template type: " + type);
+			case ENTITY_SINGLE_CLASS:
+				return cgenConfiguration.getTemplate();
+			case ENTITY_SUBCLASS:
+				return cgenConfiguration.getTemplate();
+			case ENTITY_SUPERCLASS:
+				return cgenConfiguration.getSuperTemplate();
+			case EMBEDDABLE_SINGLE_CLASS:
+				return cgenConfiguration.getEmbeddableTemplate();
+			case EMBEDDABLE_SUBCLASS:
+				return cgenConfiguration.getEmbeddableTemplate();
+			case EMBEDDABLE_SUPERCLASS:
+				return cgenConfiguration.getEmbeddableSuperTemplate();
+			case DATAMAP_SINGLE_CLASS:
+				return cgenConfiguration.getQueryTemplate();
+			case DATAMAP_SUPERCLASS:
+				return cgenConfiguration.getQuerySuperTemplate();
+			case DATAMAP_SUBCLASS:
+				return cgenConfiguration.getQueryTemplate();
+			default:
+				throw new IllegalArgumentException("Invalid template type: " + type);
 		}
 	}
 
-	/**
-	 * VelocityContext initialization method called once per artifact.
-	 */
-	private void resetContextForArtifact(Artifact artifact) {
-		StringUtils stringUtils = StringUtils.getInstance();
+    /**
+     * VelocityContext initialization method called once per artifact.
+     */
+    public void resetContextForArtifact(Artifact artifact) {
+        StringUtils stringUtils = StringUtils.getInstance();
 
-		String qualifiedClassName = artifact.getQualifiedClassName();
-		String packageName = stringUtils.stripClass(qualifiedClassName);
-		String className = stringUtils.stripPackageName(qualifiedClassName);
+        String qualifiedClassName = artifact.getQualifiedClassName();
+        String packageName = stringUtils.stripClass(qualifiedClassName);
+        String className = stringUtils.stripPackageName(qualifiedClassName);
 
-		String qualifiedBaseClassName = artifact.getQualifiedBaseClassName();
-		String basePackageName = stringUtils.stripClass(qualifiedBaseClassName);
-		String baseClassName = stringUtils.stripPackageName(qualifiedBaseClassName);
+        String qualifiedBaseClassName = artifact.getQualifiedBaseClassName();
+        String basePackageName = stringUtils.stripClass(qualifiedBaseClassName);
+        String baseClassName = stringUtils.stripPackageName(qualifiedBaseClassName);
 
-		String superClassName = getSuperclassPrefix() + stringUtils.stripPackageName(qualifiedClassName);
+        String superClassName = SUPERCLASS_PREFIX + stringUtils.stripPackageName(qualifiedClassName);
 
-		String superPackageName = this.superPkg;
-		if (superPackageName == null) {
-			superPackageName = packageName + ".auto";
-		}
+        String superPackageName = cgenConfiguration.getSuperPkg();
+        if (superPackageName == null) {
+            superPackageName = packageName + ".auto";
+        }
 
-		context.put(Artifact.BASE_CLASS_KEY, baseClassName);
-		context.put(Artifact.BASE_PACKAGE_KEY, basePackageName);
+        context.put(Artifact.BASE_CLASS_KEY, baseClassName);
+        context.put(Artifact.BASE_PACKAGE_KEY, basePackageName);
 
-		context.put(Artifact.SUB_CLASS_KEY, className);
-		context.put(Artifact.SUB_PACKAGE_KEY, packageName);
+        context.put(Artifact.SUB_CLASS_KEY, className);
+        context.put(Artifact.SUB_PACKAGE_KEY, packageName);
 
-		context.put(Artifact.SUPER_CLASS_KEY, superClassName);
-		context.put(Artifact.SUPER_PACKAGE_KEY, superPackageName);
+        context.put(Artifact.SUPER_CLASS_KEY, superClassName);
+        context.put(Artifact.SUPER_PACKAGE_KEY, superPackageName);
 
-		context.put(Artifact.OBJECT_KEY, artifact.getObject());
-		context.put(Artifact.STRING_UTILS_KEY, stringUtils);
+        context.put(Artifact.OBJECT_KEY, artifact.getObject());
+        context.put(Artifact.STRING_UTILS_KEY, stringUtils);
 
-		context.put(Artifact.CREATE_PROPERTY_NAMES, createPropertyNames);
-		context.put(Artifact.CREATE_PK_PROPERTIES, createPKProperties);
-	}
+        context.put(Artifact.CREATE_PROPERTY_NAMES, cgenConfiguration.isCreatePropertyNames());
+        context.put(Artifact.CREATE_PK_PROPERTIES, cgenConfiguration.isCreatePKProperties());
+    }
 
 	/**
 	 * VelocityContext initialization method called once per each artifact and
@@ -221,11 +162,50 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 		artifact.postInitContext(context);
 	}
 
+	/**
+	 * Adds entities to the internal entity list.
+	 * @param entities collection
+	 *
+	 * @since 4.0 throws exception
+	 */
+	public void addEntities(Collection<ObjEntity> entities) {
+		if (entities != null) {
+			for (ObjEntity entity : entities) {
+				cgenConfiguration.addArtifact(new EntityArtifact(entity));
+			}
+		}
+	}
+
+	public void addEmbeddables(Collection<Embeddable> embeddables) {
+		if (embeddables != null) {
+			for (Embeddable embeddable : embeddables) {
+				cgenConfiguration.addArtifact(new EmbeddableArtifact(embeddable));
+			}
+		}
+	}
+
+	public void addQueries(Collection<QueryDescriptor> queries) {
+		if (cgenConfiguration.getArtifactsGenerationMode().equals(ArtifactsGenerationMode.ALL.getLabel())) {
+			// TODO: andrus 10.12.2010 - why not also check for empty query list??
+			// Or create a better API for enabling DataMapArtifact
+			if (queries != null) {
+				Artifact artifact = new DataMapArtifact(cgenConfiguration.getDataMap(), queries);
+				if(!cgenConfiguration.getArtifacts().contains(artifact)) {
+					cgenConfiguration.addArtifact(artifact);
+				}
+			}
+		}
+	}
+
 	public void prepareArtifacts() {
-		this.artifacts.clear();
-        addAllEntities();
-        addAllEmbeddables();
-        addQueries(dataMap.getQueryDescriptors());
+		cgenConfiguration.getArtifacts().clear();
+		addEntities(cgenConfiguration.getEntities().stream()
+				.map(entity -> cgenConfiguration.getDataMap().getObjEntity(entity))
+				.collect(Collectors.toList()));
+		addEmbeddables(cgenConfiguration.getEmbeddables().stream()
+				.map(embeddable -> cgenConfiguration.getDataMap().getEmbeddable(embeddable))
+				.collect(Collectors.toList()));
+		addQueries(cgenConfiguration.getDataMap().getQueryDescriptors());
     }
 
 	/**
@@ -236,14 +216,14 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 		validateAttributes();
 
 		try {
-			for (Artifact artifact : artifacts) {
+			for (Artifact artifact : cgenConfiguration.getArtifacts()) {
 				execute(artifact);
 			}
 		} finally {
 			// must reset engine at the end of class generator run to avoid
 			// memory
 			// leaks and stale templates
-			this.templateCache.clear();
+			templateCache.clear();
 		}
 	}
 
@@ -254,7 +234,7 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 
 		resetContextForArtifact(artifact);
 
-		ArtifactGenerationMode artifactMode = makePairs ? ArtifactGenerationMode.GENERATION_GAP
+		ArtifactGenerationMode artifactMode = cgenConfiguration.isMakePairs() ? ArtifactGenerationMode.GENERATION_GAP
 				: ArtifactGenerationMode.SINGLE_CLASS;
 
 		TemplateType[] templateTypes = artifact.getTemplateTypes(artifactMode);
@@ -307,10 +287,17 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 	 * Called internally from "execute".
 	 */
 	private void validateAttributes() {
-		Path dir = buildPath();
+		Path dir = cgenConfiguration.buildPath();
 		if (dir == null) {
 			throw new CayenneRuntimeException("'rootPath' attribute is missing.");
 		}
+		if(Files.notExists(dir)) {
+			try {
+				Files.createDirectories(dir);
+			} catch (IOException e) {
+				throw new CayenneRuntimeException("can't create directory");
+			}
+		}
 
 		if (!Files.isDirectory(dir)) {
 			throw new CayenneRuntimeException("'destDir' is not a directory.");
@@ -343,7 +330,7 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 		// return writer with specified encoding
 		FileOutputStream out = new FileOutputStream(outFile);
 
-		return (encoding != null) ? new OutputStreamWriter(out, encoding) : new OutputStreamWriter(out);
+		return (cgenConfiguration.getEncoding() != null) ? new OutputStreamWriter(out, cgenConfiguration.getEncoding()) : new OutputStreamWriter(out);
 	}
 
 	/**
@@ -355,10 +342,10 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 		String packageName = (String) context.get(Artifact.SUPER_PACKAGE_KEY);
 		String className = (String) context.get(Artifact.SUPER_CLASS_KEY);
 
-		String filename = StringUtils.getInstance().replaceWildcardInStringWithString(WILDCARD, outputPattern, className);
-		File dest = new File(mkpath(new File(getDir()), packageName), filename);
+		String filename = StringUtils.getInstance().replaceWildcardInStringWithString(WILDCARD, cgenConfiguration.getOutputPattern(), className);
+		File dest = new File(mkpath(new File(cgenConfiguration.buildPath().toString()), packageName), filename);
 
-		if (dest.exists() && !fileNeedUpdate(dest, superTemplate)) {
+		if (dest.exists() && !fileNeedUpdate(dest, cgenConfiguration.getSuperTemplate())) {
 			return null;
 		}
 
@@ -374,21 +361,21 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 		String packageName = (String) context.get(Artifact.SUB_PACKAGE_KEY);
 		String className = (String) context.get(Artifact.SUB_CLASS_KEY);
 
-		String filename = StringUtils.getInstance().replaceWildcardInStringWithString(WILDCARD, outputPattern, className);
-		File dest = new File(mkpath(new File(Objects.requireNonNull(buildPath()).toString()), packageName), filename);
+		String filename = StringUtils.getInstance().replaceWildcardInStringWithString(WILDCARD, cgenConfiguration.getOutputPattern(), className);
+		File dest = new File(mkpath(new File(Objects.requireNonNull(cgenConfiguration.buildPath()).toString()), packageName), filename);
 
 		if (dest.exists()) {
 			// no overwrite of subclasses
-			if (makePairs) {
+			if (cgenConfiguration.isMakePairs()) {
 				return null;
 			}
 
 			// skip if said so
-			if (!overwrite) {
+			if (!cgenConfiguration.isOverwrite()) {
 				return null;
 			}
 
-			if (!fileNeedUpdate(dest, template)) {
+			if (!fileNeedUpdate(dest, cgenConfiguration.getTemplate())) {
 				return null;
 			}
 		}
@@ -402,7 +389,7 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 	 * last saved AND the template is older than the destination file
 	 */
 	protected boolean fileNeedUpdate(File dest, String templateFileName) {
-		if(force) {
+		if(cgenConfiguration.isForce()) {
 			return true;
 		}
 
@@ -421,7 +408,7 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 	 * Is file modified after internal timestamp (usually equal to mtime of datamap file)
 	 */
 	protected boolean isOld(File file) {
-		return file.lastModified() > timestamp;
+		return file.lastModified() > cgenConfiguration.getTimestamp();
 	}
 
 	/**
@@ -431,7 +418,7 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 	 */
 	private File mkpath(File dest, String pkgName) throws Exception {
 
-		if (!usePkgPath || pkgName == null) {
+		if (!cgenConfiguration.isUsePkgPath() || pkgName == null) {
 			return dest;
 		}
 
@@ -445,242 +432,6 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 	}
 
 	/**
-	 * Adds entities to the internal entity list.
-	 * @param entities collection
-	 *
-	 * @since 4.0 throws exception
-	 */
-	public void addEntities(Collection<ObjEntity> entities) {
-		if (entities != null) {
-			for (ObjEntity entity : entities) {
-				artifacts.add(new EntityArtifact(entity));
-			}
-		}
-	}
-
-	public void addEmbeddables(Collection<Embeddable> embeddables) {
-		if (embeddables != null) {
-			for (Embeddable embeddable : embeddables) {
-				artifacts.add(new EmbeddableArtifact(embeddable));
-			}
-		}
-	}
-
-	public void addQueries(Collection<QueryDescriptor> queries) {
-		if (artifactsGenerationMode == ArtifactsGenerationMode.ALL) {
-			// TODO: andrus 10.12.2010 - why not also check for empty query list??
-			// Or create a better API for enabling DataMapArtifact
-			if (queries != null) {
-				Artifact artifact = new DataMapArtifact(dataMap, queries);
-				if(!artifacts.contains(artifact)) {
-					artifacts.add(artifact);
-				}
-			}
-		}
-	}
-
-    private void addAllEntities() {
-		entityArtifacts.forEach(val -> {
-			Artifact artifact = new EntityArtifact(dataMap.getObjEntity(val));
-			if(!artifacts.contains(artifact)) {
-				artifacts.add(artifact);
-			}
-		});
-	}
-
-    private void addAllEmbeddables() {
-		embeddableArtifacts.forEach(val -> {
-			Artifact artifact = new EmbeddableArtifact(dataMap.getEmbeddable(val));
-			if(!artifacts.contains(artifact)) {
-				artifacts.add(artifact);
-			}
-		});
-	}
-
-    /**
-     * @since 4.1
-     */
-	public void loadEntity(String name) {
-		entityArtifacts.add(name);
-	}
-
-	/**
-	 * @since 4.1
-	 */
-	public void loadEmbeddable(String name) {
-		embeddableArtifacts.add(name);
-	}
-
-	public void setArtifactsGenerationMode(String mode) {
-		if (ArtifactsGenerationMode.ENTITY.getLabel().equalsIgnoreCase(mode)) {
-			this.artifactsGenerationMode = ArtifactsGenerationMode.ENTITY;
-		} else {
-			this.artifactsGenerationMode = ArtifactsGenerationMode.ALL;
-		}
-	}
-
-	public Path buildPath() {
-		return rootPath != null ? relPath != null ? rootPath.resolve(relPath).toAbsolutePath().normalize() : rootPath : null;
-	}
-
-	public void loadEntities(String entities) {
-		excludeEntityArtifacts.addAll(Arrays.asList(entities.split(",")));
-	}
-
-	public void resolveExcludeEntities() {
-		entityArtifacts = dataMap.getObjEntities()
-				.stream()
-				.filter(entity -> !excludeEntityArtifacts.contains(entity.getName()))
-				.map(ObjEntity::getName)
-				.collect(Collectors.toList());
-	}
-
-	public void loadEmbeddables(String embeddables) {
-		excludeEmbeddableArtifacts.addAll(Arrays.asList(embeddables.split(",")));
-	}
-
-	public void resolveExcludeEmbeddables() {
-    	embeddableArtifacts = dataMap.getEmbeddables()
-				.stream()
-				.filter(embeddable -> !excludeEmbeddableArtifacts.contains(embeddable.getClassName()))
-				.map(Embeddable::getClassName)
-				.collect(Collectors.toList());
-	}
-
-    public void resetCollections(){
-		this.embeddableArtifacts.clear();
-		this.entityArtifacts.clear();
-	}
-
-	private String getExcludeEntites() {
-		Collection<String> excludeEntities = dataMap.getObjEntities()
-				.stream()
-				.filter(entity -> !entityArtifacts.contains(entity.getName()))
-				.map(ObjEntity::getName)
-				.collect(Collectors.toList());
-		return org.apache.commons.lang3.StringUtils.join(excludeEntities, ",");
-	}
-
-	private String getExcludeEmbeddables() {
-		Collection<String> excludeEmbeddable = dataMap.getEmbeddables()
-				.stream()
-				.filter(embeddable -> !embeddableArtifacts.contains(embeddable.getClassName()))
-				.map(Embeddable::getClassName)
-				.collect(Collectors.toList());
-		return org.apache.commons.lang3.StringUtils.join(excludeEmbeddable, ",");
-	}
-
-	/**
-	 * Returns a String used to prefix class name to create a generated
-	 * superclass. Default value is "_".
-	 */
-	private String getSuperclassPrefix() {
-		return ClassGenerationAction.SUPERCLASS_PREFIX;
-	}
-
-	public Collection<String> getEmbeddables() {
-		return embeddableArtifacts;
-	}
-
-	/**
-	 * @since 4.1
-	 */
-	public boolean isCreatePKProperties() {
-		return createPKProperties;
-	}
-
-	public boolean isMakePairs() {
-		return makePairs;
-	}
-
-	public boolean isOverwrite() {
-		return overwrite;
-	}
-
-	public boolean isUsePkgPath() {
-		return usePkgPath;
-	}
-
-	public boolean isCreatePropertyNames() {
-		return createPropertyNames;
-	}
-
-	public String getOutputPattern() {
-		return outputPattern;
-	}
-
-	public String getSuperclassTemplate(){
-		return superTemplate;
-	}
-
-	public DataMap getDataMap() {
-		return dataMap;
-	}
-
-	public String getDir(){
-		return rootPath != null ? relPath != null ? rootPath.resolve(relPath).toAbsolutePath().normalize().toString() : rootPath.toString() : null;
-	}
-
-	public String getTemplate() {
-		return template;
-	}
-
-	public String getSuperPkg(){
-		return superPkg;
-	}
-
-	public Collection<String> getEntities() {
-		return entityArtifacts;
-	}
-
-	public String getRelPath() {
-    	if(relPath == null || relPath.toString().isEmpty()) {
-    		return ".";
-		}
-		return relPath.toString();
-	}
-
-	public String getArtifactsGenerationMode(){
-		return artifactsGenerationMode.getLabel();
-	}
-
-	public boolean isForce() {
-		return force;
-	}
-
-	public void setForce(boolean force) {
-		this.force = force;
-	}
-
-	public String getEncoding() {
-		return encoding;
-	}
-
-	public String getEmbeddableTemplate() {
-		return embeddableTemplate;
-	}
-
-	public String getEmbeddableSuperTemplate() {
-		return embeddableSuperTemplate;
-	}
-
-	public String getQueryTemplate() {
-		return queryTemplate;
-	}
-
-	public String getQuerySuperTemplate() {
-		return querySuperTemplate;
-	}
-
-	/**
-	 * Sets an optional shared nVelocityContext. Useful with tools like VPP that
-	 * can set custom values in the context, not known to Cayenne.
-	 */
-	public void setContext(VelocityContext context) {
-		this.context = context;
-	}
-
-	/**
 	 * Injects an optional logger that will be used to trace generated files at
 	 * the info level.
 	 */
@@ -688,132 +439,20 @@ public class ClassGenerationAction implements Serializable, XMLSerializable {
 		this.logger = logger;
 	}
 
-	public void setTimestamp(long timestamp) {
-		this.timestamp = timestamp;
+	public CgenConfiguration getCgenConfiguration() {
+		return cgenConfiguration;
 	}
 
 	/**
-	 * Sets file encoding. If set to null, default system encoding will be used.
-	 */
-	public void setEncoding(String encoding) {
-		this.encoding = encoding;
-	}
-
-	/**
-	 * Sets "superPkg" property value.
-	 */
-	public void setSuperPkg(String superPkg) {
-		this.superPkg = superPkg;
-	}
-
-	/**
-	 * @param dataMap The dataMap to set.
-	 */
-	public void setDataMap(DataMap dataMap) {
-		this.dataMap = dataMap;
-	}
-
-	public void setEmbeddableTemplate(String embeddableTemplate) {
-		this.embeddableTemplate = embeddableTemplate;
-	}
-
-	public void setEmbeddableSuperTemplate(String embeddableSuperTemplate) {
-		this.embeddableSuperTemplate = embeddableSuperTemplate;
-	}
-
-	/**
-	 * Sets <code>overwrite</code> property.
-	 */
-	public void setOverwrite(boolean overwrite) {
-		this.overwrite = overwrite;
-	}
-
-	/**
-	 * Sets <code>makepairs</code> property.
-	 */
-	public void setMakePairs(boolean makePairs) {
-		this.makePairs = makePairs;
-	}
-
-	/**
-	 * Sets <code>template</code> property.
-	 */
-	public void setTemplate(String template) {
-		this.template = template;
-	}
-
-	/**
-	 * Sets <code>superTemplate</code> property.
-	 */
-	public void setSuperTemplate(String superTemplate) {
-		this.superTemplate = superTemplate;
-	}
-
-	public void setQueryTemplate(String queryTemplate) {
-		this.queryTemplate = queryTemplate;
-	}
-
-	public void setQuerySuperTemplate(String querySuperTemplate) {
-		this.querySuperTemplate = querySuperTemplate;
-	}
-
-	/**
-	 * Sets <code>usepkgpath</code> property.
-	 */
-	public void setUsePkgPath(boolean usePkgPath) {
-		this.usePkgPath = usePkgPath;
-	}
-
-	/**
-	 * Sets <code>outputPattern</code> property.
-	 */
-	public void setOutputPattern(String outputPattern) {
-		this.outputPattern = outputPattern;
-	}
-
-	/**
-	 * Sets <code>createPropertyNames</code> property.
-	 */
-	public void setCreatePropertyNames(boolean createPropertyNames) {
-		this.createPropertyNames = createPropertyNames;
-	}
-
-	/**
-	 * @since 4.1
+	 * Sets an optional shared VelocityContext. Useful with tools like VPP that
+	 * can set custom values in the context, not known to Cayenne.
 	 */
-	public void setCreatePKProperties(boolean createPKProperties) {
-		this.createPKProperties = createPKProperties;
-	}
-
-	public void setRootPath(Path rootPath) {
-		this.rootPath = rootPath;
-	}
-
-	public void setRelPath(Path relPath) {
-		this.relPath = relPath;
+	public void setContext(VelocityContext context) {
+		this.context = context;
 	}
 
-	public void setRelPath(String path) {
-		this.relPath = rootPath.relativize(Paths.get(path));
+	public void setCgenConfiguration(CgenConfiguration cgenConfiguration) {
+		this.cgenConfiguration = cgenConfiguration;
 	}
 
-	@Override
-	public void encodeAsXML(XMLEncoder encoder, ConfigurationNodeVisitor delegate) {
-		encoder.start("cgen")
-				.attribute("xmlns", CgenExtension.NAMESPACE)
-				.simpleTag("excludeEntities", getExcludeEntites())
-				.simpleTag("excludeEmbeddables",getExcludeEmbeddables())
-				.simpleTag("outputDirectory", getRelPath())
-				.simpleTag("generationMode", this.artifactsGenerationMode.getLabel())
-				.simpleTag("subclassTemplate", this.template)
-				.simpleTag("superclassTemplate", this.superTemplate)
-				.simpleTag("outputPattern", this.outputPattern)
-				.simpleTag("makePairs", Boolean.toString(this.makePairs))
-				.simpleTag("usePkgPath", Boolean.toString(this.usePkgPath))
-				.simpleTag("overwriteSubclasses", Boolean.toString(this.overwrite))
-				.simpleTag("createPropertyNames", Boolean.toString(this.createPropertyNames))
-				.simpleTag("superPkg", this.superPkg)
-				.simpleTag("createPKProperties", Boolean.toString(this.createPKProperties))
-				.end();
-	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientClassGenerationAction.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientClassGenerationAction.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientClassGenerationAction.java
index c8880aa..b823c85 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientClassGenerationAction.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientClassGenerationAction.java
@@ -30,18 +30,27 @@ import java.util.Collection;
  */
 public class ClientClassGenerationAction extends ClassGenerationAction {
 
+    private static final String TEMPLATES_DIR_NAME = "templates/v4_1/";
     public static final String SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-subclass.vm";
     public static final String SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-superclass.vm";
     public static final String SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-singleclass.vm";
-    
+
     public static final String DMAP_SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-datamap-subclass.vm";
     public static final String DMAP_SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-datamap-superclass.vm";
-    public static final String DMAP_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-datamap-singleclass.vm";
+    public static final String DATAMAP_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + "client-datamap-singleclass.vm";
 
     public static final String CLIENT_SUPERCLASS_PREFIX = "_Client";
 
+    public ClientClassGenerationAction(CgenConfiguration cgenConfiguration) {
+        super(cgenConfiguration);
+        cgenConfiguration.setTemplate(SUBCLASS_TEMPLATE);
+        cgenConfiguration.setSuperTemplate(SUPERCLASS_TEMPLATE);
+        cgenConfiguration.setQueryTemplate(DMAP_SUBCLASS_TEMPLATE);
+        cgenConfiguration.setQuerySuperTemplate(DMAP_SUPERCLASS_TEMPLATE);
+    }
+
     @Override
-    protected String defaultTemplateName(TemplateType type) {
+    public String defaultTemplateName(TemplateType type) {
         switch (type) {
             case ENTITY_SUBCLASS:
                 return SUBCLASS_TEMPLATE;
@@ -51,18 +60,18 @@ public class ClientClassGenerationAction extends ClassGenerationAction {
                 return SINGLE_CLASS_TEMPLATE;
 
             case EMBEDDABLE_SUBCLASS:
-                return EMBEDDABLE_SUBCLASS_TEMPLATE;
+                return ClassGenerationAction.EMBEDDABLE_SUBCLASS_TEMPLATE;
             case EMBEDDABLE_SUPERCLASS:
-                return EMBEDDABLE_SUPERCLASS_TEMPLATE;
+                return ClassGenerationAction.EMBEDDABLE_SUPERCLASS_TEMPLATE;
             case EMBEDDABLE_SINGLE_CLASS:
-                return EMBEDDABLE_SINGLE_CLASS_TEMPLATE;
-            
+                return ClassGenerationAction.EMBEDDABLE_SINGLE_CLASS_TEMPLATE;
+
             case DATAMAP_SUPERCLASS:
-                return ClientClassGenerationAction.DMAP_SUPERCLASS_TEMPLATE;
+                return DMAP_SUPERCLASS_TEMPLATE;
             case DATAMAP_SUBCLASS:
-                return ClientClassGenerationAction.DMAP_SUBCLASS_TEMPLATE;
+                return DMAP_SUBCLASS_TEMPLATE;
             case DATAMAP_SINGLE_CLASS:
-                return DMAP_SINGLE_CLASS_TEMPLATE;
+                return DATAMAP_SINGLE_CLASS_TEMPLATE;
 
             default:
                 throw new IllegalArgumentException("Unsupported template type: " + type);
@@ -73,14 +82,14 @@ public class ClientClassGenerationAction extends ClassGenerationAction {
      * @since 4.0 throws exception
      */
     @Override
-    public void addEntities(Collection<ObjEntity> entities) throws CayenneRuntimeException {
-        if (!dataMap.isClientSupported()) {
+    public void addEntities(Collection<ObjEntity> entities) {
+        if (!cgenConfiguration.getDataMap().isClientSupported()) {
             throw new CayenneRuntimeException("Can't create client classes. Check client supported option on DataMap configuration.");
         }
         if (entities != null) {
             for (ObjEntity entity : entities) {
                 if (!entity.isServerOnly()) {
-                    artifacts.add(new ClientEntityArtifact(entity));
+                    cgenConfiguration.addArtifact(new ClientEntityArtifact(entity));
                 }
             }
         }
@@ -88,9 +97,9 @@ public class ClientClassGenerationAction extends ClassGenerationAction {
 
     @Override
     public void addQueries(Collection<QueryDescriptor> queries) {
-        if (artifactsGenerationMode == ArtifactsGenerationMode.ALL) {
+        if (cgenConfiguration.getArtifactsGenerationMode().equals(ArtifactsGenerationMode.ALL.getLabel())) {
             if (queries != null) {
-                artifacts.add(new ClientDataMapArtifact(dataMap, queries));
+                cgenConfiguration.addArtifact(new ClientDataMapArtifact(cgenConfiguration.getDataMap(), queries));
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
index 7883ca2..1f4dd5e 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenConfigHandler.java
@@ -20,7 +20,7 @@ package org.apache.cayenne.gen.xml;
 
 import org.apache.cayenne.configuration.xml.DataChannelMetaData;
 import org.apache.cayenne.configuration.xml.NamespaceAwareNestedTagHandler;
-import org.apache.cayenne.gen.ClassGenerationAction;
+import org.apache.cayenne.gen.CgenConfiguration;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 
@@ -33,23 +33,24 @@ public class CgenConfigHandler extends NamespaceAwareNestedTagHandler{
 
     public static final String CONFIG_TAG = "cgen";
 
-    private static final String OUTPUT_DIRECTORY_TAG = "outputDirectory";
-    private static final String GENERATION_MODE_TAG = "generationMode";
-    private static final String SUBCLASS_TEMPLATE_TAG = "subclassTemplate";
+    private static final String OUTPUT_DIRECTORY_TAG = "destDir";
+    private static final String GENERATION_MODE_TAG = "mode";
+    private static final String SUBCLASS_TEMPLATE_TAG = "template";
     private static final String SUPERCLASS_TEMPLATE_TAG = "superclassTemplate";
     private static final String OUTPUT_PATTERN_TAG = "outputPattern";
     private static final String MAKE_PAIRS_TAG = "makePairs";
     private static final String USE_PKG_PATH_TAG = "usePkgPath";
-    private static final String OVERWRITE_SUBCLASSES_TAG = "overwriteSubclasses";
+    private static final String OVERWRITE_SUBCLASSES_TAG = "overwrite";
     private static final String CREATE_PROPERTY_NAMES_TAG = "createPropertyNames";
     private static final String EXCLUDE_ENTITIES_TAG = "excludeEntities";
     private static final String EXCLUDE_EMBEDDABLES_TAG = "excludeEmbeddables";
     private static final String CREATE_PK_PROPERTIES = "createPKProperties";
+    private static final String CLIENT_TAG = "client";
 
     public static final String TRUE = "true";
 
     private DataChannelMetaData metaData;
-    private ClassGenerationAction configuration;
+    private CgenConfiguration configuration;
 
     CgenConfigHandler(NamespaceAwareNestedTagHandler parentHandler, DataChannelMetaData metaData) {
         super(parentHandler);
@@ -106,6 +107,9 @@ public class CgenConfigHandler extends NamespaceAwareNestedTagHandler{
             case CREATE_PK_PROPERTIES:
                 createPkPropertiesTag(data);
                 break;
+            case CLIENT_TAG:
+                createClient(data);
+                break;
         }
     }
 
@@ -249,8 +253,22 @@ public class CgenConfigHandler extends NamespaceAwareNestedTagHandler{
         }
     }
 
+    private void createClient(String data) {
+        if(data.trim().length() == 0) {
+            return;
+        }
+
+        if(configuration != null) {
+            if(data.equals(TRUE)) {
+                configuration.setClient(true);
+            } else {
+                configuration.setClient(false);
+            }
+        }
+    }
+
     private void createConfig() {
-        configuration = new ClassGenerationAction();
+        configuration = new CgenConfiguration();
         loaderContext.addDataMapListener(dataMap -> {
             configuration.setDataMap(dataMap);
             configuration.resolveExcludeEntities();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
index fc23e50..aa008b1 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/xml/CgenSaverDelegate.java
@@ -19,7 +19,7 @@
 package org.apache.cayenne.gen.xml;
 
 import org.apache.cayenne.configuration.xml.DataChannelMetaData;
-import org.apache.cayenne.gen.ClassGenerationAction;
+import org.apache.cayenne.gen.CgenConfiguration;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.project.extension.BaseSaverDelegate;
 
@@ -41,7 +41,7 @@ public class CgenSaverDelegate extends BaseSaverDelegate{
 
     @Override
     public Void visitDataMap(DataMap dataMap) {
-        ClassGenerationAction cgen = metaData.get(dataMap, ClassGenerationAction.class);
+        CgenConfiguration cgen = metaData.get(dataMap, CgenConfiguration.class);
         if(cgen != null){
             resolveOutputDir(cgen);
             encoder.nested(cgen, getParentDelegate());
@@ -49,8 +49,11 @@ public class CgenSaverDelegate extends BaseSaverDelegate{
         return null;
     }
 
-    private void resolveOutputDir(ClassGenerationAction classGenerationAction) {
-        Path prevPath = classGenerationAction.buildPath();
+    private void resolveOutputDir(CgenConfiguration cgenConfiguration) {
+        if(cgenConfiguration.getRootPath() == null) {
+            return;
+        }
+        Path prevPath = cgenConfiguration.buildPath();
         URL url = getBaseDirectory().getURL();
         if(url != null) {
             Path resourcePath = Paths.get(url.getPath());
@@ -59,9 +62,8 @@ public class CgenSaverDelegate extends BaseSaverDelegate{
             }
 
             if(prevPath != null && resourcePath.compareTo(prevPath) != 0) {
-                classGenerationAction.setRootPath(resourcePath);
                 Path relPath = resourcePath.relativize(prevPath);
-                classGenerationAction.setRelPath(relPath);
+                cgenConfiguration.setRelPath(relPath);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEmbeddableFilterAction.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEmbeddableFilterAction.java b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEmbeddableFilterAction.java
new file mode 100644
index 0000000..00ab16a
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEmbeddableFilterAction.java
@@ -0,0 +1,29 @@
+package org.apache.cayenne.tools;
+
+import org.apache.cayenne.dbsync.filter.NameFilter;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.Embeddable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+class CayenneGeneratorEmbeddableFilterAction {
+
+    private NameFilter nameFilter;
+
+    Collection<Embeddable> getFilteredEmbeddables(DataMap mainDataMap) {
+        Collection<Embeddable> embeddables = new ArrayList<>(mainDataMap.getEmbeddables());
+
+        // filter out excluded entities...
+
+        // note that unlike entity, embeddable is matched by class name as it doesn't
+        // have a symbolic name...
+        embeddables.removeIf(e -> !nameFilter.isIncluded(e.getClassName()));
+
+        return embeddables;
+    }
+
+    public void setNameFilter(NameFilter nameFilter) {
+        this.nameFilter = nameFilter;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
index 4d068d8..7d53536 100644
--- a/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/tools/CayenneGeneratorEntityFilterAction.java
@@ -26,7 +26,6 @@ import org.apache.cayenne.map.ObjEntity;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
 
 /**
  * Performs entity filtering to build a collection of entities that should be used in
@@ -43,17 +42,10 @@ class CayenneGeneratorEntityFilterAction {
         Collection<Embeddable> embeddables = new ArrayList<>(mainDataMap.getEmbeddables());
 
         // filter out excluded entities...
-        Iterator<Embeddable> it = embeddables.iterator();
 
-        while (it.hasNext()) {
-            Embeddable e = it.next();
-
-            // note that unlike entity, embeddable is matched by class name as it doesn't
-            // have a symbolic name...
-            if (!nameFilter.isIncluded(e.getClassName())) {
-                it.remove();
-            }
-        }
+        // note that unlike entity, embeddable is matched by class name as it doesn't
+        // have a symbolic name...
+        embeddables.removeIf(e -> !nameFilter.isIncluded(e.getClassName()));
 
         return embeddables;
     }
@@ -64,13 +56,7 @@ class CayenneGeneratorEntityFilterAction {
         Collection<ObjEntity> entities = new ArrayList<>(mainDataMap.getObjEntities());
 
         // filter out excluded entities...
-        Iterator<ObjEntity> it = entities.iterator();
-        while (it.hasNext()) {
-            ObjEntity e = it.next();
-            if (e.isGeneric() || client && !e.isClientAllowed() || !nameFilter.isIncluded(e.getName())) {
-                it.remove();
-            }
-        }
+        entities.removeIf(e -> e.isGeneric() || client && !e.isClientAllowed() || !nameFilter.isIncluded(e.getName()));
 
         return entities;
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/52ea45b5/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
index 721a129..89dfaaa 100644
--- a/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
+++ b/cayenne-cgen/src/test/java/org/apache/cayenne/gen/ClassGenerationActionTest.java
@@ -48,10 +48,13 @@ public class ClassGenerationActionTest {
 	protected ClassGenerationAction action;
 	protected Collection<StringWriter> writers;
 
+	protected CgenConfiguration cgenConfiguration;
+
 	@Before
 	public void setUp() throws Exception {
 		writers = new ArrayList<>(3);
-		action = new ClassGenerationAction() {
+		cgenConfiguration = new CgenConfiguration();
+		action = new ClassGenerationAction(cgenConfiguration) {
 
 			@Override
 			protected Writer openWriter(TemplateType templateType) throws Exception {
@@ -74,8 +77,8 @@ public class ClassGenerationActionTest {
 		ObjEntity testEntity1 = new ObjEntity("TE1");
 		testEntity1.setClassName("org.example.TestClass1");
 
-		action.setMakePairs(true);
-		action.setSuperPkg("org.example.auto");
+		cgenConfiguration.setMakePairs(true);
+		cgenConfiguration.setSuperPkg("org.example.auto");
 
 		List<String> generated = execute(new EntityArtifact(testEntity1));
 		assertNotNull(generated);
@@ -116,7 +119,7 @@ public class ClassGenerationActionTest {
 		relationship.setCollectionType("java.util.Map");
 		testEntity1.addRelationship(relationship);
 
-		action.setMakePairs(true);
+		cgenConfiguration.setMakePairs(true);
 
 		List<String> generated = execute(new EntityArtifact(testEntity1));
 		assertNotNull(generated);
@@ -143,7 +146,7 @@ public class ClassGenerationActionTest {
 		testEntity1.addAttribute(attr);
 		testEntity1.addAttribute(attr1);
 
-		action.setMakePairs(true);
+		cgenConfiguration.setMakePairs(true);
 
 		List<String> generated = execute(new EntityArtifact(testEntity1));
 		assertNotNull(generated);
@@ -213,7 +216,7 @@ public class ClassGenerationActionTest {
 
 		if (isClient) {
 
-			action = new ClientClassGenerationAction() {
+			action = new ClientClassGenerationAction(cgenConfiguration) {
 				@Override
 				protected Writer openWriter(TemplateType templateType) throws Exception {
 					StringWriter writer = new StringWriter();
@@ -225,7 +228,7 @@ public class ClassGenerationActionTest {
 
 		}
 
-		action.setMakePairs(true);
+		cgenConfiguration.setMakePairs(true);
 
 		List<String> generated = execute(new EntityArtifact(testEntity1));
 		assertNotNull(generated);
@@ -261,10 +264,10 @@ public class ClassGenerationActionTest {
 		File file = mock(File.class);
 		when(file.lastModified()).thenReturn(1000L);
 
-		action.setTimestamp(0);
+		cgenConfiguration.setTimestamp(0);
 		assertTrue(action.isOld(file));
 
-		action.setTimestamp(2000L);
+		cgenConfiguration.setTimestamp(2000L);
 		assertFalse(action.isOld(file));
 	}
 
@@ -273,23 +276,23 @@ public class ClassGenerationActionTest {
 		File file = mock(File.class);
 		when(file.lastModified()).thenReturn(1000L);
 
-		action.setTimestamp(0);
-		action.setForce(false);
+		cgenConfiguration.setTimestamp(0);
+		cgenConfiguration.setForce(false);
 
 		assertFalse(action.fileNeedUpdate(file, null));
 
-		action.setTimestamp(2000L);
-		action.setForce(false);
+		cgenConfiguration.setTimestamp(2000L);
+		cgenConfiguration.setForce(false);
 
 		assertTrue(action.fileNeedUpdate(file, null));
 
-		action.setTimestamp(0);
-		action.setForce(true);
+		cgenConfiguration.setTimestamp(0);
+		cgenConfiguration.setForce(true);
 
 		assertTrue(action.fileNeedUpdate(file, null));
 
-		action.setTimestamp(2000L);
-		action.setForce(true);
+		cgenConfiguration.setTimestamp(2000L);
+		cgenConfiguration.setForce(true);
 
 		assertTrue(action.fileNeedUpdate(file, null));
 	}