001 package org.apache.ojb.broker.metadata.torque;
002
003 /* Copyright 2002-2005 The Apache Software Foundation
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 import org.apache.ojb.broker.metadata.ClassDescriptor;
019 import org.apache.ojb.broker.metadata.CollectionDescriptor;
020 import org.apache.ojb.broker.metadata.DescriptorRepository;
021 import org.apache.ojb.broker.metadata.FieldDescriptor;
022 import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
023 import org.apache.ojb.broker.util.logging.Logger;
024 import org.apache.ojb.broker.util.logging.LoggerFactory;
025
026 import java.util.HashMap;
027 import java.util.Iterator;
028 import java.util.Vector;
029
030 public class TorqueForeignKeyGenerator {
031 private final Logger logger = LoggerFactory.getLogger(this.getClass());
032 private DescriptorRepository repository;
033 private HashMap mappingTables = new HashMap();
034 private HashMap foreignKeyVectors = new HashMap();
035
036 public TorqueForeignKeyGenerator(DescriptorRepository repository) {
037 this.repository = repository;
038 }
039
040 public void buildConstraintsMap() {
041 Iterator classDescriptorIterators = this.repository.iterator();
042 while (classDescriptorIterators.hasNext()) {
043 ClassDescriptor cd = (ClassDescriptor) classDescriptorIterators.next();
044 if(cd.isAbstract() || cd.isInterface())
045 {
046 logger.debug( "Skip constraint build for abstract class/ interface " + cd.getClassNameOfObject() );
047 }
048 else
049 {
050 buildConstraints(cd);
051 buildOneToOneConstraints(cd);
052 }
053 }
054 }
055
056 public Vector getForeignKeysForTable(String tableName) {
057 return (Vector) this.foreignKeyVectors.get(tableName);
058 }
059
060 public HashMap getMappingTables() {
061 return this.mappingTables;
062 }
063
064 private void buildTableFieldDescriptors(FieldDescriptor fieldDescriptors[], TableDescriptor tableDescriptor) {
065 for (int i = 0; i < fieldDescriptors.length; i++) {
066 tableDescriptor.addColumn(fieldDescriptors[i]);
067 }
068 }
069
070 private void buildConstraints(ClassDescriptor cd) {
071 Vector collectionDescriptors = cd.getCollectionDescriptors();
072 for (int i = 0; i < collectionDescriptors.size(); i++) {
073 CollectionDescriptor collectionDescriptor = (CollectionDescriptor) collectionDescriptors.get(i);
074 if (collectionDescriptor.isMtoNRelation()) {
075 buildManyToManyConstraints(cd, collectionDescriptor);
076 } else {
077 buildOneToManyReferences(cd, collectionDescriptor);
078 }
079 }
080 }
081
082 private void buildManyToManyConstraints(ClassDescriptor cd, CollectionDescriptor collectionDescriptor) {
083 Vector columns = new Vector();
084
085 ClassDescriptor itemDescriptor = this.repository.getDescriptorFor(collectionDescriptor.getItemClass());
086 buildManyToManyReferences(cd, collectionDescriptor, collectionDescriptor.getFksToThisClass(), columns);
087 buildManyToManyReferences(itemDescriptor, collectionDescriptor, collectionDescriptor.getFksToItemClass(), columns);
088
089 if (isImplicitlyMapped(collectionDescriptor.getIndirectionTable())) {
090 TableDescriptor mappingTable = new TableDescriptor();
091 buildTableFieldDescriptors((FieldDescriptor[]) columns.toArray(new FieldDescriptor[0]), mappingTable);
092 mappingTable.setName(collectionDescriptor.getIndirectionTable());
093 this.mappingTables.put(mappingTable.getName(), mappingTable);
094 }
095 }
096
097 private void buildManyToManyReferences(ClassDescriptor cd, CollectionDescriptor collectionDescriptor,
098 Object keys[], Vector columns)
099 {
100 if(cd.isAbstract() || cd.isInterface())
101 {
102 logger.debug( "Skip foreign key build for MtoM, found abstract base class or interface " + cd.getClassNameOfObject() );
103 return;
104 }
105 StringBuffer buffer = new StringBuffer(256);
106 buildForeignKeyHeader(cd.getFullTableName(), buffer);
107
108 for (int i = 0; i < keys.length; i++) {
109 String columnName = (String) keys[i];
110
111 FieldDescriptor foreignColumn = cd.getPkFields()[i];
112 String foreignColumnName = foreignColumn.getPersistentField().getName();
113 buildReferenceForColumn(buffer, columnName, foreignColumnName);
114 FieldDescriptor fieldDescriptor = (FieldDescriptor)foreignColumn.clone();
115 fieldDescriptor.setColumnName(columnName);
116 columns.add(fieldDescriptor);
117 }
118 buffer.append(" </foreign-key>\n");
119
120 addReferenceToTable(collectionDescriptor.getIndirectionTable(), buffer.toString());
121 }
122
123 private void buildOneToManyReferences(ClassDescriptor cd, CollectionDescriptor collectionDescriptor) {
124 Vector foreignKeyIndices = collectionDescriptor.getForeignKeyFields();
125 ClassDescriptor foreignKeyClassDescriptor = this.repository.getDescriptorFor(collectionDescriptor.getItemClass());
126 buildForeignKey(cd, foreignKeyIndices, foreignKeyClassDescriptor);
127 }
128
129
130 private void buildOneToOneConstraints(ClassDescriptor classDescriptor) {
131 Vector referenceDescriptors = classDescriptor.getObjectReferenceDescriptors();
132 for (int i = 0; i < referenceDescriptors.size(); i++) {
133 ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) referenceDescriptors.get(i);
134
135 Vector foreignKeyIndices = ord.getForeignKeyFields();
136 ClassDescriptor foreignClassDescriptor = this.repository.getDescriptorFor(ord.getItemClass());
137 buildForeignKey(foreignClassDescriptor, foreignKeyIndices, classDescriptor);
138 }
139 }
140
141 private void buildForeignKey(ClassDescriptor foreignClassDescriptor, Vector foreignKeyIndices, ClassDescriptor classDescriptor) {
142
143 if(classDescriptor.isAbstract() || classDescriptor.isInterface())
144 {
145 logger.debug( "Skip foreign key build, found abstract base class or interface " + classDescriptor.getClassNameOfObject() );
146 return;
147 }
148 StringBuffer buffer = new StringBuffer(256);
149 buildForeignKeyHeader(foreignClassDescriptor.getFullTableName(), buffer);
150
151 for (int i = 0; i < foreignKeyIndices.size(); i++) {
152 String columnName = null;
153 Object obj = foreignKeyIndices.get(i);
154
155 if (obj instanceof Integer)
156 {
157 int foreignKeyIndex = ((Integer) obj).intValue();
158 columnName = classDescriptor.getFieldDescriptorByIndex(foreignKeyIndex).getColumnName();
159 }
160 else
161 {
162 FieldDescriptor fld = classDescriptor.getFieldDescriptorByName((String) obj);
163 if(fld == null)
164 {
165 logger.debug( "FieldDescriptor for foreign key parameter \n" + obj + " was not found in ClassDescriptor \n" + classDescriptor );
166 }
167 else columnName = fld.getColumnName();
168 }
169
170 FieldDescriptor foreignColumn = foreignClassDescriptor.getPkFields()[i];
171 String foreignColumnName = foreignColumn.getColumnName();
172 buildReferenceForColumn(buffer, columnName, foreignColumnName);
173 }
174 buffer.append(" </foreign-key>\n");
175 addReferenceToTable(classDescriptor.getFullTableName(), buffer.toString());
176 }
177
178 private void buildForeignKeyHeader(String foreignClassName, StringBuffer buffer) {
179 buffer.append(" <foreign-key foreignTable=\"");
180 buffer.append(foreignClassName);
181 buffer.append("\">\n");
182 }
183
184 private void buildReferenceForColumn(StringBuffer buffer, String columnName, String foreignColumnName) {
185 buffer.append(" <reference local=\"");
186 buffer.append(columnName);
187 buffer.append("\" foreign=\"");
188 buffer.append(foreignColumnName);
189 buffer.append("\"/>\n");
190 }
191
192
193 private boolean isImplicitlyMapped(String tableName) {
194 Iterator classDescriptorIterator = repository.iterator();
195
196 while (classDescriptorIterator.hasNext()) {
197 ClassDescriptor cd = (ClassDescriptor) classDescriptorIterator.next();
198 if (tableName.equals(cd.getFullTableName())) {
199 return false;
200 }
201 }
202
203 return true;
204 }
205
206 private void addReferenceToTable(String tableName, String reference) {
207 Vector tableReferences = (Vector) this.foreignKeyVectors.get(tableName);
208 if (tableReferences == null) {
209 tableReferences = new Vector();
210 this.foreignKeyVectors.put(tableName, tableReferences);
211
212 }
213 if (!tableReferences.contains(reference)) {
214 tableReferences.add(reference);
215 }
216 }
217 }