KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > j2ee > persistence > entitygenerator > DbSchemaEjbGenerator


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.j2ee.persistence.entitygenerator;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import org.netbeans.modules.dbschema.ColumnElement;
29 import org.netbeans.modules.dbschema.ColumnPairElement;
30 import org.netbeans.modules.dbschema.DBIdentifier;
31 import org.netbeans.modules.dbschema.ForeignKeyElement;
32 import org.netbeans.modules.dbschema.SchemaElement;
33 import org.netbeans.modules.dbschema.TableElement;
34 import org.netbeans.modules.dbschema.UniqueKeyElement;
35
36 /**
37  * This class provides an algorithm to produce a set of cmp beans and relations
38  * from a dbschema element.
39  *
40  * @author Chris Webster, Martin Adamek, Andrei Badea
41  */

42 public class DbSchemaEjbGenerator {
43     
44     private GeneratedTables genTables;
45     private Map JavaDoc beans = new HashMap JavaDoc();
46     private List JavaDoc relations = new ArrayList JavaDoc();
47     private SchemaElement schemaElement;
48     
49     /**
50      * Creates a generator for a set of beans.
51      *
52      * @param genTables contains the tables to generate and their respective locations.
53      * @param schemaElement the dbschema containing the tables to generate beans for.
54      */

55     public DbSchemaEjbGenerator(GeneratedTables genTables, SchemaElement schemaElement) {
56         this.schemaElement = schemaElement;
57         this.genTables = genTables;
58     
59         buildCMPSet();
60     }
61     
62     /**
63      * Returns true if the table is a join table. A table is considered
64      * a join table regardless of whether the tables it joins are
65      * included in the tables to generate.
66      */

67     public static boolean isJoinTable(TableElement e) {
68         ForeignKeyElement[] foreignKeys = e.getForeignKeys();
69         if (foreignKeys == null ||
70                 foreignKeys.length != 2) {
71             return false;
72         }
73         
74         int foreignKeySize = foreignKeys[0].getColumns().length +
75                 foreignKeys[1].getColumns().length;
76         
77         if (foreignKeySize < e.getColumns().length) {
78             return false;
79         }
80         
81         // issue 89576: a table which references itself is not a join table
82
String JavaDoc tableName = e.getName().getName();
83         for (int i = 0; i < 2; i++) {
84             if (tableName.equals(foreignKeys[i].getReferencedTable().getName().getName())) {
85                 return false;
86             }
87         }
88         
89         // issue 90962: a table whose foreign keys are unique is not a join table
90
if (isFkUnique(foreignKeys[0]) || isFkUnique(foreignKeys[1])) {
91             return false;
92         }
93         
94         return true;
95     }
96     
97     private boolean isForeignKey(ForeignKeyElement[] fks,
98             ColumnElement col) {
99         if (fks == null) {
100             return false;
101         }
102         
103         for (int i = 0; i < fks.length; i++) {
104             if (fks[i].getColumn(col.getName()) != null) {
105                 return true;
106             }
107         }
108         
109         return false;
110     }
111     
112     public EntityClass[] getBeans() {
113         return (EntityClass[])beans.values().toArray(new EntityClass[beans.size()]);
114     }
115     
116     public EntityRelation[] getRelations() {
117         return (EntityRelation[])relations.toArray(new EntityRelation[relations.size()]);
118     }
119     
120     
121     private EntityClass getBean(String JavaDoc tableName) {
122         return (EntityClass)beans.get(tableName);
123     }
124     
125     private EntityClass addBean(String JavaDoc tableName) {
126         EntityClass bean = getBean(tableName);
127         if (bean != null) {
128             return bean;
129         }
130         
131         bean = new EntityClass(tableName,
132                 genTables.getRootFolder(tableName),
133                 genTables.getPackageName(tableName),
134                 genTables.getClassName(tableName));
135         beans.put(tableName, bean);
136         
137         return bean;
138     }
139     
140     private void addAllTables() {
141         List JavaDoc<TableElement> joinTables = new LinkedList JavaDoc<TableElement>();
142         for (String JavaDoc tableName : genTables.getTableNames()) {
143             TableElement tableElement =
144                     schemaElement.getTable(DBIdentifier.create(tableName));
145             if (isJoinTable(tableElement)) {
146                 joinTables.add(tableElement);
147             } else {
148                 addBean(tableName);
149             }
150         }
151         for (TableElement joinTable : joinTables) {
152             addJoinTable(joinTable);
153         }
154     }
155     
156     private String JavaDoc[] localColumnNames(ForeignKeyElement key) {
157         ColumnPairElement[] pkPairs = key.getColumnPairs();
158         String JavaDoc[] localColumns = new String JavaDoc[pkPairs.length];
159         for (int i = 0; i < pkPairs.length; i++) {
160             localColumns[i] =
161                     pkPairs[i].getLocalColumn().getName().getName();
162         }
163         return localColumns;
164     }
165     
166     private String JavaDoc[] referencedColumnNames(ForeignKeyElement key) {
167         ColumnPairElement[] pkPairs = key.getColumnPairs();
168         String JavaDoc[] refColumns = new String JavaDoc[pkPairs.length];
169         for (int i = 0; i < pkPairs.length; i++) {
170             refColumns[i] =
171                     pkPairs[i].getReferencedColumn().getName().getName();
172         }
173         return refColumns;
174     }
175     /**
176      * Provide a role name based on the foreign key column.
177      * @return role name based on foreign key column or default name
178      */

179     private String JavaDoc getRoleName(ForeignKeyElement fk, String JavaDoc defaultName) {
180         ColumnPairElement[] pkPairs = fk.getColumnPairs();
181         if (pkPairs == null || pkPairs.length > 1) {
182             return defaultName;
183         }
184         return EntityMember.makeClassName(
185                 pkPairs[0].getLocalColumn().getName().getName());
186     }
187     
188     private void addJoinTable(TableElement table) {
189         ForeignKeyElement[] foreignKeys = table.getForeignKeys();
190         
191         // create role A
192
EntityClass roleAHelper = getBean(
193                 foreignKeys[0].getReferencedTable().getName().getName());
194         EntityClass roleBHelper = getBean(
195                 foreignKeys[1].getReferencedTable().getName().getName());
196         
197         String JavaDoc roleAname = getRoleName(foreignKeys[0], roleAHelper.getClassName());
198         String JavaDoc roleBname = getRoleName(foreignKeys[1], roleBHelper.getClassName());
199         
200         String JavaDoc roleACmr = EntityMember.makeRelationshipFieldName(roleBname, true);
201         String JavaDoc roleBCmr = EntityMember.makeRelationshipFieldName(roleAname, true);
202         
203         roleACmr = uniqueAlgorithm(getFieldNames(roleAHelper), roleACmr, null);
204         roleBCmr = uniqueAlgorithm(getFieldNames(roleBHelper), roleBCmr, null);
205         
206         RelationshipRole roleA = new RelationshipRole(
207                 roleAname,
208                 roleAHelper.getClassName(),
209                 roleACmr,
210                 true,
211                 true,
212                 false);
213         roleAHelper.addRole(roleA);
214         
215         RelationshipRole roleB = new RelationshipRole(
216                 roleBname,
217                 roleBHelper.getClassName(),
218                 roleBCmr,
219                 true,
220                 true,
221                 false);
222         roleBHelper.addRole(roleB);
223         
224         EntityRelation relation = new EntityRelation(roleA, roleB);
225         relations.add(relation);
226         
227         relation.setRelationName(EntityMember.makeClassName(table.getName().getName()));
228         
229         roleAHelper.getCMPMapping().getJoinTableMapping().put(roleACmr, table.getName().getName());
230         CMPMappingModel.JoinTableColumnMapping joinColMapA = new CMPMappingModel.JoinTableColumnMapping();
231         joinColMapA.setColumns(getColumnNames(foreignKeys[0].getColumns()));
232         joinColMapA.setReferencedColumns(getColumnNames(foreignKeys[0].getReferencedColumns()));
233         joinColMapA.setInverseColumns(getColumnNames(foreignKeys[1].getColumns()));
234         joinColMapA.setReferencedInverseColumns(getColumnNames(foreignKeys[1].getReferencedColumns()));
235         roleAHelper.getCMPMapping().getJoinTableColumnMppings().put(roleACmr, joinColMapA);
236                 
237         roleBHelper.getCMPMapping().getJoinTableMapping().put(roleBCmr, table.getName().getName());
238         CMPMappingModel.JoinTableColumnMapping joinColMapB = new CMPMappingModel.JoinTableColumnMapping();
239         joinColMapB.setColumns(getColumnNames(foreignKeys[1].getColumns()));
240         joinColMapB.setReferencedColumns(getColumnNames(foreignKeys[1].getReferencedColumns()));
241         joinColMapB.setInverseColumns(getColumnNames(foreignKeys[0].getColumns()));
242         joinColMapB.setReferencedInverseColumns(getColumnNames(foreignKeys[0].getReferencedColumns()));
243         roleBHelper.getCMPMapping().getJoinTableColumnMppings().put(roleBCmr, joinColMapB);
244
245     }
246     
247     private String JavaDoc[] getColumnNames(ColumnElement[] cols) {
248         String JavaDoc[] names = new String JavaDoc[cols.length];
249         for (int i = 0; i < cols.length; i++) {
250             names [i] = cols[i].getName().getName();
251         }
252         return names;
253     }
254     
255     private static boolean containsSameColumns(ColumnElement[] fkColumns,
256             UniqueKeyElement uk) {
257         if (fkColumns.length == uk.getColumns().length) {
258             for (int i = 0; i < fkColumns.length; i++) {
259                 if (uk.getColumn(fkColumns[i].getName())==null) {
260                     return false;
261                 }
262             }
263             return true;
264         }
265         return false;
266     }
267     
268     private boolean containsColumns(ColumnElement[] fkColumns,
269             UniqueKeyElement uk) {
270         if (uk == null) {
271             return false;
272         }
273         
274         for (int i = 0; i < fkColumns.length; i++) {
275             if (uk.getColumn(fkColumns[i].getName())!=null) {
276                 return true;
277             }
278         }
279         return false;
280     }
281     
282     private static boolean isFkUnique(ForeignKeyElement key) {
283         UniqueKeyElement[] uk = key.getDeclaringTable().getUniqueKeys();
284         if (uk == null) {
285             return false;
286         }
287         
288         ColumnElement[] columns = key.getColumns();
289         for (int uin=0; uin < uk.length; uin++) {
290             if (containsSameColumns(columns, uk[uin])) {
291                 return true;
292             }
293         }
294         
295         return false;
296     }
297
298     // returns true if all of the columns are nullable
299
private boolean isNullable(ForeignKeyElement key) {
300         ColumnElement[] columns = key.getColumns();
301         int i, count = ((columns != null) ? columns.length : 0);
302
303         for (i=0; i < count; i++) {
304             if (!columns[i].isNullable()) {
305                 return false;
306             }
307         }
308         
309         return true;
310     }
311
312     private static UniqueKeyElement getPrimaryOrCandidateKey(TableElement table) {
313         UniqueKeyElement pk = table.getPrimaryKey();
314         if (pk != null) {
315             return pk;
316         }
317         
318         UniqueKeyElement[] keys = table.getUniqueKeys();
319         if (keys == null || keys.length == 0) {
320             return null;
321         }
322         
323         pk = keys[0];
324         for (int i = 1; i < keys.length; i++) {
325             if (keys[i].getColumns().length < pk.getColumns().length) {
326                 pk = keys[i];
327             }
328         }
329         return pk;
330     }
331     
332     private void generatePkField(ColumnElement column, boolean inPk, boolean pkField) {
333         EntityMember m = EntityMember.create(column);
334         m.setPrimaryKey(inPk, pkField);
335         EntityClass bean = getBean(column.getDeclaringTable().getName().getName());
336         m.setMemberName(uniqueAlgorithm(getFieldNames(bean), m.getMemberName(), null));
337         bean.getFields().add(m);
338     }
339     
340     private void generateRelationship(ForeignKeyElement key) {
341         String JavaDoc keyTableName = key.getDeclaringTable().getName().getName();
342         String JavaDoc keyRefName = key.getReferencedTable().getName().getName();
343         boolean oneToOne = isFkUnique(key);
344         
345         EntityClass roleBHelper = getBean(keyRefName);
346         if (roleBHelper == null) {
347             return;
348         }
349         EntityClass roleAHelper = getBean(keyTableName);
350         if (roleAHelper == null) {
351             return;
352         }
353
354         // create role B (it's the table which contains the foreign key)
355
String JavaDoc roleBCmr = EntityMember.makeRelationshipFieldName(
356                 roleAHelper.getClassName(), !oneToOne);
357         roleBCmr = uniqueAlgorithm(getFieldNames(roleBHelper), roleBCmr, null);
358         RelationshipRole roleB = new RelationshipRole(
359                 //TODO ask generator for default role name, do not assume it is EJB name
360
getRoleName(key, roleBHelper.getClassName()),
361                 roleBHelper.getClassName(),
362                 roleBCmr,
363                 false,
364                 !oneToOne,
365                 !isNullable(key));
366         roleBHelper.addRole(roleB);
367         
368         // role A
369
String JavaDoc roleACmr = EntityMember.makeRelationshipFieldName(
370                 roleBHelper.getClassName(), false);
371         
372         /* only use database column name if a column is not required by the
373            primary key. If a column is already required by the primary key
374            then executing this code would cause the cmr-field name to be
375            named cmp-fieldname1. Therefore, we do not change the cmr-field
376            name and instead use the name of the other ejb (default).
377          */

378         if (!containsColumns(key.getColumns(), getPrimaryOrCandidateKey(key.getDeclaringTable()))) {
379             roleACmr = EntityMember.makeRelationshipFieldName(roleB.getRoleName(), false);
380         }
381         
382         roleACmr = uniqueAlgorithm(getFieldNames(roleAHelper), roleACmr, null);
383         
384         RelationshipRole roleA = new RelationshipRole(
385                 //TODO ask generator for default role name, do not assume it is EJB name
386
getRoleName(key, roleAHelper.getClassName()),
387                 roleAHelper.getClassName(),
388                 roleACmr,
389                 !oneToOne,
390                 false,
391                 false);
392         roleAHelper.addRole(roleA);
393         
394         EntityRelation relation = new EntityRelation(roleA, roleB);
395         relation.setRelationName(roleA.getEntityName() + '-' + roleB.getEntityName()); // NOI18N
396
relations.add(relation);
397         
398         roleAHelper.getCMPMapping().getCmrFieldMapping().put(roleACmr, localColumnNames(key));
399         roleBHelper.getCMPMapping().getCmrFieldMapping().put(roleBCmr, referencedColumnNames(key));
400     }
401     
402     private void reset() {
403         beans.clear();
404         relations.clear();
405     }
406     
407     private void buildCMPSet() {
408         reset();
409         addAllTables();
410         for (Iterator JavaDoc it = beans.keySet().iterator(); it.hasNext();) {
411             String JavaDoc tableName = it.next().toString();
412             TableElement table = schemaElement.getTable(DBIdentifier.create(tableName));
413             ColumnElement[] cols = table.getColumns();
414             UniqueKeyElement pk = getPrimaryOrCandidateKey(table);
415             ForeignKeyElement[] fkeys = table.getForeignKeys();
416             for (int col = 0; col < cols.length; col++) {
417                 if (pk != null &&
418                         pk.getColumn(cols[col].getName()) != null) {
419                     generatePkField(cols[col],true, pk.getColumns().length==1);
420                 } else {
421                     // TODO add check to see if table is included
422
if (!isForeignKey(fkeys, cols[col])){
423                         generatePkField(cols[col], false, false);
424                     }
425                 }
426             }
427             
428             for (int fk = 0 ; fkeys != null && fkeys.length > fk; fk++) {
429                 generateRelationship(fkeys[fk]);
430             }
431             EntityClass helperData = getBean(tableName);
432             helperData.usePkField(pk!= null && pk.getColumns().length == 1);
433         }
434         makeRelationsUnique();
435     }
436     
437     private List JavaDoc getFieldNames(EntityClass bean) {
438         List JavaDoc result = new ArrayList JavaDoc();
439         for (Iterator JavaDoc i = bean.getFields().iterator(); i.hasNext();) {
440             EntityMember member = (EntityMember)i.next();
441             result.add(member.getMemberName());
442         }
443         for (Iterator JavaDoc i = bean.getRoles().iterator(); i.hasNext();) {
444             RelationshipRole role = (RelationshipRole)i.next();
445             result.add(role.getFieldName());
446         }
447         return result;
448     }
449     
450     /**
451      * This method will make the relationships unique
452      */

453     private EntityRelation[] makeRelationsUnique() {
454         EntityRelation[] r = getRelations();
455         List JavaDoc relationNames = new ArrayList JavaDoc(r.length);
456         for (int i = 0; i < r.length; i++) {
457             r[i].makeRoleNamesUnique();
458             String JavaDoc baseName = r[i].getRelationName();
459             r[i].setRelationName(uniqueAlgorithm(relationNames, baseName, "-")); // NOI18N
460
}
461         return r;
462     }
463     
464     /**
465      * return name generated or base name if this was ok
466      */

467     private static String JavaDoc uniqueAlgorithm(List JavaDoc names, String JavaDoc baseName, String JavaDoc sep) {
468         String JavaDoc newName = baseName;
469         int unique = 0;
470         while (names.contains(newName)) {
471             String JavaDoc ins = (sep == null? "":sep); // NOI18N
472
newName = baseName + ins + String.valueOf(++unique);
473         }
474         names.add(newName);
475         return newName;
476     }
477 }
478
Popular Tags