http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-ant/src/test/resources/testmap.map.xml
----------------------------------------------------------------------
diff --git a/cayenne-ant/src/test/resources/testmap.map.xml 
b/cayenne-ant/src/test/resources/testmap.map.xml
new file mode 100644
index 0000000..60b94a6
--- /dev/null
+++ b/cayenne-ant/src/test/resources/testmap.map.xml
@@ -0,0 +1,744 @@
+<?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="org.apache.cayenne.testdo.testmap"/>
+       <property name="defaultSuperclass" 
value="org.apache.cayenne.CayenneDataObject"/>
+       <property name="clientSupported" value="true"/>
+       <property name="defaultClientPackage" value="test.client"/>
+       <property name="defaultClientSuperclass" 
value="org.apache.cayenne.PersistentObject"/>
+       <procedure name="cayenne_tst_out_proc">
+               <procedure-parameter name="in_param" type="INTEGER" 
direction="in"/>
+               <procedure-parameter name="out_param" type="INTEGER" 
direction="out"/>
+       </procedure>
+       <procedure name="cayenne_tst_select_proc">
+               <procedure-parameter name="aName" type="VARCHAR" length="254" 
direction="in"/>
+               <procedure-parameter name="paintingPrice" type="INTEGER" 
direction="in"/>
+       </procedure>
+       <procedure name="cayenne_tst_upd_proc">
+               <procedure-parameter name="paintingPrice" type="INTEGER" 
direction="in"/>
+       </procedure>
+       <procedure name="cayenne_tst_upd_proc2">
+       </procedure>
+       <db-entity name="ARRAYS_ENTITY">
+               <db-attribute name="BYTE_ARRAY" type="VARBINARY" length="200"/>
+               <db-attribute name="BYTE_WRAPPER_ARRAY" type="VARBINARY" 
length="200"/>
+               <db-attribute name="CHAR_ARRAY" type="VARCHAR" length="200"/>
+               <db-attribute name="CHAR_WRAPPER_ARRAY" type="VARCHAR" 
length="200"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="ARTGROUP">
+               <db-attribute name="GROUP_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" isMandatory="true" 
length="100"/>
+               <db-attribute name="PARENT_GROUP_ID" type="INTEGER"/>
+       </db-entity>
+       <db-entity name="ARTIST">
+               <db-attribute name="ARTIST_ID" type="BIGINT" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="ARTIST_NAME" type="CHAR" isMandatory="true" 
length="254"/>
+               <db-attribute name="DATE_OF_BIRTH" type="DATE"/>
+       </db-entity>
+       <db-entity name="ARTIST_CT">
+               <db-attribute name="ARTIST_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="ARTIST_NAME" type="CHAR" isMandatory="true" 
length="254"/>
+               <db-attribute name="DATE_OF_BIRTH" type="DATE"/>
+       </db-entity>
+       <db-entity name="ARTIST_EXHIBIT">
+               <db-attribute name="ARTIST_ID" type="BIGINT" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="EXHIBIT_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="ARTIST_GROUP">
+               <db-attribute name="ARTIST_ID" type="BIGINT" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="GROUP_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="BIGDECIMAL_ENTITY">
+               <db-attribute name="BIGDECIMAL_FIELD" type="NUMERIC" 
length="12" scale="2"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="BIGINTEGER_ENTITY">
+               <db-attribute name="BIG_INTEGER_FIELD" type="BIGINT"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="BINARY_PK_TEST1">
+               <db-attribute name="BIN_ID" type="VARBINARY" 
isPrimaryKey="true" isMandatory="true" length="32"/>
+               <db-attribute name="NAME" type="VARCHAR" length="10"/>
+       </db-entity>
+       <db-entity name="BINARY_PK_TEST2">
+               <db-attribute name="DETAIL_NAME" type="VARCHAR" length="10"/>
+               <db-attribute name="FK_ID" type="VARBINARY" length="32"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="BIT_TEST">
+               <db-attribute name="BIT_COLUMN" type="BIT" isMandatory="true"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="BLOB_TEST">
+               <db-attribute name="BLOB_COL" type="BLOB"/>
+               <db-attribute name="BLOB_TEST_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="BOOLEAN_TEST">
+               <db-attribute name="BOOLEAN_COLUMN" type="BOOLEAN" 
isMandatory="true"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="CALENDAR_TEST">
+               <db-attribute name="CALENDAR_FIELD" type="TIMESTAMP"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="CHARACTER_ENTITY">
+               <db-attribute name="CHARACTER_FIELD" type="CHAR" length="1"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="CHAR_FK_TEST">
+               <db-attribute name="FK_COL" type="CHAR" length="10"/>
+               <db-attribute name="NAME" type="VARCHAR" length="100"/>
+               <db-attribute name="PK" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="CHAR_PK_TEST">
+               <db-attribute name="OTHER_COL" type="CHAR" length="10"/>
+               <db-attribute name="PK_COL" type="CHAR" isPrimaryKey="true" 
isMandatory="true" length="10"/>
+       </db-entity>
+       <db-entity name="CLOB_TEST">
+               <db-attribute name="CLOB_COL" type="CLOB"/>
+               <db-attribute name="CLOB_TEST_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="CLOB_TEST_RELATION">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="ID_CLOB" type="INTEGER" isMandatory="true"/>
+               <db-attribute name="VALUE" type="INTEGER"/>
+       </db-entity>
+       <db-entity name="COMPOUND_FK_TEST">
+               <db-attribute name="F_KEY1" type="VARCHAR" length="20"/>
+               <db-attribute name="F_KEY2" type="VARCHAR" length="20"/>
+               <db-attribute name="NAME" type="VARCHAR" length="255"/>
+               <db-attribute name="PKEY" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="COMPOUND_PK_TEST">
+               <db-attribute name="KEY1" type="VARCHAR" isPrimaryKey="true" 
isMandatory="true" length="20"/>
+               <db-attribute name="KEY2" type="VARCHAR" isPrimaryKey="true" 
isMandatory="true" length="20"/>
+               <db-attribute name="NAME" type="VARCHAR" length="255"/>
+       </db-entity>
+       <db-entity name="DATE_TEST">
+               <db-attribute name="DATE_COLUMN" type="DATE"/>
+               <db-attribute name="DATE_TEST_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="TIMESTAMP_COLUMN" type="TIMESTAMP"/>
+               <db-attribute name="TIME_COLUMN" type="TIME"/>
+       </db-entity>
+       <db-entity name="DECIMAL_PK_TST">
+               <db-attribute name="DECIMAL_PK" type="DECIMAL" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="100"/>
+       </db-entity>
+       <db-entity name="ENUM_ENTITY">
+               <db-attribute name="ENUM_ATTRIBUTE" type="VARCHAR" 
length="250"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="EXHIBIT">
+               <db-attribute name="CLOSING_DATE" type="TIMESTAMP" 
isMandatory="true"/>
+               <db-attribute name="EXHIBIT_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="GALLERY_ID" type="INTEGER" 
isMandatory="true"/>
+               <db-attribute name="OPENING_DATE" type="TIMESTAMP" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="EXTENDED_TYPE_TEST">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="200"/>
+       </db-entity>
+       <db-entity name="FLOAT_TEST">
+               <db-attribute name="FLOAT_COL" type="FLOAT"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="GALLERY">
+               <db-attribute name="GALLERY_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="GALLERY_NAME" type="VARCHAR" 
isMandatory="true" length="100"/>
+       </db-entity>
+       <db-entity name="GENERATED_COLUMN_COMP_KEY">
+               <db-attribute name="AUTO_PK" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="GENERATED_COLUMN" type="INTEGER" 
isPrimaryKey="true" isGenerated="true" isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="100"/>
+               <db-attribute name="PROPAGATED_PK" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="GENERATED_COLUMN_COMP_M">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="100"/>
+       </db-entity>
+       <db-entity name="GENERATED_COLUMN_DEP">
+               <db-attribute name="GENERATED_COLUMN_FK" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="100"/>
+       </db-entity>
+       <db-entity name="GENERATED_COLUMN_TEST">
+               <db-attribute name="GENERATED_COLUMN" type="INTEGER" 
isPrimaryKey="true" isGenerated="true" isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="250"/>
+       </db-entity>
+       <db-entity name="GENERATED_COLUMN_TEST2">
+               <db-attribute name="GENERATED_COLUMN" type="INTEGER" 
isPrimaryKey="true" isGenerated="true" isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="100"/>
+       </db-entity>
+       <db-entity name="GENERATED_F1">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="GENERATED_F2">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+       </db-entity>
+       <db-entity name="GENERATED_JOIN">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isGenerated="true" isMandatory="true"/>
+               <db-attribute name="ID1" type="INTEGER"/>
+               <db-attribute name="ID2" type="INTEGER"/>
+       </db-entity>
+       <db-entity name="LONG_ENTITY">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="LONG_FIELD" type="BIGINT"/>
+       </db-entity>
+       <db-entity name="MEANINGFUL_PK_DEP">
+               <db-attribute name="DESCR" type="VARCHAR" length="50"/>
+               <db-attribute name="MASTER_PK" type="INTEGER"/>
+               <db-attribute name="PK_ATTRIBUTE" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="MEANINGFUL_PK_TEST1">
+               <db-attribute name="DESCR" type="VARCHAR" length="50"/>
+               <db-attribute name="PK_ATTRIBUTE" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+       </db-entity>
+       <db-entity name="MIXED_PERSISTENCE_STRATEGY">
+               <db-attribute name="DESCRIPTION" type="VARCHAR" length="200"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="NAME" type="VARCHAR" length="200"/>
+       </db-entity>
+       <db-entity name="MIXED_PERSISTENCE_STRATEGY2">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="MASTER_ID" type="INTEGER"/>
+               <db-attribute name="NAME" type="VARCHAR" length="200"/>
+       </db-entity>
+       <db-entity name="NO_PK_TEST">
+               <db-attribute name="ATTRIBUTE1" type="INTEGER"/>
+       </db-entity>
+       <db-entity name="PAINTING">
+               <db-attribute name="ARTIST_ID" type="BIGINT"/>
+               <db-attribute name="ESTIMATED_PRICE" type="DECIMAL" length="10" 
scale="2"/>
+               <db-attribute name="GALLERY_ID" type="INTEGER"/>
+               <db-attribute name="PAINTING_DESCRIPTION" type="VARCHAR" 
length="255"/>
+               <db-attribute name="PAINTING_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="PAINTING_TITLE" type="VARCHAR" 
isMandatory="true" length="255"/>
+       </db-entity>
+       <db-entity name="PAINTING1">
+               <db-attribute name="ARTIST_ID" type="BIGINT"/>
+               <db-attribute name="ESTIMATED_PRICE" type="DECIMAL" length="10" 
scale="2"/>
+               <db-attribute name="GALLERY_ID" type="INTEGER"/>
+               <db-attribute name="PAINTING_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="PAINTING_TITLE" type="VARCHAR" 
isMandatory="true" length="255"/>
+       </db-entity>
+       <db-entity name="PAINTING_INFO">
+               <db-attribute name="IMAGE_BLOB" type="LONGVARBINARY"/>
+               <db-attribute name="PAINTING_ID" type="INTEGER" 
isPrimaryKey="true" isMandatory="true"/>
+               <db-attribute name="TEXT_REVIEW" type="LONGVARCHAR"/>
+       </db-entity>
+       <db-entity name="PRIMITIVES_TEST">
+               <db-attribute name="BOOLEAN_COLUMN" type="BOOLEAN"/>
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="INT_COLUMN" type="INTEGER"/>
+       </db-entity>
+       <db-entity name="SERIALIZABLE_ENTITY">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="SERIALIZABLE_FIELD" type="BLOB"/>
+       </db-entity>
+       <db-entity name="SMALLINT_TEST">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="SMALLINT_COL" type="SMALLINT"/>
+       </db-entity>
+       <db-entity name="TINYINT_TEST">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="TINYINT_COL" type="TINYINT"/>
+       </db-entity>
+       <db-entity name="TYPES_MAPPING_TEST1">
+               <db-attribute name="AAAID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="BIGINT_COLUMN" type="BIGINT"/>
+               <db-attribute name="BIT_COLUMN" type="BIT"/>
+               <db-attribute name="BOOLEAN_COLUMN" type="BOOLEAN"/>
+               <db-attribute name="CHAR_COLUMN" type="CHAR" length="254"/>
+               <db-attribute name="CLOB_COLUMN" type="CLOB"/>
+               <db-attribute name="DATE_COLUMN" type="DATE"/>
+               <db-attribute name="DECIMAL_COLUMN" type="DECIMAL" length="12" 
scale="5"/>
+               <db-attribute name="DOUBLE_COLUMN" type="DOUBLE" scale="7"/>
+               <db-attribute name="FLOAT_COLUMN" type="FLOAT" scale="3"/>
+               <db-attribute name="INTEGER_COLUMN" type="INTEGER"/>
+               <db-attribute name="LONGVARCHAR_COLUMN" type="LONGVARCHAR"/>
+               <db-attribute name="NUMERIC_COLUMN" type="NUMERIC" length="12" 
scale="5"/>
+               <db-attribute name="REAL_COLUMN" type="REAL" scale="5"/>
+               <db-attribute name="SMALLINT_COLUMN" type="SMALLINT"/>
+               <db-attribute name="TIMESTAMP_COLUMN" type="TIMESTAMP"/>
+               <db-attribute name="TIME_COLUMN" type="TIME"/>
+               <db-attribute name="TINYINT_COLUMN" type="TINYINT"/>
+               <db-attribute name="VARCHAR_COLUMN" type="VARCHAR" 
length="255"/>
+       </db-entity>
+       <db-entity name="TYPES_MAPPING_TEST2">
+               <db-attribute name="AAAID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="BINARY_COLUMN" type="BINARY" length="14"/>
+               <db-attribute name="BLOB_COLUMN" type="BLOB"/>
+               <db-attribute name="LONGVARBINARY_COLUMN" type="LONGVARBINARY"/>
+               <db-attribute name="VARBINARY_COLUMN" type="VARBINARY" 
length="1000"/>
+       </db-entity>
+       <db-entity name="UUID_TEST">
+               <db-attribute name="ID" type="INTEGER" isPrimaryKey="true" 
isMandatory="true"/>
+               <db-attribute name="UUID" type="VARCHAR" length="100"/>
+       </db-entity>
+       <obj-entity name="ArraysEntity" 
className="org.apache.cayenne.testdo.misc_types.ArraysEntity" 
dbEntityName="ARRAYS_ENTITY">
+               <obj-attribute name="byteArray" type="byte[]" 
db-attribute-path="BYTE_ARRAY"/>
+               <obj-attribute name="byteWrapperArray" type="java.lang.Byte[]" 
db-attribute-path="BYTE_WRAPPER_ARRAY"/>
+               <obj-attribute name="charArray" type="char[]" 
db-attribute-path="CHAR_ARRAY"/>
+               <obj-attribute name="charWrapperArray" 
type="java.lang.Character[]" db-attribute-path="CHAR_WRAPPER_ARRAY"/>
+       </obj-entity>
+       <obj-entity name="ArtGroup" 
className="org.apache.cayenne.testdo.testmap.ArtGroup" dbEntityName="ARTGROUP">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="Artist" 
className="org.apache.cayenne.testdo.testmap.Artist" dbEntityName="ARTIST">
+               <obj-attribute name="artistName" type="java.lang.String" 
db-attribute-path="ARTIST_NAME"/>
+               <obj-attribute name="dateOfBirth" type="java.util.Date" 
db-attribute-path="DATE_OF_BIRTH"/>
+       </obj-entity>
+       <obj-entity name="ArtistCallbackTest" 
className="org.apache.cayenne.testdo.testmap.ArtistCallbackTest" 
dbEntityName="ARTIST_CT" exclude-superclass-listeners="true" 
exclude-default-listeners="true">
+               <obj-attribute name="artistName" type="java.lang.String"/>
+               <obj-attribute name="dateOfBirth" type="java.util.Date"/>
+               <entity-listener 
class="org.apache.cayenne.testdo.testmap.EntityListenerObjEntity">
+                       <post-add method-name="prePersistEntityListener"/>
+                       <post-persist method-name="postPersistEntityListener"/>
+                       <pre-update method-name="preUpdateEntityListener"/>
+                       <post-update method-name="postUpdateEntityListener"/>
+                       <pre-remove method-name="preRemoveEntityListener"/>
+                       <post-remove method-name="postRemoveEntityListener"/>
+                       <post-load method-name="postLoadEntityListener"/>
+               </entity-listener>
+               <post-add method-name="prePersistEntityObjEntity"/>
+               <post-persist method-name="postPersistEntityObjEntity"/>
+               <pre-update method-name="preUpdateEntityObjEntity"/>
+               <post-update method-name="postUpdateEntityObjEntity"/>
+               <pre-remove method-name="preRemoveEntityObjEntity"/>
+               <post-remove method-name="postRemoveEntityObjEntity"/>
+               <post-load method-name="postLoadEntityObjEntity"/>
+       </obj-entity>
+       <obj-entity name="ArtistExhibit" 
className="org.apache.cayenne.testdo.testmap.ArtistExhibit" 
dbEntityName="ARTIST_EXHIBIT">
+       </obj-entity>
+       <obj-entity name="BigDecimalEntity" 
className="org.apache.cayenne.testdo.numeric_types.BigDecimalEntity" 
dbEntityName="BIGDECIMAL_ENTITY">
+               <obj-attribute name="bigDecimalField" 
type="java.math.BigDecimal" db-attribute-path="BIGDECIMAL_FIELD"/>
+       </obj-entity>
+       <obj-entity name="BigIntegerEntity" 
className="org.apache.cayenne.testdo.numeric_types.BigIntegerEntity" 
dbEntityName="BIGINTEGER_ENTITY">
+               <obj-attribute name="bigIntegerField" 
type="java.math.BigInteger" db-attribute-path="BIG_INTEGER_FIELD"/>
+       </obj-entity>
+       <obj-entity name="BinaryPKTest1" 
className="org.apache.cayenne.testdo.binary_pk.BinaryPKTest1" 
dbEntityName="BINARY_PK_TEST1">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="BinaryPKTest2" 
className="org.apache.cayenne.testdo.binary_pk.BinaryPKTest2" 
dbEntityName="BINARY_PK_TEST2">
+               <obj-attribute name="detailName" type="java.lang.String" 
db-attribute-path="DETAIL_NAME"/>
+       </obj-entity>
+       <obj-entity name="BitNumberTestEntity" 
className="org.apache.cayenne.testdo.numeric_types.BitNumberTestEntity" 
dbEntityName="BIT_TEST">
+               <obj-attribute name="bitColumn" type="java.lang.Integer" 
db-attribute-path="BIT_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="BitTestEntity" 
className="org.apache.cayenne.testdo.numeric_types.BitTestEntity" 
dbEntityName="BIT_TEST">
+               <obj-attribute name="bitColumn" type="java.lang.Boolean" 
db-attribute-path="BIT_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="BlobTestEntity" 
className="org.apache.cayenne.testdo.lob.BlobTestEntity" 
dbEntityName="BLOB_TEST">
+               <obj-attribute name="blobCol" type="byte[]" 
db-attribute-path="BLOB_COL"/>
+       </obj-entity>
+       <obj-entity name="BooleanTestEntity" 
className="org.apache.cayenne.testdo.numeric_types.BooleanTestEntity" 
dbEntityName="BOOLEAN_TEST">
+               <obj-attribute name="booleanColumn" type="java.lang.Boolean" 
db-attribute-path="BOOLEAN_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="CalendarEntity" 
className="org.apache.cayenne.testdo.date_time.CalendarEntity" 
dbEntityName="CALENDAR_TEST">
+               <obj-attribute name="calendarField" type="java.util.Calendar" 
db-attribute-path="CALENDAR_FIELD"/>
+       </obj-entity>
+       <obj-entity name="CharFkTestEntity" 
className="org.apache.cayenne.testdo.compound.CharFkTestEntity" 
dbEntityName="CHAR_FK_TEST">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="CharPkTestEntity" 
className="org.apache.cayenne.testdo.compound.CharPkTestEntity" 
dbEntityName="CHAR_PK_TEST">
+               <obj-attribute name="otherCol" type="java.lang.String" 
db-attribute-path="OTHER_COL"/>
+               <obj-attribute name="pkCol" type="java.lang.String" 
db-attribute-path="PK_COL"/>
+       </obj-entity>
+       <obj-entity name="CharacterEntity" 
className="org.apache.cayenne.testdo.misc_types.CharacterEntity" 
dbEntityName="CHARACTER_ENTITY">
+               <obj-attribute name="characterField" type="java.lang.Character" 
db-attribute-path="CHARACTER_FIELD"/>
+       </obj-entity>
+       <obj-entity name="ClobTestEntity" 
className="org.apache.cayenne.testdo.lob.ClobTestEntity" 
dbEntityName="CLOB_TEST">
+               <obj-attribute name="clobCol" type="java.lang.String" 
db-attribute-path="CLOB_COL"/>
+       </obj-entity>
+       <obj-entity name="ClobTestRelation" 
className="org.apache.cayenne.testdo.lob.ClobTestRelation" 
dbEntityName="CLOB_TEST_RELATION">
+               <obj-attribute name="id" type="java.lang.Integer" 
db-attribute-path="ID"/>
+               <obj-attribute name="value" type="java.lang.Integer" 
db-attribute-path="VALUE"/>
+       </obj-entity>
+       <obj-entity name="CompoundFkTestEntity" 
className="org.apache.cayenne.testdo.compound.CompoundFkTestEntity" 
dbEntityName="COMPOUND_FK_TEST">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="CompoundPainting" 
className="org.apache.cayenne.testdo.testmap.CompoundPainting" 
dbEntityName="PAINTING">
+               <obj-attribute name="artistName" type="java.lang.String" 
db-attribute-path="toArtist.ARTIST_NAME"/>
+               <obj-attribute name="estimatedPrice" 
type="java.math.BigDecimal" db-attribute-path="ESTIMATED_PRICE"/>
+               <obj-attribute name="galleryName" type="java.lang.String" 
db-attribute-path="toGallery.GALLERY_NAME"/>
+               <obj-attribute name="paintingTitle" type="java.lang.String" 
db-attribute-path="PAINTING_TITLE"/>
+               <obj-attribute name="textReview" type="java.lang.String" 
db-attribute-path="toPaintingInfo.TEXT_REVIEW"/>
+       </obj-entity>
+       <obj-entity name="CompoundPkTestEntity" 
className="org.apache.cayenne.testdo.compound.CompoundPkTestEntity" 
dbEntityName="COMPOUND_PK_TEST">
+               <obj-attribute name="key1" type="java.lang.String" 
db-attribute-path="KEY1"/>
+               <obj-attribute name="key2" type="java.lang.String" 
db-attribute-path="KEY2"/>
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="DateTestEntity" 
className="org.apache.cayenne.testdo.date_time.DateTestEntity" 
dbEntityName="DATE_TEST">
+               <obj-attribute name="dateColumn" type="java.util.Date" 
db-attribute-path="DATE_COLUMN"/>
+               <obj-attribute name="timeColumn" type="java.util.Date" 
db-attribute-path="TIME_COLUMN"/>
+               <obj-attribute name="timestampColumn" type="java.util.Date" 
db-attribute-path="TIMESTAMP_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="DecimalPKTest1" 
className="org.apache.cayenne.testdo.numeric_types.DecimalPKTest1" 
dbEntityName="DECIMAL_PK_TST">
+               <obj-attribute name="decimalPK" type="java.lang.Double" 
db-attribute-path="DECIMAL_PK"/>
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="DecimalPKTestEntity" 
className="org.apache.cayenne.testdo.numeric_types.DecimalPKTestEntity" 
dbEntityName="DECIMAL_PK_TST">
+               <obj-attribute name="decimalPK" type="java.math.BigDecimal" 
db-attribute-path="DECIMAL_PK"/>
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="EnumEntity" 
className="org.apache.cayenne.testdo.enum_test.EnumEntity" 
dbEntityName="ENUM_ENTITY">
+               <obj-attribute name="enumAttribute" 
type="org.apache.cayenne.testdo.enum_test.Enum1" 
db-attribute-path="ENUM_ATTRIBUTE"/>
+       </obj-entity>
+       <obj-entity name="Exhibit" 
className="org.apache.cayenne.testdo.testmap.Exhibit" dbEntityName="EXHIBIT">
+               <obj-attribute name="closingDate" type="java.util.Date" 
db-attribute-path="CLOSING_DATE"/>
+               <obj-attribute name="openingDate" type="java.util.Date" 
db-attribute-path="OPENING_DATE"/>
+       </obj-entity>
+       <obj-entity name="ExtendedTypeEntity" 
className="org.apache.cayenne.testdo.extended_type.ExtendedTypeEntity" 
dbEntityName="EXTENDED_TYPE_TEST">
+               <obj-attribute name="name" 
type="org.apache.cayenne.testdo.extended_type.StringET1" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="Gallery" 
className="org.apache.cayenne.testdo.testmap.Gallery" dbEntityName="GALLERY">
+               <obj-attribute name="galleryName" type="java.lang.String" 
db-attribute-path="GALLERY_NAME"/>
+       </obj-entity>
+       <obj-entity name="GeneratedColumnCompKey" 
className="org.apache.cayenne.testdo.generated.GeneratedColumnCompKey" 
dbEntityName="GENERATED_COLUMN_COMP_KEY">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="GeneratedColumnCompMaster" 
className="org.apache.cayenne.testdo.generated.GeneratedColumnCompMaster" 
dbEntityName="GENERATED_COLUMN_COMP_M">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="GeneratedColumnDep" 
className="org.apache.cayenne.testdo.generated.GeneratedColumnDep" 
dbEntityName="GENERATED_COLUMN_DEP">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="GeneratedColumnTest2" 
className="org.apache.cayenne.testdo.generated.GeneratedColumnTest2" 
dbEntityName="GENERATED_COLUMN_TEST2">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="GeneratedColumnTestEntity" 
className="org.apache.cayenne.testdo.generated.GeneratedColumnTestEntity" 
dbEntityName="GENERATED_COLUMN_TEST">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="GeneratedF1" 
className="org.apache.cayenne.testdo.generated.GeneratedF1" 
clientClassName="test.client.GeneratedF1" dbEntityName="GENERATED_F1" 
superClassName="org.apache.cayenne.CayenneDataObject" 
clientSuperClassName="org.apache.cayenne.PersistentObject">
+       </obj-entity>
+       <obj-entity name="GeneratedF2" 
className="org.apache.cayenne.testdo.generated.GeneratedF2" 
clientClassName="test.client.GeneratedF2" dbEntityName="GENERATED_F2" 
superClassName="org.apache.cayenne.CayenneDataObject" 
clientSuperClassName="org.apache.cayenne.PersistentObject">
+       </obj-entity>
+       <obj-entity name="LongEntity" 
className="org.apache.cayenne.testdo.numeric_types.LongEntity" 
dbEntityName="LONG_ENTITY">
+               <obj-attribute name="longField" type="java.lang.Long" 
db-attribute-path="LONG_FIELD"/>
+       </obj-entity>
+       <obj-entity name="MeaningfulGeneratedColumnTestEntity" 
className="org.apache.cayenne.testdo.testmap.MeaningfulGeneratedColumnTestEntity"
 dbEntityName="GENERATED_COLUMN_TEST">
