View Javadoc

    1   /*
    2    * joey-gen and its relative products are published under the terms
    3    * of the Apache Software License.
    4    *
    5    * Created on 2004/08/14 20:48:18
    6    */
    7   package org.asyrinx.joey.gen.command.rdb2java.standard;
    8
    9   import java.util.HashMap;
    10  import java.util.Iterator;
    11  import java.util.Map;
    12
    13  import org.apache.commons.lang.StringUtils;
    14  import org.apache.commons.logging.Log;
    15  import org.apache.commons.logging.LogFactory;
    16  import org.asyrinx.joey.gen.command.java.JavaCommand;
    17  import org.asyrinx.joey.gen.command.rdb.RdbCommand;
    18  import org.asyrinx.joey.gen.command.rdb.StandardCommands;
    19  import org.asyrinx.joey.gen.command.rdb2java.NamingStrategy;
    20  import org.asyrinx.joey.gen.command.rdb2java.PackagingStrategy;
    21  import org.asyrinx.joey.gen.command.rdb2java.Rdb2JavaBuilder;
    22  import org.asyrinx.joey.gen.command.rdb2java.TypeMappingStrategy;
    23  import org.asyrinx.joey.gen.model.Element;
    24  import org.asyrinx.joey.gen.model.EnumerationEntry;
    25  import org.asyrinx.joey.gen.model.command.Command;
    26  import org.asyrinx.joey.gen.model.java.AppDomain;
    27  import org.asyrinx.joey.gen.model.java.Entity;
    28  import org.asyrinx.joey.gen.model.java.EntityKey;
    29  import org.asyrinx.joey.gen.model.java.EntityKeyEntry;
    30  import org.asyrinx.joey.gen.model.java.JavaEnumeration;
    31  import org.asyrinx.joey.gen.model.java.Property;
    32  import org.asyrinx.joey.gen.model.java.Reference;
    33  import org.asyrinx.joey.gen.model.java.ReferenceEntry;
    34  import org.asyrinx.joey.gen.model.java.ReferenceType;
    35  import org.asyrinx.joey.gen.model.java.Type;
    36  import org.asyrinx.joey.gen.model.java.classes.EmbeddedClassUtils;
    37  import org.asyrinx.joey.gen.model.rdb.Column;
    38  import org.asyrinx.joey.gen.model.rdb.Databases;
    39  import org.asyrinx.joey.gen.model.rdb.ForeignKey;
    40  import org.asyrinx.joey.gen.model.rdb.ForeignKeyEntry;
    41  import org.asyrinx.joey.gen.model.rdb.ForeignKeyType;
    42  import org.asyrinx.joey.gen.model.rdb.RdbEnumeration;
    43  import org.asyrinx.joey.gen.model.rdb.Table;
    44  import org.asyrinx.joey.gen.model.rdb.visitor.RdbTopDownVisitor;
    45  import org.asyrinx.joey.gen.model.rdb.visitor.RdbVisitorMock;
    46
    47  /***
    48   * @author akima
    49   */
    50  public class BasicBuilder implements Rdb2JavaBuilder {
    51
    52      /***
    53       *
    54       */
    55      public BasicBuilder() {
    56          super();
    57      }
    58
    59      private final JavaElementBuilder elementBuilder = new JavaElementBuilder();
    60
    61      private final JavaTypeResolver resolver = new JavaTypeResolver();
    62
    63      private final JavaReferenceBuilder referenceBuilder = new JavaReferenceBuilder();
    64
    65      private final JavaPrimaryKeyBuilder pkBuilder = new JavaPrimaryKeyBuilder();
    66
    67      public AppDomain execute(Databases dbs) {
    68
    69          final AppDomain result = new AppDomain();
    70          //
    71          final Command dbCommand = new StandardCommands();
    72          dbCommand.execute(dbs);
    73          //まずクラスとか基本要素を作る
    74          elementBuilder.execute(dbs, result, this.resolver);
    75          //CaptionPropertyを解決
    76          new CaptionPropertyResolver().execute(dbs, elementBuilder.getRdb2java());
    77          //パッケージ名を設定
    78          new PackagePreparer().execute(result, new BasicPackaging(getProperties()));
    79          //primary keyを設定。
    80          pkBuilder.execute(dbs, elementBuilder.getRdb2java());
    81          //クラスのTypeとしての参照を解決
    82          resolver.execute(result);
    83          //プロパティのデフォルト値を設定
    84          new DefaultValueBuilder().execute(result);
    85          //プロパティのEnumとの関係を設定
    86          new EnumPropertyBuilder().execute(dbs, elementBuilder.getRdb2java(), this.getNaming());
    87          //継承関係を解決
    88          new ExtendsResolver().execute(dbs, elementBuilder.getRdb2java());
    89          //派生クラスを解決
    90          new AssignableEntityResolver().execute(result);
    91          //クラス間の関係をFKを元に構築
    92          referenceBuilder.execute(dbs, elementBuilder.getRdb2java());
    93          //importを設定
    94          new ImportBuilder().execute(result);
    95          return result;
    96      }
    97
    98      /***
    99       * @return
    100      */
    101     public NamingStrategy getNaming() {
    102         return elementBuilder.getNaming();
    103     }
    104
    105     /***
    106      * @return
    107      */
    108     public TypeMappingStrategy getTypeMapping() {
    109         return elementBuilder.getTypeMapping();
    110     }
    111
    112     /***
    113      * @param naming
    114      */
    115     public void setNaming(NamingStrategy naming) {
    116         elementBuilder.setNaming(naming);
    117     }
    118
    119     /***
    120      * @param typeMapping
    121      */
    122     public void setTypeMapping(TypeMappingStrategy typeMapping) {
    123         elementBuilder.setTypeMapping(typeMapping);
    124     }
    125
    126     public Map getRdb2Java() {
    127         return elementBuilder.getRdb2java();
    128     }
    129
    130     /***
    131      * @return
    132      */
    133     public Map getJava2rdb() {
    134         return elementBuilder.getJava2rdb();
    135     }
    136
    137     private Map properties = null;
    138
    139     public Map getProperties() {
    140         return properties;
    141     }
    142
    143     public void setProperties(Map properties) {
    144         this.properties = properties;
    145     }
    146 }
    147
    148 class JavaElementBuilder extends RdbVisitorMock {
    149     private AppDomain appDomain = null;
    150
    151     private JavaTypeResolver resolver = null;
    152
    153     final Log log = LogFactory.getLog(this.getClass());
    154
    155     final Map java2rdb = new HashMap() {
    156         public Object put(Object key, Object value) {
    157             if (this.containsKey(key))
    158                 log.warn("java2rdb: key'" + key + "' was overriden.");
    159             return super.put(key, value);
    160         }
    161     };
    162
    163     private final Map rdb2java = new HashMap() {
    164         private String toName(Object obj) {
    165             if (obj instanceof Element)
    166                 return ((Element) obj).getFullName();
    167             else
    168                 return String.valueOf(obj);
    169         }
    170
    171         public Object remove(Object key) {
    172             final Object value = super.remove(key);
    173             if (value != null)
    174                 JavaElementBuilder.this.java2rdb.remove(value);
    175             return value;
    176         }
    177
    178         public Object put(Object key, Object value) {
    179             if (key == null)
    180                 log.warn("rdb2java: key was null. value =" + toName(value));
    181             if (value == null)
    182                 log.warn("rdb2java: value was null. key =" + toName(key));
    183             if (this.containsKey(key))
    184                 log.warn("rdb2java: key'" + key + "' was overriden.");
    185             JavaElementBuilder.this.java2rdb.put(value, key);
    186             return super.put(key, value);
    187         }
    188
    189     };
    190
    191     private NamingStrategy naming = new BasicNaming();
    192
    193     private TypeMappingStrategy typeMapping = new BasicTypeMapping();
    194
    195     public void execute(Databases databases, AppDomain domain, JavaTypeResolver typeResolver) {
    196         this.appDomain = domain;
    197         this.resolver = typeResolver;
    198         final RdbTopDownVisitor topDownVisitor = new RdbTopDownVisitor(this);
    199         topDownVisitor.visit(databases);
    200     }
    201
    202     public void visit(RdbEnumeration enum) {
    203         final JavaEnumeration result = new JavaEnumeration(this.appDomain, enum.getName(), enum.getValueType());
    204         result.setOriginal(enum);
    205         //
    206         result.setLabel(enum.getLabel());
    207         //この時点ではtemplate相当のデータが入っているかもしれない。あとでPackagePreparerで直す
    208         //result.setPackageName(packaging.toPackageName(enum));
    209         result.setDescription(enum.getDescription());
    210         result.setValueTypeObj(typeMapping.toJavaType(enum.getValueType()));
    211         result.getOptions().putAll(enum.getOptions());
    212         //
    213         for (Iterator i = enum.iterator(); i.hasNext();) {
    214             final EnumerationEntry entry = (EnumerationEntry) i.next();
    215             try {
    216                 result.add((EnumerationEntry) entry.clone());
    217             } catch (CloneNotSupportedException e) {
    218                 e.printStackTrace();
    219                 throw new UnsupportedOperationException(e.getMessage());
    220             }
    221         }
    222         rdb2java.put(enum, result);
    223         resolver.addType(result.getFullName(), result);
    224     }
    225
    226     public void visit(Table table) {
    227         final Entity result = new Entity(this.appDomain);
    228         result.setOriginal(table);
    229         //
    230         result.setName(naming.toClassName(table));
    231         //result.setPackageTemplate(packaging.toPackageName(table));
    232         result.setDescription(table.getDescription());
    233         result.setLabel(table.getLabel());
    234         result.getOptions().putAll(table.getOptions());
    235         //
    236         rdb2java.put(table, result);
    237         resolver.addType(result.getFullName(), result);
    238     }
    239
    240     public void visit(Column column) {
    241         final Entity owner = (Entity) rdb2java.get(column.getParent());
    242         final Property result = new Property(owner);
    243         result.setOriginal(column);
    244         //
    245         result.setName(naming.toPropertyName(column));
    246         result.setType(typeMapping.toJavaType(column));
    247         result.setPrimaryKey(column.isPrimaryKey());
    248         if (result.getType() == null) {
    249             JavaEnumeration enumeration = appDomain.getEnumerations().getEnumeration(column.getType());
    250             if (enumeration != null)
    251                 result.setType(enumeration);
    252         }
    253         result.setDefaultValue(column.getDefaultValue());
    254         result.setDescription(column.getDescription());
    255         result.setLabel(column.getLabel());
    256         result.setRequired(column.isRequired());
    257         result.setMaxLength(column.getSizeAsInt());
    258         result.setExtended(column.isExtended());
    259         result.getOptions().putAll(column.getOptions());
    260         //
    261         rdb2java.put(column, result);
    262     }
    263
    264     /***
    265      * @return Returns the naming.
    266      */
    267     public NamingStrategy getNaming() {
    268         return naming;
    269     }
    270
    271     /***
    272      * @param naming
    273      *            The naming to set.
    274      */
    275     public void setNaming(NamingStrategy naming) {
    276         this.naming = naming;
    277     }
    278
    279     /***
    280      * @return Returns the typeMapping.
    281      */
    282     public TypeMappingStrategy getTypeMapping() {
    283         return typeMapping;
    284     }
    285
    286     /***
    287      * @param typeMapping
    288      *            The typeMapping to set.
    289      */
    290     public void setTypeMapping(TypeMappingStrategy typeMapping) {
    291         this.typeMapping = typeMapping;
    292     }
    293
    294     /***
    295      * @return Returns the rdb2java.
    296      */
    297     public Map getRdb2java() {
    298         return rdb2java;
    299     }
    300
    301     /***
    302      * @return Returns the java2rdb.
    303      */
    304     public Map getJava2rdb() {
    305         return java2rdb;
    306     }
    307 }
    308
    309 class CaptionPropertyResolver extends RdbCommand {
    310
    311     private Map rdb2java = null;
    312
    313     public void execute(Databases databases, Map rdb2javaMap) {
    314         this.rdb2java = rdb2javaMap;
    315         new RdbTopDownVisitor(this).visit(databases);
    316     }
    317
    318     public void visit(Table table) {
    319         if (table.getCaptionColumn() == null)
    320             return;
    321         final Property property = (Property) rdb2java.get(table.getCaptionColumn());
    322         if (property == null)
    323             addError(table.getCaptionColumn(), "property was not found");
    324         final Entity ownerClass = (Entity) rdb2java.get(table);
    325         ownerClass.setCaptionProperty(property);
    326     }
    327
    328 }
    329
    330 class JavaTypeResolver extends JavaCommand {
    331     private final Map javaName2Type = new HashMap();
    332
    333     public void addType(String typeName, Type type) {
    334         this.javaName2Type.put(typeName, type);
    335     }
    336
    337     public Type getType(String typeName) {
    338         final Type result = (Type) this.javaName2Type.get(typeName);
    339         return (result != null) ? result : EmbeddedClassUtils.get(typeName);
    340     }
    341
    342     public void visit(JavaEnumeration enum) {
    343         if (enum.getValueTypeObj() != null)
    344             return;
    345         final Type type = getType(enum.getValueType());
    346         if (type == null) {
    347             addError(enum, "type[" + enum.getValueType() + "] is not found.");
    348             return;
    349         }
    350         enum.setValueTypeObj(type);
    351     }
    352
    353     public void visit(Property property) {
    354         if (property.getType() != null)
    355             return;
    356         final Type type = getType(property.getTypeName());
    357         if (type == null) {
    358             addError(property, "type[" + property.getTypeName() + "] is not found.");
    359             return;
    360         }
    361         property.setType(type);
    362     }
    363 }
    364
    365 class JavaPrimaryKeyBuilder extends RdbVisitorMock {
    366     private Map rdb2java = null;
    367
    368     public void execute(Databases databases, Map rdb2javaMap) {
    369         this.rdb2java = rdb2javaMap;
    370         new RdbTopDownVisitor(this).visit(databases);
    371     }
    372
    373     public void visit(Table table) {
    374         final Entity ownerClass = (Entity) rdb2java.get(table);
    375         if (table.getExtendsTable() != null)
    376             return;
    377         final EntityKey pk = new EntityKey(ownerClass, "pk");
    378         pk.setPrimaryKey(true);
    379         for (Iterator i = table.getColumns().iterator(); i.hasNext();) {
    380             final Column column = (Column) i.next();
    381             if (column.isPrimaryKey()) {
    382                 final Property property = (Property) rdb2java.get(column);
    383                 new EntityKeyEntry(pk, property);
    384             }
    385         }
    386     }
    387 }
    388
    389 class JavaReferenceBuilder extends RdbCommand {
    390     private Map rdb2java = null;
    391
    392     public void execute(Databases databases, Map rdb2javaMap) {
    393         this.rdb2java = rdb2javaMap;
    394         super.execute(databases);
    395     }
    396
    397     public void visit(ForeignKey foreignKey) {
    398         if (foreignKey.getType() == ForeignKeyType.EXTENDS) {
    399             rdb2java.remove(foreignKey);
    400             return;
    401         }
    402         final Table localTable = foreignKey.getParent();
    403         final Table foreignTable = foreignKey.getForeignTable();
    404         final Entity ownerClass = (Entity) rdb2java.get(localTable);
    405         final Entity referenceClass = (Entity) rdb2java.get(foreignTable);
    406         final Reference result = new Reference(ownerClass);
    407         result.setOriginal(foreignKey);
    408         result.setType(ReferenceType.get(foreignKey.getType().getName()));
    409         result.setLabel(foreignKey.getLabel());
    410         result.setReferenceClass(referenceClass);
    411         if (result.getOption(Reference.HIBERNATE_DIRECTION) == null) {
    412             //デフォルト双方向関連
    413             result.getOptions().put(Reference.HIBERNATE_DIRECTION, Reference.DIRECTION_BIDIRECTIONAL);
    414         }
    415         for (Iterator i = foreignKey.iterator(); i.hasNext();) {
    416             final ForeignKeyEntry entry = (ForeignKeyEntry) i.next();
    417             final Property local = (Property) rdb2java.get(entry.getLocalColumn());
    418             final Property foreign = (Property) rdb2java.get(entry.getForeignColumn());
    419             if (local == null) {
    420                 addError(foreignKey, "property for column '" + entry.getLocal() + "'" + entry.getLocalColumn()
    421                         + " not found.");
    422             }
    423             if (foreign == null)
    424                 addError(foreignKey, "column '" + entry.getForeign() + "' not found.");
    425             new ReferenceEntry(result, local, foreign);
    426         }
    427         rdb2java.put(foreignKey, result);
    428     }
    429
    430 }
    431
    432 class DefaultValueBuilder extends JavaCommand {
    433     public void visit(Property property) {
    434         if (property.getDefaultValue() != null)
    435             return;
    436         if (property.getType() == null) {
    437             addError(property, "type [" + property.getTypeName() + "] is not found", false);
    438             return;
    439         }
    440         property.setDefaultValue(property.getType().getCategory().getDefaultValue());
    441     }
    442 }
    443
    444 class EnumPropertyBuilder extends RdbCommand {
    445     private Map rdb2java = null;
    446
    447     private NamingStrategy naming = null;
    448
    449     public void execute(Databases databases, Map rdb2javaMap, NamingStrategy namingStrategy) {
    450         this.rdb2java = rdb2javaMap;
    451         this.naming = namingStrategy;
    452         new RdbTopDownVisitor(this).visit(databases);
    453     }
    454
    455     public void visit(Column column) {
    456         final Property property = (Property) rdb2java.get(column);
    457         if (StringUtils.isEmpty(column.getEnum()))
    458             return;
    459         property.setEnumPropertyName(naming.toEnumPropertyName(property.getName()));
    460         property.setEnumType(findEnum(column));
    461     }
    462
    463     protected JavaEnumeration findEnum(Column column) {
    464         final RdbEnumeration rdbENum = column.getParent().getParent().getEnumerations()
    465                 .getEnumeration(column.getEnum());
    466         if (rdbENum == null) {
    467             addError(column, "enum [" + column.getEnum() + "] is not found.");
    468             return null;
    469         }
    470         final Object javaEnum = rdb2java.get(rdbENum);
    471         if (javaEnum == null) {
    472             addError(column, "rdbENum [" + rdbENum.getFullName() + "] has no mapped java class.");
    473             return null;
    474         }
    475         if (javaEnum instanceof JavaEnumeration) {
    476             return (JavaEnumeration) javaEnum;
    477         } else {
    478             addError(column, "enum [" + column.getEnum() + "] is not found.");
    479             return null;
    480         }
    481     }
    482 }
    483
    484 class PackagePreparer extends JavaCommand {
    485
    486     private PackagingStrategy packaging = null;
    487
    488     public void execute(AppDomain appDomain, PackagingStrategy packagingStrategy) {
    489         this.packaging = packagingStrategy;
    490         execute(appDomain);
    491     }
    492
    493     public void visit(Entity entity) {
    494         packaging.preparePackageNames(entity);
    495     }
    496
    497     public void visit(JavaEnumeration enum) {
    498         packaging.preparePackageName(enum);
    499     }
    500
    501 }
    502
    503 class ImportBuilder extends JavaCommand {
    504     public void visit(Entity entity) {
    505         for (Entity source = entity; source != null; source = source.getSuperClass()) {
    506             addImportByEntity(entity, source);
    507         }
    508     }
    509
    510     /***
    511      * @param entity
    512      */
    513     private void addImportByEntity(Entity entity, Entity source) {
    514         if (source.getSuperClass() != null) {
    515             addImport(entity, source.getSuperClass());
    516         }
    517         for (Iterator i = source.getProperties().iterator(); i.hasNext();) {
    518             final Property property = (Property) i.next();
    519             addImport(entity, property.getEnumType());
    520         }
    521         for (Iterator i = source.getReferences().iterator(); i.hasNext();) {
    522             final Reference reference = (Reference) i.next();
    523             addImport(entity, reference.getReferenceClass());
    524         }
    525         for (Iterator i = source.getReferreds().iterator(); i.hasNext();) {
    526             final Reference reference = (Reference) i.next();
    527             addImport(entity, reference.getParent());
    528         }
    529     }
    530
    531     /***
    532      * @param entity
    533      * @param type
    534      */
    535     private void addImport(Entity entity, final Type type) {
    536         if (type == null)
    537             return;
    538         if (!type.getPackage().equals(entity.getPackage()))
    539             entity.getImports().add(type.getFqn());
    540     }
    541 }
    542
    543 class ExtendsResolver extends RdbCommand {
    544
    545     private Map rdb2java = null;
    546
    547     public void execute(Databases databases, Map rdb2javaMap) {
    548         this.rdb2java = rdb2javaMap;
    549         new RdbTopDownVisitor(this).visit(databases);
    550     }
    551
    552     public void visit(Table table) {
    553         if (table.getExtendsTable() == null)
    554             return;
    555         final Entity subclass = (Entity) rdb2java.get(table);
    556         final Entity superclass = (Entity) rdb2java.get(table.getExtendsTable());
    557         subclass.setSuperClass(superclass);
    558     }
    559 }
    560
    561 class AssignableEntityResolver extends JavaCommand {
    562
    563     public void visit(Entity javaClass) {
    564         addToAssignableEntities(javaClass);
    565     }
    566
    567     private void addToAssignableEntities(Entity entity) {
    568         for (Entity current = entity; current != null; current = current.getSuperClass()) {
    569             current.getAssignableEntities().add(entity);
    570         }
    571     }
    572 }