001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.sql.framework.model.impl;
042:
043: import java.util.ArrayList;
044: import java.util.Collections;
045: import java.util.List;
046: import org.netbeans.modules.sql.framework.model.DBColumn;
047: import org.openide.util.Exceptions;
048: import org.w3c.dom.Element;
049: import com.sun.sql.framework.exception.BaseException;
050: import com.sun.sql.framework.utils.StringUtil;
051: import java.sql.ResultSet;
052: import java.sql.SQLException;
053: import java.util.Locale;
054: import java.util.ResourceBundle;
055: import org.netbeans.modules.sql.framework.model.DBTable;
056: import org.netbeans.modules.sql.framework.model.ForeignKey;
057: import org.netbeans.modules.sql.framework.model.PrimaryKey;
058:
059: /**
060: * Implements PrimaryKey interface.
061: *
062: * @author Jonathan Giron
063: * @version $Revision$
064: */
065: public class PrimaryKeyImpl implements Cloneable, PrimaryKey {
066:
067: /** Name of attribute used for marshalling out PK column names to XML */
068: public static final String COLUMNS_ATTR = "columns"; // NOI18N
069: /** Document element tag name for marshalling out this object to XML */
070: public static final String ELEMENT_TAG = "primaryKey"; // NOI18N
071: /** Name of attribute used for marshalling out primary key name to XML */
072: public static final String NAME_ATTR = "name"; // NOI18N
073: /**DatabaseMetaData ResultSet column name used to decode name of associated primary key */
074: protected static final String RS_KEY_NAME = "PK_NAME"; // NOI18N
075: private static final String RS_COLUMN_NAME = "COLUMN_NAME"; // NOI18N
076: /** DatabaseMetaData ResultSet column name used to decode key sequence number*/
077: protected static final String RS_SEQUENCE_NUM = "KEY_SEQ";
078: /* List of column names in key sequence order. */
079: private List<String> columnNames;
080: /* (optional) DOM element used to construct this instance of PrimaryKey */
081: private transient Element element;
082: /* Name of this key; may be null */
083: private String name;
084: /* DBTable to which this PK belongs */
085: private DBTable parent;
086:
087: public PrimaryKeyImpl(ResultSet rs) {// throws SQLException {
088: this ();
089: try {
090: if (rs == null) {
091: Locale locale = Locale.getDefault();
092: ResourceBundle cMessages = ResourceBundle
093: .getBundle(
094: "org/netbeans/modules/sql/framework/model/impl/Bundle",
095: locale); // NO i18n
096: throw new IllegalArgumentException(cMessages
097: .getString("ERROR_VALID_RS")
098: + "(ERROR_VALID_RS)"); // NO i18n
099: }
100: while (rs.next()) {
101: columnNames.add(rs.getString(RS_COLUMN_NAME));
102: }
103: } catch (SQLException ex) {
104: Exceptions.printStackTrace(ex);
105: }
106: }
107:
108: /**
109: * Creates a new instance of PrimaryKeyImpl, using the keyElement as a source for
110: * reconstituting its contents. Caller must invoke parseXml() after this constructor
111: * returns in order to unmarshal and reconstitute the instance object.
112: *
113: * @param keyElement DOM element containing XML marshalled version of a PrimaryKeyImpl
114: * instance
115: */
116: public PrimaryKeyImpl(Element keyElement) {
117: this ();
118: element = keyElement;
119: }
120:
121: /**
122: * Creates a new instance of PrimaryKeyImpl, cloning the contents of the given
123: * PrimaryKey implementation instance.
124: *
125: * @param src PrimaryKey to be cloned
126: */
127: public PrimaryKeyImpl(PrimaryKey src) {
128: this ();
129: if (src == null) {
130: throw new IllegalArgumentException(
131: "Must supply non-null PrimaryKey instance for src.");
132: }
133: copyFrom(src);
134: }
135:
136: /**
137: * Creates a new instance of PrimaryKey with the given key name and referencing the
138: * column names in the given List.
139: *
140: * @param keyName name, if any, of this PrimaryKey
141: * @param keyColumnNames List of Column objects, or column names in key sequence
142: * order, depending on state of isStringList
143: * @param isStringList true if keyColumnName contains column names in key sequence
144: * order, false if it contains Column objects which need to be sorted in key
145: * sequence order.
146: */
147: public PrimaryKeyImpl(String keyName, List<String> keyColumnNames) {
148: this ();
149: name = keyName;
150: columnNames.addAll(keyColumnNames);
151: }
152:
153: private PrimaryKeyImpl() {
154: name = null;
155: columnNames = new ArrayList<String>();
156: }
157:
158: /**
159: * Create a clone of this PrimaryKeyImpl.
160: *
161: * @return cloned copy of DBColumn.
162: */
163: @Override
164: public Object clone() {
165: try {
166: PrimaryKeyImpl impl = (PrimaryKeyImpl) super .clone();
167: impl.columnNames = new ArrayList<String>(this .columnNames);
168: return impl;
169: } catch (CloneNotSupportedException e) {
170: throw new InternalError(e.toString());
171: }
172: }
173:
174: /**
175: * @see org.netbeans.modules.model.database.PrimaryKey#contains(DBColumn)
176: */
177: public boolean contains(DBColumn col) {
178: return contains(col.getName());
179: }
180:
181: /**
182: * @see org.netbeans.modules.model.database.PrimaryKey#contains(java.lang.String)
183: */
184: public boolean contains(String columnName) {
185: return columnNames.contains(columnName);
186: }
187:
188: /**
189: * Overrides default implementation to return value based on memberwise comparison.
190: *
191: * @param refObj Object against which we compare this instance
192: * @return true if refObj is functionally identical to this instance; false otherwise
193: */
194: @Override
195: public boolean equals(Object refObj) {
196: if (this == refObj) {
197: return true;
198: }
199:
200: if (!(refObj instanceof PrimaryKeyImpl)) {
201: return false;
202: }
203:
204: PrimaryKeyImpl ref = (PrimaryKeyImpl) refObj;
205: boolean result = (getName() != null) ? name.equals(ref.name)
206: : (ref.name == null);
207: result &= (columnNames != null) ? columnNames
208: .equals(ref.columnNames) : (ref.columnNames != null);
209: return result;
210: }
211:
212: /**
213: * @see org.netbeans.modules.model.database.PrimaryKey#getColumnCount
214: */
215: public int getColumnCount() {
216: return columnNames.size();
217: }
218:
219: /**
220: * @see org.netbeans.modules.model.database.PrimaryKey#getColumnNames
221: */
222: public List<String> getColumnNames() {
223: return Collections.unmodifiableList(columnNames);
224: }
225:
226: /**
227: * @see org.netbeans.modules.model.database.PrimaryKey#getDBColumnName
228: */
229: public String getDBColumnName(int iColumn) {
230: return columnNames.get(iColumn);
231: }
232:
233: /**
234: * @see org.netbeans.modules.model.database.PrimaryKey#getName
235: */
236: public String getName() {
237: if (name == null && parent != null) {
238: name = "PK_" + parent.getName();
239: }
240: return name;
241: }
242:
243: /**
244: * @see org.netbeans.modules.model.database.PrimaryKey#getParent
245: */
246: public DBTable getParent() {
247: return parent;
248: }
249:
250: /**
251: * @see org.netbeans.modules.model.database.PrimaryKey#getSequence(DBColumn)
252: */
253: public int getSequence(DBColumn col) {
254: if (col == null || col.getName() == null) {
255: return -1;
256: }
257:
258: return getSequence(col.getName().trim());
259: }
260:
261: /**
262: * @see org.netbeans.modules.model.database.PrimaryKey#getSequence(java.lang.String)
263: */
264: public int getSequence(String columnName) {
265: return columnNames.indexOf(columnName);
266: }
267:
268: /**
269: * Overrides default implementation to compute hashCode value for those members used
270: * in equals() for comparison.
271: *
272: * @return hash code for this object
273: * @see java.lang.Object#hashCode
274: */
275: @Override
276: public int hashCode() {
277: int myHash = (getName() != null) ? name.hashCode() : 0;
278: myHash += (columnNames != null) ? columnNames.hashCode() : 0;
279:
280: return myHash;
281: }
282:
283: /**
284: * @see org.netbeans.modules.model.database.PrimaryKey#isReferencedBy
285: */
286: public boolean isReferencedBy(ForeignKey fk) {
287: return (fk != null) ? fk.references(this ) : false;
288: }
289:
290: /**
291: * Parses the XML content, if any, represented by the DOM element member variable.
292: *
293: * @exception BaseException thrown while parsing XML, or if member variable element is
294: * null
295: */
296: @SuppressWarnings("unchecked")
297: public void parseXML() throws BaseException {
298: if (this .element == null) {
299: throw new BaseException("No <" + ELEMENT_TAG
300: + "> element found.");
301: }
302:
303: this .name = element.getAttribute(NAME_ATTR);
304:
305: String colNames = element.getAttribute(COLUMNS_ATTR);
306: columnNames.addAll(StringUtil.createStringListFrom(colNames));
307: }
308:
309: @Override
310: public String toString() {
311: StringBuilder buf = new StringBuilder(100);
312: for (int i = 0; i < columnNames.size(); i++) {
313: if (i != 0) {
314: buf.append(",");
315: }
316: buf.append((columnNames.get(i)).trim());
317: }
318: return buf.toString();
319: }
320:
321: /**
322: * Replaces the current List of column names with the contents of the given String
323: * array.
324: *
325: * @param newColNames array of names to supplant current list of column names
326: */
327: public void setColumnNames(String[] newColNames) {
328: if (newColNames == null) {
329: throw new IllegalArgumentException(
330: "Must supply non-null String[] for param newColNames.");
331: }
332:
333: columnNames.clear();
334: for (int i = 0; i < newColNames.length; i++) {
335: columnNames.add(newColNames[i]);
336: }
337: }
338:
339: /**
340: * Writes contents of this PrimaryKeyImpl instance out as an XML element, using the
341: * default prefix.
342: *
343: * @return String containing XML representation of this PrimaryKeyImpl instance
344: */
345: public synchronized String toXMLString() {
346: return toXMLString(null);
347: }
348:
349: /**
350: * Writes contents of this PrimaryKeyImpl instance out as an XML element, using the
351: * given prefix String.
352: *
353: * @param prefix String used to prefix each new line of the XML output
354: * @return String containing XML representation of this PrimaryKeyImpl instance
355: */
356: public synchronized String toXMLString(String prefix) {
357: if (prefix == null) {
358: prefix = "";
359: }
360:
361: StringBuilder buf = new StringBuilder(100);
362:
363: buf.append(prefix).append("<").append(ELEMENT_TAG).append(" ");
364: if (name != null && name.trim().length() != 0) {
365: buf.append(NAME_ATTR).append("=\"").append(name.trim())
366: .append("\" ");
367: }
368:
369: if (columnNames.size() != 0) {
370: buf.append(COLUMNS_ATTR).append("=\"");
371: for (int i = 0; i < columnNames.size(); i++) {
372: if (i != 0) {
373: buf.append(",");
374: }
375: buf.append((columnNames.get(i)).trim());
376: }
377: buf.append("\" ");
378: }
379:
380: buf.append("/>\n");
381:
382: return buf.toString();
383: }
384:
385: /**
386: * Sets reference to DBTable that owns this primary key.
387: *
388: * @param newParent new parent of this primary key.
389: */
390: void setParent(DBTable newParent) {
391: parent = newParent;
392: }
393:
394: /*
395: * Copies contents of given PrimaryKey implementation. @param src PrimaryKey whose
396: * contents are to be copied
397: */
398: private void copyFrom(PrimaryKey src) {
399: name = src.getName();
400: parent = src.getParent();
401:
402: columnNames.clear();
403: columnNames.addAll(src.getColumnNames());
404: }
405: }
|