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