1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.javagen.revgen.visitor;
17
18 import java.util.HashSet;
19 import java.util.Set;
20
21 import org.javagen.agile.core.model.Model;
22 import org.javagen.agile.core.util.StringUtil;
23 import org.javagen.agile.core.visitor.DefaultVisitor;
24 import org.javagen.agile.db.model.Cardinality;
25 import org.javagen.agile.db.model.FkConstraint;
26 import org.javagen.agile.db.model.FkEnum;
27 import org.javagen.agile.oo.model.Reference;
28 import org.javagen.revgen.context.Keys;
29
30 /***
31 * Post-process DB-to-Java model before templates are generated, making sure model is consistant.
32 * Doing this in a seperate pass, allows changes to be made to the model
33 * by intermediate processes (ie customized metadata).
34 *
35 * @author Richard Easterling
36 */
37 public class PostProcessVisitor extends DefaultVisitor {
38
39 private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(PostProcessVisitor.class);
40
41 public PostProcessVisitor() {
42 Set<String> itinerary = new HashSet<String>();
43 itinerary.add(Reference.DEFAULT_MODEL_TYPE);
44 this.setItinerary(itinerary);
45 }
46
47 @Override
48 public void visit(Model model) {
49 if (model instanceof Reference) {
50 Reference reference = (Reference)model;
51 referenceOwningSide(reference);
52 }
53 }
54
55 /***
56 * Determines the owning side of a relationship as follows:
57 * <ol>
58 * <li>if unidirectional then it IS the owning side</li>
59 * <li>if is the foreign key holding side then it IS the owning side</li>
60 * <li>if it is a ManyToMany and <code>owningSide=true</code> set in context then it IS the owning side</li>
61 * <li>if it is a ManyToMany then sort parent tables by name to determine owning side</li>
62 * </ol>
63 * @param reference
64 */
65 protected void referenceOwningSide(Reference reference) {
66
67 Reference reverseReference = reference.getReverse();
68 FkConstraint fkConstraint = (FkConstraint)reference.get(Keys.FK_CONSTRAINT.toString());
69 FkConstraint reverseFkColumn = reverseReference==null ? null : (FkConstraint)reverseReference.get(Keys.FK_CONSTRAINT.toString());
70 Object val = reference.get(Keys.OWNING_SIDE.toString());
71 Boolean owningSideAlreadySet = val==null ? null : Boolean.parseBoolean(val.toString());
72
73 if (reverseReference==null)
74 warn(reference+" has no reverseReference set");
75 if (fkConstraint==null)
76 warn(reference+" has no 'fkColumn' set in context");
77 if (reverseReference!=null && reverseFkColumn==null)
78 warn(reverseReference+" has no 'fkColumn' set in context");
79 boolean bidirectional =
80 reverseReference!=null
81 && ! Boolean.FALSE.equals(reverseReference.getNavigable())
82 && ! Boolean.FALSE.equals(reference.getNavigable());
83 if (bidirectional && fkConstraint!=null && reverseFkColumn!=null) {
84 boolean holdsFk = FkEnum.IMPORTED.equals(fkConstraint.getFkType());
85 boolean manyToManyPick =
86 Cardinality.MANY_TO_MANY.equals(fkConstraint.getCardinality())
87 && (
88 Boolean.TRUE.equals(owningSideAlreadySet)
89 || fkConstraint.getParentTable().getName().compareTo(reverseFkColumn.getParentTable().getName())>0
90 );
91 if (holdsFk || manyToManyPick)
92 reference.put(Keys.OWNING_SIDE.toString(), true);
93 } else {
94 if (Boolean.TRUE.equals(reference.getNavigable()))
95 reference.put(Keys.OWNING_SIDE.toString(), true);
96 }
97 }
98
99 protected void warn(String msg) {
100 log.warn(StringUtil.lastToken(this.getClass().getName(),'.')+" - "+msg+" - can't determine relationship owning side properly.");
101 }
102
103 }