Thanks for your reply, Simon!
Simon wrote:
> It's still not clear to me what your data model is.
Well, "my" data model started as a 1:1 view of a database, where a table is an
entity and a column of a table is an attribute...
Now I advanced a bit in abstaction and you could think of an entity is just a
set of attributes. This can be a 1:1 view of a database table, this could be
a part of a table or this could be a set of selected columns of selected
tables. So you could think of an entity as a dynabean.
An application consists of many different dynabeans and if you want to create
different dynabeans with the same factory, you need some rules on how to
create a dynabean.
From my point of view, such a dynabean is just an "invisible link" between UI
and database, so to abstract this connection, you need some additional
information/rules for each side of the connection.
Well, that additional information about each side combined with some rules is
"my" model, and the config-file I process, is somewhat similar like a
model-file for torque.
Ah, I think one difficulity of "my" model could be, that I try to scan the
definition of the classes I actual use for the meta-model. It's a logical
circular reference.
Anyway, you could replace the names in your mind.
Ok, the mail will get somewhat big, but I try to include the code skeletons.
First of all, the model, the XML-file I gonna transform (explanation after the
content):
<?xml version="1.0" encoding="ISO-8859-1" ?>
<meta-model>
<map name="DBTypes">
<entry value="1" lable="postgres"/>
<entry value="2" lable="Oracle"/>
<entry value="3" lable="DB/2"/>
<entry value="4" lable="mySQL"/>
</map>
<map name="TableTypes">
<entry value="1" lable="normal"/>
<entry value="2" lable="fast"/>
<entry value="3" lable="secure"/>
<entry value="4" lable="temporary"/>
</map>
<map name="FldTypes">
<entry value="1" lable="boolean"/>
<entry value="2" lable="date"/>
<entry value="3" lable="datetime"/>
<entry value="4" lable="decimal"/>
<entry value="5" lable="foreignkey"/>
<entry value="6" lable="integer"/>
<entry value="7" label="rowid"/>
<entry value="8" lable="text"/>
<entry value="9" lable="time"/>
</map>
<attributes>
<eid/>
<text name="dbname" length="40" visLength="30"/>
<text name="dbprefix" length="4" visLength="4"/>
<text name="tsname" length="30" visLength="30"/>
<text name="tblname" length="30" visLength="30"/>
<text name="fldname" length="30" visLength="30"/>
<reference name="dbid" references="Database"/>
<reference name="tsid" references="Tablespace"/>
<reference name="tblid" references="Table"/>
<reference name="fldid" references="Field"/>
<reference name="dbtype" references="DBTypes" property="value"/>
<reference name="ttype" references="TableTypes" property="value"/>
<reference name="ftype" references="FldTypes" property="value"/>
<text name="path"/>
<text name="value"/>
<text name="stduser" length="25" visLength="15"/>
<text name="ipcre" length="30" visLength="30"/>
<text name="ipmod" length="30" visLength="30"/>
<datetime name="dtimecre"/>
<datetime name="dtimemod"/>
<integer name="modcnt"/>
<integer name="bsize" minValue="0"/>
<integer name="esize" minValue="0"/>
<integer name="flen" length="4" visLength="5" minValue="1"
maxValue="2000"/>
<integer name="dlen" length="1" visLength="2" minValue="0"
maxValue="9"/>
<integer name="vlen" length="2" visLength="3" minValue="0"
maxValue="99"/>
<boolean name="flauto"/>
<boolean name="flmand"/>
</attributes>
<entity name="Database">
<addAttribute name="rowid"/>
<addAttribute name="dbname">
<unique-index idx_number="1" idx_order="1"/>
</addAttribute>
<addAttribute name="dbprefix"/>
<addAttribute name="dbtype"/>
<addAttribute name="path"/>
<addAttribute name="stduser"/>
<addAttribute name="ipcre"/>
<addAttribute name="ipmod"/>
<addAttribute name="dtimecre"/>
<addAttribute name="dtimemod"/>
<addAttribute name="modcnt"/>
</entity>
<entity name="Tablespace">
<addAttribute name="rowid"/>
<addAttribute name="bsize"/>
<addAttribute name="esize"/>
<addAttribute name="dbid"/>
<addAttribute name="flauto"/>
<addAttribute name="path"/>
<addAttribute name="tsname"/>
<addAttribute name="ipcre"/>
<addAttribute name="ipmod"/>
<addAttribute name="dtimecre"/>
<addAttribute name="dtimemod"/>
<addAttribute name="modcnt"/>
</entity>
<entity name="Table">
<addAttribute name="rowid"/>
<addAttribute name="bsize"/>
<addAttribute name="esize"/>
<addAttribute name="dbid">
<unique-index idx_number="1" idx_order="1"/>
</addAttribute>
<addAttribute name="tblname">
<unique-index idx_number="1" idx_order="2"/>
</addAttribute>
<addAttribute name="tsid"/>
<addAttribute name="ttype"/>
<addAttribute name="ipcre"/>
<addAttribute name="ipmod"/>
<addAttribute name="dtimecre"/>
<addAttribute name="dtimemod"/>
<addAttribute name="modcnt"/>
</entity>
<entity name="Field">
<addAttribute name="rowid"/>
<addAttribute name="fldname"/>
<addAttribute name="ftype"/>
<addAttribute name="tblid"/>
<addAttribute name="flmand"/>
<addAttribute name="value"/>
<addAttribute name="flen"/>
<addAttribute name="dlen"/>
<addAttribute name="vlen"/>
<addAttribute name="ipcre"/>
<addAttribute name="ipmod"/>
<addAttribute name="dtimecre"/>
<addAttribute name="dtimemod"/>
<addAttribute name="modcnt"/>
</entity>
</meta-model>
Ok, lets move to the object/rules part step by step:
All definitions of the meta-model are added to a Catalog-instance, which is
created as a "DefinitionRoot" by the factory, before starting the scanner.
The Catalog also is the first instance added to the digester-stack.
class Catalog {
public void addSelectList(Map);
public void addEntityDefinition(EntityDefinition);
public void addAttributeDefinition(AbstractAttributeDefinition);
public void putDefinition(Definition definition){
if(definition instanceof EntityDefinition)
addEntityDefinition(definition);
else if(definition instanceof(AbstractAttributeDefinition))
addAttributeDefinition(definition);
}
}
The first subpattern is the map. A map is a list of items to satisfy a
foreignkey without a target table (will be displayed in a dropdown combo).
digester.addFactoryCreate(MAP_NODE, "MapDefinitionCreateFactory");
digester.addCallMethod(MAP_ENTRY_NODE, "put", 2,
new String[] { "java.lang.Integer", "java.lang.String" });
digester.addCallParam(MAP_ENTRY_NODE,0,"value");
digester.addCallParam(MAP_ENTRY_NODE,1,"lable");
digester.addSetNext(MAP_NODE, "addSelectList", MAP_CLASS);
Next subpattern is the attribute-section. (In my model, an attribute
definition does not depend on a surrounding entity-definition.)
Each (supported) attribute-type has a different pattern and creates another
AttributeDefinitionClass - Subclass of AbstractAttributeDefinition.
digester.addObjectCreate(BOOLEAN_NODE, BOOLEAN_CLASS);
digester.addSetProperties(BOOLEAN_NODE);
digester.addSetNext(BOOLEAN_NODE, "addAttributeDefinition", ATTRIBUTE_CLASS);
The AttributeDefinition is quite a fat class, with all properties, that could
be used in certain situation. As each type needs different information to
build an entry on a dynabean, a select- or an insert-statement or on the
UI-side, each AttributeDefinition-subclass holds the needed information.
All AttributeDefinitions are just beans.
At least the entity-definitions are processed. The entity just contains
references to the real attribute-definition and - for me - the
index-information is no property of the attribute, but of the entity. For me
the same attribute may be part of different entities and in one entity this
attribute is part on an index, but in the other entities it is not.
The rules for the entity-processing are as follows (with CallAncestorParamRule
being my own written rule-class):
digester.addFactoryCreate(ENTITY_NODE,"EntityDefinitionCreateFactory");
digester.addSetProperties(ENTITY_NODE);
digester.addCallMethod(ADD_ATTRIBUTE_NODE, "addAttribute", 1
, new String[] { "java.lang.String" });
digester.addCallParam(ADD_ATTRIBUTE_NODE,0,"name");
digester.addCallMethod(UINDEX_NODE, "putUniqueIndex", 3
, new String[] { "java.lang.Integer"
, "java.lang.Integer"
, "java.lang.String"});
digester.addCallParam(UINDEX_NODE, 0, "idx_number");
digester.addCallParam(UINDEX_NODE, 1, "idx_order");
digester.addRule(UINDEX_NODE, new CallAncestorParamRule(2, 1, 0));
digester.addSetNext(ENTITY_NODE, "putDefinition", ENTITY_CLASS);
With the EntityDefinitionCreateFactory I create an Entity with the parent
(Catalog) already set before any other processing takes place.
class EntityDefinition {
public void addAttribute(String attributeName) throws DefinitionException;
public void putUniqueIndex(Integer idxNr, Integer idxOrder, String
attributeName);
}
The addAttribute-method of the Entity queries the AttributeDefinition from the
Catalog. If found, the attribute is added to the entity, otherwise an
Exception is thrown.
The benefit of checking the existence of the attribute-definition at addition
and not with a separate function-call at the end of the entity-processing is,
that I get a line-number of the error-attribute with the digester-exception.
Finally the EntityDefinition is added to the Catalog with a call to
putDefinition(EntityDefinition)
Hope, I could clarify, what "my" model is and also hope, that the size of the
mail is not a problem.
regards Gero
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]