+               <obj-attribute name="generatedColumn" type="java.lang.Integer" 
db-attribute-path="GENERATED_COLUMN"/>
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="MeaningfulPKDep" 
className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPKDep" 
dbEntityName="MEANINGFUL_PK_DEP">
+               <obj-attribute name="descr" type="java.lang.String" 
db-attribute-path="DESCR"/>
+       </obj-entity>
+       <obj-entity name="MeaningfulPKTest1" 
className="org.apache.cayenne.testdo.meaningful_pk.MeaningfulPKTest1" 
dbEntityName="MEANINGFUL_PK_TEST1">
+               <obj-attribute name="descr" type="java.lang.String" 
db-attribute-path="DESCR"/>
+               <obj-attribute name="pkAttribute" type="java.lang.Integer" 
db-attribute-path="PK_ATTRIBUTE"/>
+       </obj-entity>
+       <obj-entity name="MixedPersistenceStrategy" 
className="org.apache.cayenne.testdo.mixed_persistence_strategy.MixedPersistenceStrategy"
 dbEntityName="MIXED_PERSISTENCE_STRATEGY">
+               <obj-attribute name="description" type="java.lang.String" 
db-attribute-path="DESCRIPTION"/>
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="MixedPersistenceStrategy2" 
className="org.apache.cayenne.testdo.mixed_persistence_strategy.MixedPersistenceStrategy2"
 dbEntityName="MIXED_PERSISTENCE_STRATEGY2">
