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