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 }