+               <obj-attribute name="name" type="java.lang.String" 
db-attribute-path="NAME"/>
+       </obj-entity>
+       <obj-entity name="NoPkTestEntity" 
className="org.apache.cayenne.testdo.no_pk.NoPkTestEntity" 
dbEntityName="NO_PK_TEST">
+               <obj-attribute name="attribute1" type="java.lang.Integer" 
db-attribute-path="ATTRIBUTE1"/>
+       </obj-entity>
+       <obj-entity name="Painting" 
className="org.apache.cayenne.testdo.testmap.Painting" dbEntityName="PAINTING" 
superClassName="org.apache.cayenne.testdo.testmap.ArtDataObject">
+               <obj-attribute name="estimatedPrice" 
type="java.math.BigDecimal" db-attribute-path="ESTIMATED_PRICE"/>
+               <obj-attribute name="paintingDescription" 
type="java.lang.String" db-attribute-path="PAINTING_DESCRIPTION"/>
+               <obj-attribute name="paintingTitle" type="java.lang.String" 
db-attribute-path="PAINTING_TITLE"/>
+       </obj-entity>
+       <obj-entity name="Painting1" 
className="org.apache.cayenne.testdo.testmap.Painting1" 
dbEntityName="PAINTING1">
+               <obj-attribute name="estimatedPrice" 
type="java.math.BigDecimal" db-attribute-path="ESTIMATED_PRICE"/>
+               <obj-attribute name="paintingTitle" type="java.lang.String" 
db-attribute-path="PAINTING_TITLE"/>
+       </obj-entity>
+       <obj-entity name="PaintingInfo" 
className="org.apache.cayenne.testdo.testmap.PaintingInfo" 
dbEntityName="PAINTING_INFO">
+               <obj-attribute name="imageBlob" type="byte[]" 
db-attribute-path="IMAGE_BLOB"/>
+               <obj-attribute name="textReview" type="java.lang.String" 
db-attribute-path="TEXT_REVIEW"/>
+       </obj-entity>
+       <obj-entity name="PrimitivesTestEntity" 
className="org.apache.cayenne.testdo.primitive.PrimitivesTestEntity" 
dbEntityName="PRIMITIVES_TEST">
+               <obj-attribute name="booleanColumn" type="boolean" 
db-attribute-path="BOOLEAN_COLUMN"/>
+               <obj-attribute name="intColumn" type="int" 
db-attribute-path="INT_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="ROArtist" 
className="org.apache.cayenne.testdo.testmap.ROArtist" readOnly="true" 
dbEntityName="ARTIST">
+               <obj-attribute name="artistName" type="java.lang.String" 
db-attribute-path="ARTIST_NAME"/>
+               <obj-attribute name="dateOfBirth" type="java.sql.Date" 
db-attribute-path="DATE_OF_BIRTH"/>
+       </obj-entity>
+       <obj-entity name="ROPainting" 
className="org.apache.cayenne.testdo.testmap.ROPainting" readOnly="true" 
dbEntityName="PAINTING">
+               <obj-attribute name="estimatedPrice" 
type="java.math.BigDecimal" db-attribute-path="ESTIMATED_PRICE"/>
+               <obj-attribute name="paintingTitle" type="java.lang.String" 
db-attribute-path="PAINTING_TITLE"/>
+       </obj-entity>
+       <obj-entity name="RWCompoundPainting" 
className="org.apache.cayenne.testdo.testmap.RWCompoundPainting" 
dbEntityName="PAINTING">
+               <obj-attribute name="estimatedPrice" 
type="java.math.BigDecimal" db-attribute-path="ESTIMATED_PRICE"/>
+               <obj-attribute name="paintingTitle" type="java.lang.String" 
db-attribute-path="PAINTING_TITLE"/>
+               <obj-attribute name="textReview" type="java.lang.String" 
db-attribute-path="toPaintingInfo.TEXT_REVIEW"/>
+       </obj-entity>
+       <obj-entity name="ReturnTypesMap1" 
className="org.apache.cayenne.testdo.return_types.ReturnTypesMap1" 
clientClassName="test.client.ReturnTypesMap1" 
dbEntityName="TYPES_MAPPING_TEST1" 
superClassName="org.apache.cayenne.CayenneDataObject" 
clientSuperClassName="org.apache.cayenne.PersistentObject">
+               <obj-attribute name="bigintColumn" type="java.lang.Long" 
db-attribute-path="BIGINT_COLUMN"/>
+               <obj-attribute name="bitColumn" type="java.lang.Boolean" 
db-attribute-path="BIT_COLUMN"/>
+               <obj-attribute name="booleanColumn" type="java.lang.Boolean" 
db-attribute-path="BOOLEAN_COLUMN"/>
+               <obj-attribute name="charColumn" type="java.lang.String" 
db-attribute-path="CHAR_COLUMN"/>
+               <obj-attribute name="clobColumn" type="java.lang.String" 
db-attribute-path="CLOB_COLUMN"/>
+               <obj-attribute name="dateColumn" type="java.util.Date" 
db-attribute-path="DATE_COLUMN"/>
+               <obj-attribute name="decimalColumn" type="java.math.BigDecimal" 
db-attribute-path="DECIMAL_COLUMN"/>
+               <obj-attribute name="doubleColumn" type="java.lang.Double" 
db-attribute-path="DOUBLE_COLUMN"/>
+               <obj-attribute name="floatColumn" type="java.lang.Float" 
db-attribute-path="FLOAT_COLUMN"/>
+               <obj-attribute name="integerColumn" type="java.lang.Integer" 
db-attribute-path="INTEGER_COLUMN"/>
+               <obj-attribute name="longvarcharColumn" type="java.lang.String" 
db-attribute-path="LONGVARCHAR_COLUMN"/>
+               <obj-attribute name="numericColumn" type="java.math.BigDecimal" 
db-attribute-path="NUMERIC_COLUMN"/>
+               <obj-attribute name="realColumn" type="java.lang.Float" 
db-attribute-path="REAL_COLUMN"/>
+               <obj-attribute name="smallintColumn" type="java.lang.Short" 
db-attribute-path="SMALLINT_COLUMN"/>
+               <obj-attribute name="timeColumn" type="java.util.Date" 
db-attribute-path="TIME_COLUMN"/>
+               <obj-attribute name="timestampColumn" type="java.util.Date" 
db-attribute-path="TIMESTAMP_COLUMN"/>
+               <obj-attribute name="tinyintColumn" type="java.lang.Byte" 
db-attribute-path="TINYINT_COLUMN"/>
+               <obj-attribute name="varcharColumn" type="java.lang.String" 
db-attribute-path="VARCHAR_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="ReturnTypesMap2" 
className="org.apache.cayenne.testdo.return_types.ReturnTypesMap2" 
clientClassName="test.client.ReturnTypesMap2" 
dbEntityName="TYPES_MAPPING_TEST2" 
superClassName="org.apache.cayenne.CayenneDataObject" 
clientSuperClassName="org.apache.cayenne.PersistentObject">
+               <obj-attribute name="binaryColumn" type="byte[]" 
db-attribute-path="BINARY_COLUMN"/>
+               <obj-attribute name="blobColumn" type="byte[]" 
db-attribute-path="BLOB_COLUMN"/>
+               <obj-attribute name="longvarbinaryColumn" type="byte[]" 
db-attribute-path="LONGVARBINARY_COLUMN"/>
+               <obj-attribute name="varbinaryColumn" type="byte[]" 
db-attribute-path="VARBINARY_COLUMN"/>
+       </obj-entity>
+       <obj-entity name="SerializableEntity" 
className="org.apache.cayenne.testdo.misc_types.SerializableEntity" 
dbEntityName="SERIALIZABLE_ENTITY">
+               <obj-attribute name="serializableField" 
type="org.apache.cayenne.MockSerializable" 
db-attribute-path="SERIALIZABLE_FIELD"/>
+       </obj-entity>
+       <obj-entity name="SmallintTestEntity" 
className="org.apache.cayenne.testdo.numeric_types.SmallintTestEntity" 
dbEntityName="SMALLINT_TEST">
+               <obj-attribute name="smallintCol" type="java.lang.Short" 
db-attribute-path="SMALLINT_COL"/>
+       </obj-entity>
+       <obj-entity name="SubPainting" 
className="org.apache.cayenne.testdo.testmap.SubPainting" 
dbEntityName="PAINTING">
+               <obj-attribute name="paintingTitle" type="java.lang.String" 
db-attribute-path="PAINTING_TITLE"/>
+       </obj-entity>
+       <obj-entity name="TinyintTestEntity" 
className="org.apache.cayenne.testdo.numeric_types.TinyintTestEntity" 
dbEntityName="TINYINT_TEST">
+               <obj-attribute name="tinyintCol" type="java.lang.Byte" 
db-attribute-path="TINYINT_COL"/>
+       </obj-entity>
+       <obj-entity name="UuidTestEntity" 
className="org.apache.cayenne.testdo.uuid.UuidTestEntity" 
dbEntityName="UUID_TEST">
+               <obj-attribute name="uuid" type="java.util.UUID" 
db-attribute-path="UUID"/>
+       </obj-entity>
+       <db-relationship name="artistGroupArray" source="ARTGROUP" 
target="ARTIST_GROUP" toMany="true">
+               <db-attribute-pair source="GROUP_ID" target="GROUP_ID"/>
+       </db-relationship>
+       <db-relationship name="toChildGroups" source="ARTGROUP" 
target="ARTGROUP" toMany="true">
+               <db-attribute-pair source="GROUP_ID" target="PARENT_GROUP_ID"/>
+       </db-relationship>
+       <db-relationship name="toParentGroup" source="ARTGROUP" 
target="ARTGROUP" toMany="false">
+               <db-attribute-pair source="PARENT_GROUP_ID" target="GROUP_ID"/>
+       </db-relationship>
+       <db-relationship name="artistExhibitArray" source="ARTIST" 
target="ARTIST_EXHIBIT" toDependentPK="true" toMany="true">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="artistGroupArray" source="ARTIST" 
target="ARTIST_GROUP" toMany="true">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="paintingArray" source="ARTIST" target="PAINTING" 
toMany="true">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="toArtist" source="ARTIST_EXHIBIT" 
target="ARTIST" toMany="false">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="toExhibit" source="ARTIST_EXHIBIT" 
target="EXHIBIT" toMany="false">
+               <db-attribute-pair source="EXHIBIT_ID" target="EXHIBIT_ID"/>
+       </db-relationship>
+       <db-relationship name="toArtist" source="ARTIST_GROUP" target="ARTIST" 
toMany="false">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="toGroup" source="ARTIST_GROUP" target="ARTGROUP" 
toMany="false">
+               <db-attribute-pair source="GROUP_ID" target="GROUP_ID"/>
+       </db-relationship>
+       <db-relationship name="binaryPKDetails" source="BINARY_PK_TEST1" 
target="BINARY_PK_TEST2" toMany="true">
+               <db-attribute-pair source="BIN_ID" target="FK_ID"/>
+       </db-relationship>
+       <db-relationship name="toBinaryPKMaster" source="BINARY_PK_TEST2" 
target="BINARY_PK_TEST1" toMany="false">
+               <db-attribute-pair source="FK_ID" target="BIN_ID"/>
+       </db-relationship>
+       <db-relationship name="toCharPK" source="CHAR_FK_TEST" 
target="CHAR_PK_TEST" toMany="false">
+               <db-attribute-pair source="FK_COL" target="PK_COL"/>
+       </db-relationship>
+       <db-relationship name="charFKs" source="CHAR_PK_TEST" 
target="CHAR_FK_TEST" toMany="true">
+               <db-attribute-pair source="PK_COL" target="FK_COL"/>
+       </db-relationship>
+       <db-relationship name="clob" source="CLOB_TEST" 
target="CLOB_TEST_RELATION" toMany="true">
+               <db-attribute-pair source="CLOB_TEST_ID" target="ID_CLOB"/>
+       </db-relationship>
+       <db-relationship name="CLOB_REL" source="CLOB_TEST_RELATION" 
target="CLOB_TEST" toMany="false">
+               <db-attribute-pair source="ID_CLOB" target="CLOB_TEST_ID"/>
+       </db-relationship>
+       <db-relationship name="toCompoundPk" source="COMPOUND_FK_TEST" 
target="COMPOUND_PK_TEST" toMany="false">
+               <db-attribute-pair source="F_KEY1" target="KEY1"/>
+               <db-attribute-pair source="F_KEY2" target="KEY2"/>
+       </db-relationship>
+       <db-relationship name="compoundFkArray" source="COMPOUND_PK_TEST" 
target="COMPOUND_FK_TEST" toMany="true">
+               <db-attribute-pair source="KEY1" target="F_KEY1"/>
+               <db-attribute-pair source="KEY2" target="F_KEY2"/>
+       </db-relationship>
+       <db-relationship name="artistExhibitArray" source="EXHIBIT" 
target="ARTIST_EXHIBIT" toDependentPK="true" toMany="true">
+               <db-attribute-pair source="EXHIBIT_ID" target="EXHIBIT_ID"/>
+       </db-relationship>
+       <db-relationship name="toGallery" source="EXHIBIT" target="GALLERY" 
toMany="false">
+               <db-attribute-pair source="GALLERY_ID" target="GALLERY_ID"/>
+       </db-relationship>
+       <db-relationship name="exhibitArray" source="GALLERY" target="EXHIBIT" 
toMany="true">
+               <db-attribute-pair source="GALLERY_ID" target="GALLERY_ID"/>
+       </db-relationship>
+       <db-relationship name="paintingArray" source="GALLERY" 
target="PAINTING" toMany="true">
+               <db-attribute-pair source="GALLERY_ID" target="GALLERY_ID"/>
+       </db-relationship>
+       <db-relationship name="toMaster" source="GENERATED_COLUMN_COMP_KEY" 
target="GENERATED_COLUMN_COMP_M" toMany="false">
+               <db-attribute-pair source="PROPAGATED_PK" target="ID"/>
+       </db-relationship>
+       <db-relationship name="toDetail" source="GENERATED_COLUMN_COMP_M" 
target="GENERATED_COLUMN_COMP_KEY" toDependentPK="true" toMany="true">
+               <db-attribute-pair source="ID" target="PROPAGATED_PK"/>
+       </db-relationship>
+       <db-relationship name="toMaster" source="GENERATED_COLUMN_DEP" 
target="GENERATED_COLUMN_TEST" toMany="false">
+               <db-attribute-pair source="GENERATED_COLUMN_FK" 
target="GENERATED_COLUMN"/>
+       </db-relationship>
+       <db-relationship name="toDep" source="GENERATED_COLUMN_TEST" 
target="GENERATED_COLUMN_DEP" toDependentPK="true" toMany="false">
+               <db-attribute-pair source="GENERATED_COLUMN" 
target="GENERATED_COLUMN_FK"/>
+       </db-relationship>
+       <db-relationship name="join" source="GENERATED_F1" 
target="GENERATED_JOIN" toMany="true">
+               <db-attribute-pair source="ID" target="ID1"/>
+       </db-relationship>
+       <db-relationship name="join" source="GENERATED_F2" 
target="GENERATED_JOIN" toMany="true">
+               <db-attribute-pair source="ID" target="ID2"/>
+       </db-relationship>
+       <db-relationship name="f1" source="GENERATED_JOIN" 
target="GENERATED_F1" toMany="false">
+               <db-attribute-pair source="ID1" target="ID"/>
+       </db-relationship>
+       <db-relationship name="f2" source="GENERATED_JOIN" 
target="GENERATED_F2" toMany="false">
+               <db-attribute-pair source="ID2" target="ID"/>
+       </db-relationship>
+       <db-relationship name="toMeaningfulPK" source="MEANINGFUL_PK_DEP" 
target="MEANINGFUL_PK_TEST1" toMany="false">
+               <db-attribute-pair source="MASTER_PK" target="PK_ATTRIBUTE"/>
+       </db-relationship>
+       <db-relationship name="meaningfulPKDepArray" 
source="MEANINGFUL_PK_TEST1" target="MEANINGFUL_PK_DEP" toMany="true">
+               <db-attribute-pair source="PK_ATTRIBUTE" target="MASTER_PK"/>
+       </db-relationship>
+       <db-relationship name="details" source="MIXED_PERSISTENCE_STRATEGY" 
target="MIXED_PERSISTENCE_STRATEGY2" toMany="true">
+               <db-attribute-pair source="ID" target="MASTER_ID"/>
+       </db-relationship>
+       <db-relationship name="master" source="MIXED_PERSISTENCE_STRATEGY2" 
target="MIXED_PERSISTENCE_STRATEGY" toMany="false">
+               <db-attribute-pair source="MASTER_ID" target="ID"/>
+       </db-relationship>
+       <db-relationship name="toArtist" source="PAINTING" target="ARTIST" 
toMany="false">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="toGallery" source="PAINTING" target="GALLERY" 
toMany="false">
+               <db-attribute-pair source="GALLERY_ID" target="GALLERY_ID"/>
+       </db-relationship>
+       <db-relationship name="toPaintingInfo" source="PAINTING" 
target="PAINTING_INFO" toDependentPK="true" toMany="false">
+               <db-attribute-pair source="PAINTING_ID" target="PAINTING_ID"/>
+       </db-relationship>
+       <db-relationship name="toArtist" source="PAINTING1" target="ARTIST" 
toMany="false">
+               <db-attribute-pair source="ARTIST_ID" target="ARTIST_ID"/>
+       </db-relationship>
+       <db-relationship name="painting" source="PAINTING_INFO" 
target="PAINTING" toMany="false">
+               <db-attribute-pair source="PAINTING_ID" target="PAINTING_ID"/>
+       </db-relationship>
+       <obj-relationship name="artistArray" source="ArtGroup" target="Artist" 
deleteRule="Nullify" db-relationship-path="artistGroupArray.toArtist"/>
+       <obj-relationship name="childGroupsArray" source="ArtGroup" 
target="ArtGroup" deleteRule="Nullify" db-relationship-path="toChildGroups"/>
+       <obj-relationship name="toParentGroup" source="ArtGroup" 
target="ArtGroup" deleteRule="Nullify" db-relationship-path="toParentGroup"/>
+       <obj-relationship name="artistExhibitArray" source="Artist" 
target="ArtistExhibit" deleteRule="Cascade" 
db-relationship-path="artistExhibitArray"/>
+       <obj-relationship name="groupArray" source="Artist" target="ArtGroup" 
deleteRule="Cascade" db-relationship-path="artistGroupArray.toGroup"/>
+       <obj-relationship name="paintingArray" source="Artist" 
target="Painting" deleteRule="Cascade" db-relationship-path="paintingArray"/>
+       <obj-relationship name="toArtist" source="ArtistExhibit" 
target="Artist" deleteRule="Nullify" db-relationship-path="toArtist"/>
+       <obj-relationship name="toExhibit" source="ArtistExhibit" 
target="Exhibit" deleteRule="Nullify" db-relationship-path="toExhibit"/>
+       <obj-relationship name="binaryPKDetails" source="BinaryPKTest1" 
target="BinaryPKTest2" db-relationship-path="binaryPKDetails"/>
+       <obj-relationship name="toBinaryPKMaster" source="BinaryPKTest2" 
target="BinaryPKTest1" db-relationship-path="toBinaryPKMaster"/>
+       <obj-relationship name="toCharPK" source="CharFkTestEntity" 
target="CharPkTestEntity" db-relationship-path="toCharPK"/>
+       <obj-relationship name="charFKs" source="CharPkTestEntity" 
target="CharFkTestEntity" db-relationship-path="charFKs"/>
+       <obj-relationship name="clobValue" source="ClobTestEntity" 
target="ClobTestRelation" db-relationship-path="clob"/>
+       <obj-relationship name="clobId" source="ClobTestRelation" 
target="ClobTestEntity" db-relationship-path="CLOB_REL"/>
+       <obj-relationship name="toCompoundPk" source="CompoundFkTestEntity" 
target="CompoundPkTestEntity" db-relationship-path="toCompoundPk"/>
+       <obj-relationship name="toArtist" source="CompoundPainting" 
target="Artist" deleteRule="Nullify" db-relationship-path="toArtist"/>
+       <obj-relationship name="toGallery" source="CompoundPainting" 
target="Gallery" deleteRule="Nullify" db-relationship-path="toGallery"/>
+       <obj-relationship name="toPaintingInfo" source="CompoundPainting" 
target="PaintingInfo" deleteRule="Cascade" 
db-relationship-path="toPaintingInfo"/>
+       <obj-relationship name="compoundFkArray" source="CompoundPkTestEntity" 
target="CompoundFkTestEntity" db-relationship-path="compoundFkArray"/>
+       <obj-relationship name="artistExhibitArray" source="Exhibit" 
target="ArtistExhibit" deleteRule="Cascade" 
db-relationship-path="artistExhibitArray"/>
+       <obj-relationship name="toGallery" source="Exhibit" target="Gallery" 
deleteRule="Nullify" db-relationship-path="toGallery"/>
+       <obj-relationship name="exhibitArray" source="Gallery" target="Exhibit" 
deleteRule="Cascade" db-relationship-path="exhibitArray"/>
+       <obj-relationship name="paintingArray" source="Gallery" 
target="Painting" deleteRule="Deny" db-relationship-path="paintingArray"/>
+       <obj-relationship name="toMaster" source="GeneratedColumnCompKey" 
target="GeneratedColumnCompMaster" db-relationship-path="toMaster"/>
+       <obj-relationship name="toDetail" source="GeneratedColumnCompMaster" 
target="GeneratedColumnCompKey" db-relationship-path="toDetail"/>
+       <obj-relationship name="toMaster" source="GeneratedColumnDep" 
target="GeneratedColumnTestEntity" db-relationship-path="toMaster"/>
+       <obj-relationship name="toDep" source="GeneratedColumnTestEntity" 
target="GeneratedColumnDep" db-relationship-path="toDep"/>
+       <obj-relationship name="f2" source="GeneratedF1" target="GeneratedF2" 
deleteRule="Nullify" db-relationship-path="join.f2"/>
+       <obj-relationship name="f1" source="GeneratedF2" target="GeneratedF1" 
deleteRule="Nullify" db-relationship-path="join.f1"/>
+       <obj-relationship name="toMeaningfulPK" source="MeaningfulPKDep" 
target="MeaningfulPKTest1" db-relationship-path="toMeaningfulPK"/>
+       <obj-relationship name="meaningfulPKDepArray" 
source="MeaningfulPKTest1" target="MeaningfulPKDep" 
db-relationship-path="meaningfulPKDepArray"/>
+       <obj-relationship name="details" source="MixedPersistenceStrategy" 
target="MixedPersistenceStrategy2" db-relationship-path="details"/>
+       <obj-relationship name="master" source="MixedPersistenceStrategy2" 
target="MixedPersistenceStrategy" db-relationship-path="master"/>
+       <obj-relationship name="toArtist" source="Painting" target="Artist" 
deleteRule="Nullify" db-relationship-path="toArtist"/>
+       <obj-relationship name="toGallery" source="Painting" target="Gallery" 
deleteRule="Nullify" db-relationship-path="toGallery"/>
+       <obj-relationship name="toPaintingInfo" source="Painting" 
target="PaintingInfo" deleteRule="Cascade" 
db-relationship-path="toPaintingInfo"/>
+       <obj-relationship name="toArtist" source="Painting1" target="Artist" 
deleteRule="Nullify" db-relationship-path="toArtist"/>
+       <obj-relationship name="painting" source="PaintingInfo" 
target="Painting" deleteRule="Nullify" db-relationship-path="painting"/>
+       <obj-relationship name="paintingArray" source="ROArtist" 
target="Painting" deleteRule="Deny" db-relationship-path="paintingArray"/>
+       <obj-relationship name="toArtist" source="ROPainting" target="Artist" 
deleteRule="Nullify" db-relationship-path="toArtist"/>
+       <query name="EjbqlQueryTest" type="EJBQLQuery">
+               <property name="cayenne.GenericSelectQuery.fetchingDataRows" 
value="true"/>
+               <property name="cayenne.GenericSelectQuery.cacheStrategy" 
value="SHARED_CACHE"/>
+               <ejbql><![CDATA[select a from Artist a]]></ejbql>
+       </query>
+       <query name="NonSelectingQuery" type="SQLTemplate" root="data-map" 
root-name="testmap">
+               <property name="cayenne.SQLTemplate.columnNameCapitalization" 
value="UPPER"/>
+               <sql><![CDATA[INSERT INTO PAINTING (PAINTING_ID, 
PAINTING_TITLE, ESTIMATED_PRICE)
+VALUES (512, 'No Painting Like This', 12.5)]]></sql>
+               <sql 
adapter-class="org.apache.cayenne.dba.db2.DB2Adapter"><![CDATA[INSERT INTO 
PAINTING (PAINTING_ID, PAINTING_TITLE, ESTIMATED_PRICE) VALUES (512, 'No 
Painting Like This', 12.5)]]></sql>
+       </query>
+       <query name="ObjectQuery" type="SelectQuery" root="obj-entity" 
root-name="Painting">
+               <qualifier><![CDATA[toArtist = $artist]]></qualifier>
+               <ordering><![CDATA[paintingTitle]]></ordering>
+       </query>
+       <query name="ParameterizedNonSelectingQuery" type="SQLTemplate" 
root="data-map" root-name="testmap">
+               <sql><![CDATA[INSERT INTO PAINTING (PAINTING_ID, 
PAINTING_TITLE, ESTIMATED_PRICE)
+VALUES (#bind($id), #bind($title), #bind($price))]]></sql>
+               <sql 
adapter-class="org.apache.cayenne.dba.db2.DB2Adapter"><![CDATA[INSERT INTO 
PAINTING (PAINTING_ID, PAINTING_TITLE, ESTIMATED_PRICE) values (#bind($id), 
#bind($title), #bind($price))]]></sql>
+       </query>
+       <query name="ParameterizedQueryWithLocalCache" type="SelectQuery" 
root="obj-entity" root-name="Artist">
+               <property name="cayenne.GenericSelectQuery.cacheStrategy" 
value="LOCAL_CACHE"/>
+               <qualifier><![CDATA[artistName like $name]]></qualifier>
+       </query>
+       <query name="ParameterizedQueryWithSharedCache" type="SelectQuery" 
root="obj-entity" root-name="Artist">
+               <property name="cayenne.GenericSelectQuery.cacheStrategy" 
value="SHARED_CACHE"/>
+               <qualifier><![CDATA[artistName like $name]]></qualifier>
+       </query>
+       <query name="ProcedureQuery" type="ProcedureQuery" root="procedure" 
root-name="cayenne_tst_select_proc" result-entity="Artist">
+       </query>
+       <query name="QueryWithLocalCache" type="SelectQuery" root="obj-entity" 
root-name="Artist">
+               <property name="cayenne.GenericSelectQuery.cacheStrategy" 
value="LOCAL_CACHE"/>
+       </query>
+       <query name="QueryWithOrdering" type="SelectQuery" root="obj-entity" 
root-name="Artist">
+               <ordering descending="true" 
ignore-case="true"><![CDATA[artistName]]></ordering>
+               <ordering><![CDATA[dateOfBirth]]></ordering>
+       </query>
+       <query name="QueryWithPrefetch" type="SelectQuery" root="obj-entity" 
root-name="Gallery">
+               <prefetch>paintingArray</prefetch>
+       </query>
+       <query name="QueryWithQualifier" type="SelectQuery" root="obj-entity" 
root-name="Artist">
+               <qualifier><![CDATA[artistName = $param1]]></qualifier>
+       </query>
+       <query name="QueryWithSharedCache" type="SelectQuery" root="obj-entity" 
root-name="Artist">
+               <property name="cayenne.GenericSelectQuery.cacheStrategy" 
value="SHARED_CACHE"/>
+       </query>
+       <query name="SelectDateTest" type="SQLTemplate" root="data-map" 
root-name="testmap">
+               <property name="cayenne.GenericSelectQuery.fetchingDataRows" 
value="true"/>
+               <property name="cayenne.SQLTemplate.columnNameCapitalization" 
value="UPPER"/>
+               <sql><![CDATA[SELECT * FROM DATE_TEST]]></sql>
+       </query>
+       <query name="SelectReturnTypesMap1" type="SQLTemplate" root="data-map" 
root-name="testmap">
+               <property name="cayenne.GenericSelectQuery.fetchingDataRows" 
value="true"/>
+               <property name="cayenne.SQLTemplate.columnNameCapitalization" 
value="UPPER"/>
+               <sql><![CDATA[SELECT * FROM TYPES_MAPPING_TEST1]]></sql>
+       </query>
+       <query name="SelectReturnTypesMap2" type="SQLTemplate" root="data-map" 
root-name="testmap">
+               <property name="cayenne.GenericSelectQuery.fetchingDataRows" 
value="true"/>
+               <property name="cayenne.SQLTemplate.columnNameCapitalization" 
value="UPPER"/>
+               <sql><![CDATA[SELECT * FROM TYPES_MAPPING_TEST2]]></sql>
+       </query>
+       <query name="SelectTestLower" type="SQLTemplate" root="data-map" 
root-name="testmap">
+               <property name="cayenne.GenericSelectQuery.fetchingDataRows" 
value="true"/>
+               <property name="cayenne.SQLTemplate.columnNameCapitalization" 
value="LOWER"/>
+               <sql><![CDATA[select * from ARTIST]]></sql>
+       </query>
+       <query name="SelectTestUpper" type="SQLTemplate" root="data-map" 
root-name="testmap">
+               <property name="cayenne.GenericSelectQuery.fetchingDataRows" 
value="true"/>
+               <property name="cayenne.SQLTemplate.columnNameCapitalization" 
value="UPPER"/>
+               <sql><![CDATA[select * from ARTIST]]></sql>
+       </query>
+</data-map>

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/pom.xml
----------------------------------------------------------------------
diff --git a/cayenne-cgen/pom.xml b/cayenne-cgen/pom.xml
new file mode 100644
index 0000000..7aa0d84
--- /dev/null
+++ b/cayenne-cgen/pom.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~   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.
+  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <artifactId>cayenne-parent</artifactId>
+        <groupId>org.apache.cayenne</groupId>
+        <version>4.0.M5-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>cayenne-cgen</artifactId>
+    <packaging>jar</packaging>
+    <name>cayenne-cgen: Cayenne Class Generation Tools</name>
+
+    <dependencies>
+        <!--
+        using org.apache.cayenne.project.validation.NameValidationHelper from 
cayenne-project
+        and org.apache.cayenne.dbsync.filter.NameFilter from cayenne-dbsync
+        -->
+        <dependency>
+            <groupId>org.apache.cayenne</groupId>
+            <artifactId>cayenne-dbsync</artifactId>
+            <version>${project.version}</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>commons-logging</groupId>
+            <artifactId>commons-logging</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity</artifactId>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <!-- This ensures LICENSE and NOTICE inclusion in all jars -->
+            <plugin>
+                <artifactId>maven-remote-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>process</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/Artifact.java
----------------------------------------------------------------------
diff --git a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/Artifact.java 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/Artifact.java
new file mode 100644
index 0000000..fcd9118
--- /dev/null
+++ b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/Artifact.java
@@ -0,0 +1,65 @@
+/*****************************************************************
+ *   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.gen;
+
+import org.apache.velocity.VelocityContext;
+
+/**
+ * Represents a class generation "artifact" which is a facade to a metadata 
object used
+ * for a given single generation template run.
+ * 
+ * @since 3.0
+ */
+public interface Artifact {
+
+    public static String STRING_UTILS_KEY = "stringUtils";
+    public static String IMPORT_UTILS_KEY = "importUtils";
+
+    /**
+     * Root object, such as ObjEntity or Embeddable, etc.
+     */
+    public static String OBJECT_KEY = "object";
+    public static String SUPER_CLASS_KEY = "superClassName";
+    public static String SUPER_PACKAGE_KEY = "superPackageName";
+    public static String SUB_CLASS_KEY = "subClassName";
+    public static String SUB_PACKAGE_KEY = "subPackageName";
+    public static String BASE_CLASS_KEY = "baseClassName";
+    public static String BASE_PACKAGE_KEY = "basePackageName";
+    public static String CREATE_PROPERTY_NAMES = "createPropertyNames";
+
+    TemplateType[] getTemplateTypes(ArtifactGenerationMode mode);
+
+    String getQualifiedBaseClassName();
+
+    String getQualifiedClassName();
+
+    /**
+     * Returns a mapping metadata object for this artifact.
+     */
+    Object getObject();
+
+    /**
+     * A callback method that allows each artifact to add its own special keys 
to the
+     * context. Invoked from
+     * {@link ClassGenerationAction#resetContextForArtifactTemplate(Artifact, 
TemplateType)},
+     * after the context is initialized by code generator, so this method can 
use
+     * predefined keys from the context.
+     */
+    void postInitContext(VelocityContext context);
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactGenerationMode.java
----------------------------------------------------------------------
diff --git 
a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactGenerationMode.java 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactGenerationMode.java
new file mode 100644
index 0000000..b0c20cc
--- /dev/null
+++ 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactGenerationMode.java
@@ -0,0 +1,28 @@
+/*****************************************************************
+ *   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.gen;
+
+/**
+ * Code generator execution mode for a single artifact.
+ * 
+ * @since 3.0
+ */
+public enum ArtifactGenerationMode {
+    SINGLE_CLASS, GENERATION_GAP
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactsGenerationMode.java
----------------------------------------------------------------------
diff --git 
a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactsGenerationMode.java
 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactsGenerationMode.java
new file mode 100644
index 0000000..e76c172
--- /dev/null
+++ 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ArtifactsGenerationMode.java
@@ -0,0 +1,40 @@
+/*****************************************************************
+ *   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.gen;
+
+/**
+ * Code generator execution mode for a collection of artifacts.
+ * 
+ * @since 3.0
+ */
+public enum ArtifactsGenerationMode {
+
+    // TODO: andrus 12/9/2007 - label names are old... need to call it 
something else...
+    DATAMAP("datamap"), ENTITY("entity"), ALL("all");
+
+    private String label;
+
+    private ArtifactsGenerationMode(String label) {
+        this.label = label;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/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
new file mode 100644
index 0000000..6c46977
--- /dev/null
+++ 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGenerationAction.java
@@ -0,0 +1,584 @@
+/*****************************************************************
+ *   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.gen;
+
+import org.apache.cayenne.CayenneRuntimeException;
+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.commons.logging.Log;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+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/";
+
+       public static final String SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME + 
"singleclass.vm";
+       public static final String SUBCLASS_TEMPLATE = TEMPLATES_DIR_NAME + 
"subclass.vm";
+       public static final String SUPERCLASS_TEMPLATE = TEMPLATES_DIR_NAME + 
"superclass.vm";
+
+       public static final String EMBEDDABLE_SINGLE_CLASS_TEMPLATE = 
TEMPLATES_DIR_NAME + "embeddable-singleclass.vm";
+       public static final String EMBEDDABLE_SUBCLASS_TEMPLATE = 
TEMPLATES_DIR_NAME + "embeddable-subclass.vm";
+       public static final String EMBEDDABLE_SUPERCLASS_TEMPLATE = 
TEMPLATES_DIR_NAME + "embeddable-superclass.vm";
+
+       public static final String DATAMAP_SINGLE_CLASS_TEMPLATE = 
TEMPLATES_DIR_NAME + "datamap-singleclass.vm";
+       public static final String DATAMAP_SUBCLASS_TEMPLATE = 
TEMPLATES_DIR_NAME + "datamap-subclass.vm";
+       public static final String DATAMAP_SUPERCLASS_TEMPLATE = 
TEMPLATES_DIR_NAME + "datamap-superclass.vm";
+
+       public static final String SUPERCLASS_PREFIX = "_";
+       private static final String WILDCARD = "*";
+
+       protected Collection<Artifact> artifacts;
+
+       protected String superPkg;
+       protected DataMap dataMap;
+
+       protected ArtifactsGenerationMode artifactsGenerationMode;
+       protected boolean makePairs;
+
+       protected Log logger;
+       protected File destDir;
+       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;
+
+       // runtime ivars
+       protected VelocityContext context;
+       protected Map<String, Template> templateCache;
+
+       public ClassGenerationAction() {
+               this.outputPattern = "*.java";
+               this.timestamp = System.currentTimeMillis();
+               this.usePkgPath = true;
+               this.makePairs = true;
+               this.context = new VelocityContext();
+               this.templateCache = new HashMap<>(5);
+
+               this.artifacts = new ArrayList<>();
+       }
+
+       protected 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);
+               }
+       }
+
+       protected String customTemplateName(TemplateType type) {
+               switch (type) {
+               case ENTITY_SINGLE_CLASS:
+                       return template;
+               case ENTITY_SUBCLASS:
+                       return template;
+               case ENTITY_SUPERCLASS:
+                       return superTemplate;
+               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);
+               }
+       }
+
+       /**
+        * Returns a String used to prefix class name to create a generated
+        * superclass. Default value is "_".
+        */
+       protected String getSuperclassPrefix() {
+               return ClassGenerationAction.SUPERCLASS_PREFIX;
+       }
+
+       /**
+        * VelocityContext initialization method called once per artifact.
+        */
+       protected void resetContextForArtifact(Artifact artifact) {
+               StringUtils stringUtils = StringUtils.getInstance();
+
+               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 superClassName = getSuperclassPrefix() + 
stringUtils.stripPackageName(qualifiedClassName);
+
+               String superPackageName = this.superPkg;
+               if (superPackageName == null) {
+                       superPackageName = packageName + ".auto";
+               }
+
+               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.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.CREATE_PROPERTY_NAMES, 
createPropertyNames);
+       }
+
+       /**
+        * VelocityContext initialization method called once per each artifact 
and
+        * template type combination.
+        */
+       protected void resetContextForArtifactTemplate(Artifact artifact, 
TemplateType templateType) {
+               context.put(Artifact.IMPORT_UTILS_KEY, new ImportUtils());
+               artifact.postInitContext(context);
+       }
+
+       /**
+        * Executes class generation once per each artifact.
+        */
+       public void execute() throws Exception {
+
+               validateAttributes();
+
+               try {
+                       for (Artifact artifact : artifacts) {
+                               execute(artifact);
+                       }
+               } finally {
+                       // must reset engine at the end of class generator run 
to avoid
+                       // memory
+                       // leaks and stale templates
+                       this.templateCache.clear();
+               }
+       }
+
+       /**
+        * Executes class generation for a single artifact.
+        */
+       protected void execute(Artifact artifact) throws Exception {
+
+               resetContextForArtifact(artifact);
+
+               ArtifactGenerationMode artifactMode = makePairs ? 
ArtifactGenerationMode.GENERATION_GAP
+                               : ArtifactGenerationMode.SINGLE_CLASS;
+
+               TemplateType[] templateTypes = 
artifact.getTemplateTypes(artifactMode);
+               for (TemplateType type : templateTypes) {
+
+                       try (Writer out = openWriter(type);) {
+                               if (out != null) {
+
+                                       
resetContextForArtifactTemplate(artifact, type);
+                                       getTemplate(type).merge(context, out);
+                               }
+                       }
+               }
+       }
+
+       protected Template getTemplate(TemplateType type) throws Exception {
+
+               String templateName = customTemplateName(type);
+               if (templateName == null) {
+                       templateName = defaultTemplateName(type);
+               }
+
+               // Velocity < 1.5 has some memory problems, so we will create a
+               // VelocityEngine
+               // every time, and store templates in an internal cache, to 
avoid
+               // uncontrolled
+               // memory leaks... Presumably 1.5 fixes it.
+
+               Template template = templateCache.get(templateName);
+
+               if (template == null) {
+
+                       Properties props = new Properties();
+
+                       // null logger that will prevent velocity.log from 
being generated
+                       props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, 
NullLogSystem.class.getName());
+                       props.put("resource.loader", "cayenne");
+                       props.put("cayenne.resource.loader.class", 
ClassGeneratorResourceLoader.class.getName());
+                       props.put("cayenne.resource.loader.cache", "false");
+
+                       VelocityEngine velocityEngine = new VelocityEngine();
+                       velocityEngine.init(props);
+
+                       template = velocityEngine.getTemplate(templateName);
+                       templateCache.put(templateName, template);
+               }
+
+               return template;
+       }
+
+       /**
+        * Validates the state of this class generator. Throws
+        * CayenneRuntimeException if it is in an inconsistent state. Called
+        * internally from "execute".
+        */
+       protected void validateAttributes() {
+               if (destDir == null) {
+                       throw new CayenneRuntimeException("'destDir' attribute 
is missing.");
+               }
+
+               if (!destDir.isDirectory()) {
+                       throw new CayenneRuntimeException("'destDir' is not a 
directory.");
+               }
+
+               if (!destDir.canWrite()) {
+                       throw new CayenneRuntimeException("Do not have write 
permissions for " + destDir);
+               }
+       }
+
+       /**
+        * Sets the destDir.
+        */
+       public void setDestDir(File destDir) {
+               this.destDir = destDir;
+       }
+
+       /**
+        * 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;
+       }
+
+       /**
+        * Opens a Writer to write generated output. Returned Writer is mapped 
to a
+        * filesystem file (although subclasses may override that). File 
location is
+        * determined from the current state of VelocityContext and the 
TemplateType
+        * passed as a parameter. Writer encoding is determined from the value 
of
+        * the "encoding" property.
+        */
+       protected Writer openWriter(TemplateType templateType) throws Exception 
{
+
+               File outFile = (templateType.isSuperclass()) ? 
fileForSuperclass() : fileForClass();
+               if (outFile == null) {
+                       return null;
+               }
+
+               if (logger != null) {
+                       String label = templateType.isSuperclass() ? 
"superclass" : "class";
+                       logger.info("Generating " + label + " file: " + 
outFile.getCanonicalPath());
+               }
+
+               // return writer with specified encoding
+               FileOutputStream out = new FileOutputStream(outFile);
+
+               return (encoding != null) ? new OutputStreamWriter(out, 
encoding) : new OutputStreamWriter(out);
+       }
+
+       /**
+        * Returns a target file where a generated superclass must be saved. If 
null
+        * is returned, class shouldn't be generated.
+        */
+       protected File fileForSuperclass() throws Exception {
+
+               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(destDir, packageName), filename);
+
+               // Ignore if the destination is newer than the map
+               // (internal timestamp), i.e. has been generated after the map 
was
+               // last saved AND the template is older than the destination 
file
+               if (dest.exists() && !isOld(dest)) {
+
+                       if (superTemplate == null) {
+                               return null;
+                       }
+
+                       File superTemplateFile = new File(superTemplate);
+                       if (superTemplateFile.lastModified() < 
dest.lastModified()) {
+                               return null;
+                       }
+               }
+
+               return dest;
+       }
+
+       /**
+        * Returns a target file where a generated class must be saved. If null 
is
+        * returned, class shouldn't be generated.
+        */
+       protected File fileForClass() throws Exception {
+
+               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(destDir, packageName), filename);
+
+               if (dest.exists()) {
+                       // no overwrite of subclasses
+                       if (makePairs) {
+                               return null;
+                       }
+
+                       // skip if said so
+                       if (!overwrite) {
+                               return null;
+                       }
+
+                       // Ignore if the destination is newer than the map
+                       // (internal timestamp), i.e. has been generated after 
the map was
+                       // last saved AND the template is older than the 
destination file
+                       if (!isOld(dest)) {
+
+                               if (template == null) {
+                                       return null;
+                               }
+
+                               File templateFile = new File(template);
+                               if (templateFile.lastModified() < 
dest.lastModified()) {
+                                       return null;
+                               }
+                       }
+               }
+
+               return dest;
+       }
+
+       /**
+        * Returns true if <code>file</code> parameter is older than internal
+        * timestamp of this class generator.
+        */
+       protected boolean isOld(File file) {
+               return file.lastModified() <= timestamp;
+       }
+
+       /**
+        * Returns a File object corresponding to a directory where files that
+        * belong to <code>pkgName</code> package should reside. Creates any 
missing
+        * diectories below <code>dest</code>.
+        */
+       protected File mkpath(File dest, String pkgName) throws Exception {
+
+               if (!usePkgPath || pkgName == null) {
+                       return dest;
+               }
+
+               String path = pkgName.replace('.', File.separatorChar);
+               File fullPath = new File(dest, path);
+               if (!fullPath.isDirectory() && !fullPath.mkdirs()) {
+                       throw new Exception("Error making path: " + fullPath);
+               }
+
+               return fullPath;
+       }
+
+       public void setTimestamp(long timestamp) {
+               this.timestamp = timestamp;
+       }
+
+       /**
+        * 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;
+       }
+
+       /**
+        * Adds entities to the internal entity list.
+        */
+       public void addEntities(Collection<ObjEntity> entities) {
+               if (artifactsGenerationMode == ArtifactsGenerationMode.ENTITY
+                               || artifactsGenerationMode == 
ArtifactsGenerationMode.ALL) {
+                       if (entities != null) {
+                               for (ObjEntity entity : entities) {
+                                       artifacts.add(new 
EntityArtifact(entity));
+                               }
+                       }
+               }
+       }
+
+       public void addEmbeddables(Collection<Embeddable> embeddables) {
+               if (artifactsGenerationMode == ArtifactsGenerationMode.ENTITY
+                               || artifactsGenerationMode == 
ArtifactsGenerationMode.ALL) {
+                       if (embeddables != null) {
+                               for (Embeddable embeddable : embeddables) {
+                                       artifacts.add(new 
EmbeddableArtifact(embeddable));
+                               }
+                       }
+               }
+       }
+
+       public void addQueries(Collection<QueryDescriptor> queries) {
+               if (artifactsGenerationMode == ArtifactsGenerationMode.DATAMAP
+                               || 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) {
+                               artifacts.add(new DataMapArtifact(dataMap, 
queries));
+                       }
+               }
+       }
+
+       /**
+        * Sets an optional shared VelocityContext. 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.
+        */
+       public void setLogger(Log logger) {
+               this.logger = logger;
+       }
+
+       public void setEmbeddableTemplate(String embeddableTemplate) {
+               this.embeddableTemplate = embeddableTemplate;
+       }
+
+       public void setEmbeddableSuperTemplate(String embeddableSuperTemplate) {
+               this.embeddableSuperTemplate = embeddableSuperTemplate;
+       }
+
+       public void setArtifactsGenerationMode(String mode) {
+               if 
(ArtifactsGenerationMode.ENTITY.getLabel().equalsIgnoreCase(mode)) {
+                       this.artifactsGenerationMode = 
ArtifactsGenerationMode.ENTITY;
+               } else if 
(ArtifactsGenerationMode.DATAMAP.getLabel().equalsIgnoreCase(mode)) {
+                       this.artifactsGenerationMode = 
ArtifactsGenerationMode.DATAMAP;
+               } else {
+                       this.artifactsGenerationMode = 
ArtifactsGenerationMode.ALL;
+               }
+       }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGeneratorResourceLoader.java
----------------------------------------------------------------------
diff --git 
a/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGeneratorResourceLoader.java
 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGeneratorResourceLoader.java
new file mode 100644
index 0000000..8e8a1ee
--- /dev/null
+++ 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClassGeneratorResourceLoader.java
@@ -0,0 +1,102 @@
+/*****************************************************************
+ *   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.gen;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
+
+/**
+ * Velocity template resource loader customized for Cayenne use. Supports 
loading
+ * templates from the thread ClassLoader and from relative and absolute paths.
+ * 
+ * @since 1.2
+ */
+// must be public top-level class as it is
+// instantiated via reflection by Velocity
+public class ClassGeneratorResourceLoader extends FileResourceLoader {
+
+    /**
+     * Returns resource as InputStream. First calls super implementation. If 
resource
+     * wasn't found, it attempts to load it from current directory or as an 
absolute path.
+     */
+    @Override
+    public synchronized InputStream getResourceStream(String name)
+            throws ResourceNotFoundException {
+
+        InputStream stream = loadFromRelativePath(name);
+        if (stream != null) {
+            return stream;
+        }
+
+        stream = loadFromAbsPath(name);
+        if (stream != null) {
+            return stream;
+        }
+
+        stream = loadFromThreadClassLoader(name);
+        if (stream != null) {
+            return stream;
+        }
+
+        stream = loadFromThisClassLoader(name);
+        if (stream != null) {
+            return stream;
+        }
+
+        throw new ResourceNotFoundException("Couldn't find resource '"
+                + name
+                + "'. Searched filesystem path and classpath");
+    }
+
+    protected InputStream loadFromRelativePath(String name) {
+        try {
+            return super.getResourceStream(name);
+        }
+        catch (ResourceNotFoundException rnfex) {
+            return null;
+        }
+    }
+
+    protected InputStream loadFromAbsPath(String name) {
+        try {
+            File file = new File(name);
+            return (file.canRead()) ? new BufferedInputStream(new 
FileInputStream(file
+                    .getAbsolutePath())) : null;
+
+        }
+        catch (FileNotFoundException fnfe) {
+            return null;
+        }
+    }
+
+    protected InputStream loadFromThreadClassLoader(String name) {
+        return 
Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
+    }
+
+    protected InputStream loadFromThisClassLoader(String name) {
+        return getClass().getClassLoader().getResourceAsStream(name);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/c63b6be2/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
new file mode 100644
index 0000000..c89b1eb
--- /dev/null
+++ 
b/cayenne-cgen/src/main/java/org/apache/cayenne/gen/ClientClassGenerationAction.java
@@ -0,0 +1,80 @@
+/*****************************************************************
+ *   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.gen;
+
+import java.util.Collection;
+
+import org.apache.cayenne.map.ObjEntity;
+import org.apache.cayenne.map.QueryDescriptor;
+
+/**
+ * @since 3.0
+ */
+public class ClientClassGenerationAction extends ClassGenerationAction {
+
+    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 DMAP_SINGLE_CLASS_TEMPLATE = TEMPLATES_DIR_NAME 
+ "client-datamap-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 CLIENT_SUPERCLASS_PREFIX = "_Client";
+
+    @Override
+    protected String defaultTemplateName(TemplateType type) {
+        switch (type) {
+            case ENTITY_SUBCLASS:
+                return ClientClassGenerationAction.SUBCLASS_TEMPLATE;
+            case ENTITY_SUPERCLASS:
+                return ClientClassGenerationAction.SUPERCLASS_TEMPLATE;
+            case EMBEDDABLE_SUBCLASS:
+                return EMBEDDABLE_SUBCLASS_TEMPLATE;
+            case EMBEDDABLE_SUPERCLASS:
+                return EMBEDDABLE_SUPERCLASS_TEMPLATE;
+            
+            case DATAMAP_SUPERCLASS:
+                return ClientClassGenerationAction.DMAP_SUPERCLASS_TEMPLATE;
+            case DATAMAP_SUBCLASS:
+                return ClientClassGenerationAction.DMAP_SUBCLASS_TEMPLATE;
+            default:
+                throw new IllegalArgumentException("Unsupported template type: 
" + type);
+        }
+    }
+
+    @Override
+    public void addEntities(Collection<ObjEntity> entities) {
+        if (entities != null) {
+            for (ObjEntity entity : entities) {
+                artifacts.add(new ClientEntityArtifact(entity));
+            }
+        }
+    }
+
+    @Override
+    public void addQueries(Collection<QueryDescriptor> queries) {
+        if (artifactsGenerationMode == ArtifactsGenerationMode.DATAMAP
+                || artifactsGenerationMode == ArtifactsGenerationMode.ALL) {
+            if (queries != null) {
+                artifacts.add(new ClientDataMapArtifact(dataMap, queries));
+            }
+        }
+    }
+}

Reply via email to