1
2
3
4
5
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
81 new CaptionPropertyResolver().execute(dbs, elementBuilder.getRdb2java());
82
83 new PackagePreparer().execute(result, new BasicPackaging(getProperties()));
84
85 new JavaPrimaryKeyBuilder().execute(dbs, elementBuilder.getRdb2java());
86
87 new JavaIndexKeyBuilder().execute(dbs, elementBuilder.getRdb2java());
88
89 resolver.execute(result);
90
91 new DefaultValueBuilder().execute(result);
92
93 new EnumPropertyBuilder().execute(dbs, elementBuilder.getRdb2java(), this.getNaming());
94
95 new ExtendsResolver().execute(dbs, elementBuilder.getRdb2java());
96
97 new AssignableEntityResolver().execute(result);
98
99 referenceBuilder.execute(dbs, elementBuilder.getRdb2java());
100
101 new ImportBuilder().execute(result);
102
103
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
231
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
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 }