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.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
76 new CaptionPropertyResolver().execute(dbs, elementBuilder.getRdb2java());
77
78 new PackagePreparer().execute(result, new BasicPackaging(getProperties()));
79
80 pkBuilder.execute(dbs, elementBuilder.getRdb2java());
81
82 resolver.execute(result);
83
84 new DefaultValueBuilder().execute(result);
85
86 new EnumPropertyBuilder().execute(dbs, elementBuilder.getRdb2java(), this.getNaming());
87
88 new ExtendsResolver().execute(dbs, elementBuilder.getRdb2java());
89
90 new AssignableEntityResolver().execute(result);
91
92 referenceBuilder.execute(dbs, elementBuilder.getRdb2java());
93
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
208
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
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 }