1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.javagen.revgen.visitor;
17
18 import org.javagen.agile.db.model.Cardinality;
19 import org.javagen.agile.db.model.Column;
20 import org.javagen.agile.db.model.FkConstraint;
21 import org.javagen.agile.db.model.Table;
22 import org.javagen.agile.oo.model.Class;
23 import org.javagen.agile.oo.model.Reference;
24 import org.javagen.revgen.context.Keys;
25
26 /***
27 * Traverses the database model in two steps and generates an entity model.
28 * <ol>
29 * <li>The first pass generates classes and properties from tables and columns.</li>
30 * <li>The second pass generates references from foreign key constraints.</li>
31 * </ol>
32 * Having two passes allows the model to be more easily manipulated between passes
33 * before data (ie names) are duplicated.
34 *
35 * @author Richard Easterling
36 */
37 public class DbTransformerPass2 extends DbTransformerPass1 {
38
39 private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(DbTransformerPass2.class);
40
41
42
43
44
45 public DbTransformerPass2() {
46 this.setItinerary(new String[] {FkConstraint.DEFAULT_MODEL_TYPE});
47 }
48
49 /***
50 * Convert foreign key constraint into class reference.
51 */
52 public void visit(FkConstraint fkConstraint) {
53 assert fkConstraint.getParentTable() != null;
54 if (fkConstraint.getChildModels() != null) {
55 if ( ! Boolean.TRUE.equals(fkConstraint.getParentTable().isLinkTable()) ) {
56 currentClass = (Class)fkConstraint.getParentTable().get(Keys.ENTITY.toString());
57 if (currentClass != null) {
58 contextLoader.pushAll(stack, fkConstraint);
59 try {
60 Cardinality cardinality = fkConstraint.getCardinality();
61 if (cardinality==null) {
62 fkConstraint.setCardinality( getDb2OOMapper().determineCardinality(fkConstraint) );
63 }
64 boolean toMany = getDb2OOMapper().isManyCardinality(fkConstraint);
65 Reference reference = new Reference();
66 String name = uniquePropertyName(currentClass, getDb2OOMapper().referenceName(fkConstraint) );
67 reference.setName(name);
68 Class type = getDb2OOMapper().referenceType(fkConstraint);
69 reference.setTargetType(type);
70 if (toMany) {
71 String collectionType = getDb2OOMapper().containerType(fkConstraint);
72 reference.setCollectionType(collectionType);
73 }
74 reference.setNavigable(true);
75 currentClass.addChildModel(reference);
76 reference.put(Keys.FK_CONSTRAINT.toString(), fkConstraint);
77 fkConstraint.put(Keys.REFERENCE.toString(), reference);
78 trySettingReverseReferences(fkConstraint, reference);
79 if (log.isDebugEnabled())
80 log.debug("created reference: "+reference);
81 } finally {
82 contextLoader.popAll(stack, fkConstraint);
83 }
84 }
85 }
86 }
87 }
88
89 public void visit(Table table) { throw new java.lang.IllegalStateException("visit(Table) BAD - not supposed to be here"); }
90
91 public void visit(Column column) { throw new java.lang.IllegalStateException("visit(Table) BAD - not supposed to be here"); }
92
93
94
95
96
97 /***
98 * create links to reverse references on 2nd reference creation
99 */
100 private void trySettingReverseReferences(FkConstraint fkConstraint, Reference reference) {
101 boolean isLinkTable = Boolean.TRUE.equals(fkConstraint.getTargetTable().isLinkTable());
102 Reference reverse = null;
103 FkConstraint reverseFkColumn = fkConstraint.getReverseFkConstraint();
104 if (isLinkTable) {
105 for(FkConstraint linkFkColumn : fkConstraint.getTargetTable().getFkColumns())
106 if (fkConstraint.getParentTable() != linkFkColumn.getTargetTable())
107 reverseFkColumn = linkFkColumn.getReverseFkConstraint();
108 }
109 reverse = (Reference)reverseFkColumn.get(Keys.REFERENCE.toString());
110 if (reverse!=null && reverse.getReverse()==null) {
111 if (isLinkTable || fkConstraint.getReverseFkConstraint().getReverseFkConstraint()==fkConstraint) {
112 reverse.setReverse(reference);
113 reference.setReverse(reverse);
114 } else {
115 log.warn("Reverse reference not set for "+reference+" - foreign key may have multiple constraints.");
116 }
117 }
118 }
119
120 }