001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019:
020: /*
021: *
022: * Copyright 2005 Sun Microsystems, Inc.
023: *
024: * Licensed under the Apache License, Version 2.0 (the "License");
025: * you may not use this file except in compliance with the License.
026: * You may obtain a copy of the License at
027: *
028: * http://www.apache.org/licenses/LICENSE-2.0
029: *
030: * Unless required by applicable law or agreed to in writing, software
031: * distributed under the License is distributed on an "AS IS" BASIS,
032: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
033: * See the License for the specific language governing permissions and
034: * limitations under the License.
035: *
036: */
037: package org.netbeans.modules.jdbcwizard.builder.dbmodel.impl;
038:
039: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DBTable;
040: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DBColumn;
041: import org.netbeans.modules.jdbcwizard.builder.dbmodel.PrimaryKey;
042: import org.netbeans.modules.jdbcwizard.builder.dbmodel.ForeignKey;
043:
044: import java.util.ArrayList;
045: import java.util.Collections;
046: import java.util.Iterator;
047: import java.util.List;
048: import java.util.ListIterator;
049: import java.util.ResourceBundle;
050:
051: import org.openide.util.NbBundle;
052:
053: /**
054: * Implements ForeignKey interface.
055: *
056: * @author
057: */
058: public class ForeignKeyImpl implements ForeignKey, Cloneable {
059:
060: /* Name of this key; may be null */
061: private String fkName;
062:
063: /* Name of corresponding primary key; may be null */
064: private String pkName;
065:
066: /* List of column names for this foreign key in key sequence order. */
067: private List fkColumnNames = new ArrayList();
068:
069: /*
070: * List of column names of corresponding primary key columns, in key sequence order.
071: */
072: private List pkColumnNames = new ArrayList();
073:
074: private String pkTable;
075:
076: private String pkSchema;
077:
078: private String pkCatalog;
079:
080: private int updateRule;
081:
082: private int deleteRule;
083:
084: private int deferrability;
085:
086: /* DBTable to which this PK belongs */
087: private DBTable parent;
088:
089: /**
090: * Creates a new instance of ForeignKey with the given key name and referencing the column names
091: * in the given List.
092: *
093: * @param fkTable DBTable that owns this FK instance
094: * @param foreignKeyName name, if any, of this ForeignKeyImpl
095: * @param primaryKeyName name, if any, of PK associated with this ForeignKeyImpl
096: * @param primaryKeyTable table owning associated PK
097: * @param primaryKeySchema schema containing table which owns associated PK; may be null
098: * @param primaryKeyCatalog catalog containing table which owns associated PK; may be null
099: * @param updateFlag update cascade rule
100: * @param deleteFlag delete cascade rule
101: * @param deferFlag flag indicating deferrability of application of cascade rules
102: */
103: public ForeignKeyImpl(final DBTable fkTable,
104: final String foreignKeyName, final String primaryKeyName,
105: final String primaryKeyTable,
106: final String primaryKeySchema,
107: final String primaryKeyCatalog, final int updateFlag,
108: final int deleteFlag, final int deferFlag) {
109: this .parent = fkTable;
110: this .fkName = foreignKeyName;
111: this .pkName = primaryKeyName;
112:
113: this .pkTable = primaryKeyTable;
114: this .pkSchema = primaryKeySchema;
115: this .pkCatalog = primaryKeyCatalog;
116:
117: this .updateRule = updateFlag;
118: this .deleteRule = deleteFlag;
119: this .deferrability = deferFlag;
120: }
121:
122: /**
123: * Creates a new instance of ForeignKeyImpl, cloning the contents of the given ForeignKey
124: * implementation instance.
125: *
126: * @param src ForeignKey to be cloned
127: */
128: public ForeignKeyImpl(final ForeignKey src) {
129: if (src == null) {
130: final ResourceBundle cMessages = NbBundle
131: .getBundle(ForeignKeyImpl.class);
132: throw new IllegalArgumentException(cMessages
133: .getString("ERROR_NULL_FK")
134: + "ERROR_NULL_FK");// NO
135: // i18n
136: }
137:
138: this .copyFrom(src);
139: }
140:
141: /**
142: * @see com.stc.model.database.ForeignKey#getName
143: */
144: public String getName() {
145: return this .fkName;
146: }
147:
148: /**
149: * @see com.stc.model.database.ForeignKey#getPKName
150: */
151: public String getPKName() {
152: return this .pkName;
153: }
154:
155: /**
156: * @see com.stc.model.database.ForeignKey#getColumnNames
157: */
158: public List getColumnNames() {
159: return Collections.unmodifiableList(this .fkColumnNames);
160: }
161:
162: public void setColumnNames(final ForeignKeyImpl.Column[] columns) {
163: this .fkColumnNames.clear();
164: this .pkColumnNames.clear();
165:
166: if (columns == null) {
167: return;
168: }
169:
170: for (int i = 0; i < columns.length; i++) {
171: final Column col = columns[i];
172: this .fkColumnNames.add(col.getName());
173: this .pkColumnNames.add(col.getPKColumnName());
174: }
175: }
176:
177: public void setColumnNames(final List columns) {
178: this .fkColumnNames.clear();
179: this .pkColumnNames.clear();
180:
181: if (columns == null) {
182: return;
183: }
184:
185: for (final Iterator it = columns.iterator(); it.hasNext();) {
186: final ForeignKeyImpl.Column col = (ForeignKeyImpl.Column) it
187: .next();
188: this .fkColumnNames.add(col.getName());
189: this .pkColumnNames.add(col.getPKColumnName());
190: }
191: }
192:
193: public void setColumnNames(final List fkColumns,
194: final List pkColumns) {
195: this .fkColumnNames.clear();
196: this .pkColumnNames.clear();
197:
198: if (fkColumns == null && pkColumns == null) {
199: return;
200: }
201:
202: if (fkColumns.size() != pkColumns.size()) {
203: final ResourceBundle cMessages = NbBundle
204: .getBundle(ForeignKeyImpl.class);
205: throw new IllegalArgumentException(cMessages
206: .getString("ERROR_SIZE_PK_FK")
207: + "ERROR_SIZE_PK_FK");// NO
208: // i18n
209: }
210:
211: for (final ListIterator it = fkColumns.listIterator(); it
212: .hasNext();) {
213: final String fkName = (String) it.next();
214: final String pkName = (String) pkColumns.get(it
215: .previousIndex());
216:
217: if (fkName != null && pkName != null) {
218: this .fkColumnNames.add(fkName);
219: this .pkColumnNames.add(pkName);
220: }
221: }
222: }
223:
224: /**
225: * @see com.stc.model.database.ForeignKey#getPKColumnNames
226: */
227: public List getPKColumnNames() {
228: return Collections.unmodifiableList(this .pkColumnNames);
229: }
230:
231: /**
232: * @see com.stc.model.database.ForeignKey#getMatchingPKColumn
233: */
234: public String getMatchingPKColumn(final String fkColumnName) {
235: final ListIterator it = this .fkColumnNames.listIterator();
236: while (it.hasNext()) {
237: final String colName = (String) it.next();
238: if (colName.equals(fkColumnName.trim())) {
239: return (String) this .pkColumnNames.get(it
240: .previousIndex());
241: }
242: }
243:
244: return null;
245: }
246:
247: /**
248: * @see com.stc.model.database.ForeignKey#getPKTable
249: */
250: public String getPKTable() {
251: return this .pkTable;
252: }
253:
254: /**
255: * @see com.stc.model.database.ForeignKey#getPKSchema
256: */
257: public String getPKSchema() {
258: return this .pkSchema;
259: }
260:
261: /**
262: * @see com.stc.model.database.ForeignKey#getPKCatalog
263: */
264: public String getPKCatalog() {
265: return this .pkCatalog;
266: }
267:
268: /**
269: * @see com.stc.model.database.ForeignKey#getUpdateRule
270: */
271: public int getUpdateRule() {
272: return this .updateRule;
273: }
274:
275: /**
276: * @see com.stc.model.database.ForeignKey#getDeleteRule
277: */
278: public int getDeleteRule() {
279: return this .deleteRule;
280: }
281:
282: /**
283: * @see com.stc.model.database.ForeignKey#getDeferrability
284: */
285: public int getDeferrability() {
286: return this .deferrability;
287: }
288:
289: /**
290: * @see com.stc.model.database.ForeignKey#getParent
291: */
292: public DBTable getParent() {
293: return this .parent;
294: }
295:
296: public void setParent(final DBTable newParent) {
297: this .parent = newParent;
298: }
299:
300: /**
301: * @see com.stc.model.database.ForeignKey#contains(String)
302: */
303: public boolean contains(final String fkColumnName) {
304: return this .fkColumnNames.contains(fkColumnName);
305: }
306:
307: /**
308: * @see com.stc.model.database.ForeignKey#contains(DbColumn)
309: */
310: public boolean contains(final DBColumn fkCol) {
311: return this .contains(fkCol.getName());
312: }
313:
314: /**
315: * @see com.stc.model.database.ForeignKey#references
316: */
317: public boolean references(final PrimaryKey pk) {
318: if (pk == null) {
319: return false;
320: }
321:
322: final List targetColNames = pk.getColumnNames();
323: final DBTable targetTable = pk.getParent();
324:
325: return this .references(targetTable)
326: && targetColNames.containsAll(this .pkColumnNames)
327: && this .pkColumnNames.containsAll(targetColNames);
328: }
329:
330: /**
331: * @see com.stc.model.database.ForeignKey#references(DBTable)
332: */
333: public boolean references(final DBTable pkTable) {
334: return pkTable != null ? this .references(pkTable.getName(),
335: pkTable.getSchema(), pkTable.getCatalog()) : false;
336: }
337:
338: /**
339: * @see com.stc.model.database.ForeignKey#references(String, String, String)
340: */
341: public boolean references(final String pkTableName,
342: final String pkSchemaName, final String pkCatalogName) {
343: final boolean tableMatches = pkTableName != null ? pkTableName
344: .equals(this .pkTable) : this .pkTable == null;
345:
346: final boolean schemaMatches = pkSchemaName != null ? pkSchemaName
347: .equals(this .pkSchema)
348: : this .pkSchema == null;
349:
350: final boolean catalogMatches = pkCatalogName != null ? pkCatalogName
351: .equals(this .pkCatalog)
352: : this .pkCatalog == null;
353:
354: return tableMatches && schemaMatches && catalogMatches;
355: }
356:
357: /**
358: * Create a clone of this PrimaryKeyImpl.
359: *
360: * @return cloned copy of DBColumn.
361: */
362: public Object clone() {
363: try {
364: final ForeignKeyImpl impl = (ForeignKeyImpl) super .clone();
365: impl.pkColumnNames = new ArrayList(this .pkColumnNames);
366: impl.fkColumnNames = new ArrayList(this .fkColumnNames);
367:
368: return impl;
369: } catch (final CloneNotSupportedException e) {
370: throw new InternalError(e.toString());
371: }
372: }
373:
374: /**
375: * Overrides default implementation to return value based on memberwise comparison.
376: *
377: * @param refObj Object against which we compare this instance
378: * @return true if refObj is functionally identical to this instance; false otherwise
379: */
380: public boolean equals(final Object refObj) {
381: if (this == refObj) {
382: return true;
383: }
384:
385: if (!(refObj instanceof ForeignKeyImpl)) {
386: return false;
387: }
388:
389: final ForeignKeyImpl ref = (ForeignKeyImpl) refObj;
390:
391: boolean result = this .fkName != null ? this .fkName
392: .equals(ref.fkName) : ref.fkName == null;
393:
394: result &= this .pkName != null ? this .pkName.equals(ref.pkName)
395: : ref.pkName == null;
396:
397: result &= this .pkTable != null ? this .pkTable
398: .equals(ref.pkTable) : ref.pkTable == null;
399:
400: result &= this .pkSchema != null ? this .pkSchema
401: .equals(ref.pkSchema) : ref.pkSchema == null;
402:
403: result &= this .pkCatalog != null ? this .pkCatalog
404: .equals(ref.pkCatalog) : ref.pkCatalog == null;
405:
406: result &= this .updateRule == ref.updateRule
407: && this .deleteRule == ref.deleteRule
408: && this .deferrability == ref.deferrability;
409:
410: result &= this .pkColumnNames != null ? this .pkColumnNames
411: .equals(ref.pkColumnNames) : ref.pkColumnNames != null;
412:
413: result &= this .fkColumnNames != null ? this .fkColumnNames
414: .equals(ref.fkColumnNames) : ref.fkColumnNames != null;
415:
416: return result;
417: }
418:
419: /**
420: * Overrides default implementation to compute hashCode value for those members used in equals()
421: * for comparison.
422: *
423: * @return hash code for this object
424: * @see java.lang.Object#hashCode
425: */
426: public int hashCode() {
427: int myHash = this .fkName != null ? this .fkName.hashCode() : 0;
428:
429: myHash += this .pkName != null ? this .pkName.hashCode() : 0;
430: myHash += this .pkTable != null ? this .pkTable.hashCode() : 0;
431: myHash += this .pkSchema != null ? this .pkSchema.hashCode() : 0;
432: myHash += this .pkCatalog != null ? this .pkCatalog.hashCode()
433: : 0;
434:
435: myHash += this .updateRule + this .deleteRule
436: + this .deferrability;
437:
438: myHash += this .fkColumnNames != null ? this .fkColumnNames
439: .hashCode() : 0;
440: myHash += this .pkColumnNames != null ? this .pkColumnNames
441: .hashCode() : 0;
442:
443: return myHash;
444: }
445:
446: /**
447: * @see com.stc.model.database.ForeignKey#getColumnCount
448: */
449: public int getColumnCount() {
450: return this .fkColumnNames.size();
451: }
452:
453: /**
454: * @see com.stc.model.database.ForeignKey#getColumnName
455: */
456: public String getColumnName(final int iColumn) {
457: return (String) this .fkColumnNames.get(iColumn);
458: }
459:
460: /**
461: * @see com.stc.model.database.ForeignKey#getSequence
462: */
463: public int getSequence(final DBColumn col) {
464: if (col == null || col.getName() == null) {
465: return -1;
466: }
467:
468: return this .fkColumnNames.indexOf(col.getName().trim());
469: }
470:
471: private void copyFrom(final ForeignKey src) {
472: this .parent = src.getParent();
473:
474: this .fkName = src.getName();
475: this .fkColumnNames.clear();
476: this .fkColumnNames.addAll(src.getColumnNames());
477:
478: this .pkName = src.getPKName();
479: this .pkCatalog = src.getPKCatalog();
480: this .pkSchema = src.getPKSchema();
481: this .pkTable = src.getPKTable();
482: this .pkColumnNames.clear();
483: this .pkColumnNames.addAll(src.getPKColumnNames());
484:
485: // Set cascade attributes
486: this .updateRule = src.getUpdateRule();
487: this .deleteRule = src.getDeleteRule();
488: this .deferrability = src.getDeferrability();
489: }
490:
491: public static class Column implements Comparable {
492: private String name;
493:
494: private int sequence;
495:
496: private String pkColumnName;
497:
498: public Column(final String colName, final int colSequence,
499: final String pkColName) {
500: final ResourceBundle cMessages = NbBundle
501: .getBundle(ForeignKeyImpl.class);
502:
503: if (colName == null || colName.trim().length() == 0) {
504: throw new IllegalArgumentException(cMessages
505: .getString("ERROR_COL_NAME")
506: + "ERROR_COL_NAME");// NO
507: // i18n
508: }
509:
510: if (pkColName == null || pkColName.trim().length() == 0) {
511: throw new IllegalArgumentException(cMessages
512: .getString("ERROR_PK_COLNAME")
513: + "ERROR_PK_COLNAME");// NO
514: // i18n
515: }
516:
517: if (colSequence <= 0) {
518: throw new IllegalArgumentException(cMessages
519: .getString("ERROR_COL_SEQ")
520: + "ERROR_COL_SEQ");// NO
521: // i18n
522: }
523:
524: this .name = colName.trim();
525: this .sequence = colSequence;
526:
527: this .pkColumnName = pkColName.trim();
528: }
529:
530: public String getName() {
531: return this .name;
532: }
533:
534: public int getSequence() {
535: return this .sequence;
536: }
537:
538: public String getPKColumnName() {
539: return this .pkColumnName;
540: }
541:
542: /**
543: * Compares this object with the specified object for order. Returns a negative integer,
544: * zero, or a positive integer as this object is less than, equal to, or greater than the
545: * specified object.
546: * <p>
547: * Note: this class has a natural ordering that is inconsistent with equals.
548: *
549: * @param o the Object to be compared.
550: * @return a negative integer, zero, or a positive integer as this object is less than,
551: * equal to, or greater than the specified object.
552: */
553: public int compareTo(final Object o) {
554: return this .sequence - ((Column) o).sequence;
555: }
556: }
557: }
|