View Javadoc

1   /*
2    * Copyright 2006 Outsource Cafe, Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the 'License')
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *    http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an 'AS IS' BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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  	// DatabaseModelVisitor interface methods:
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  	// helper methods:
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 }