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 java.util.Collections;
040: import java.util.Map;
041: import java.util.List;
042: import java.util.SortedMap;
043: import java.util.TreeMap;
044:
045: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DatabaseModel;
046: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DBConnectionDefinition;
047: import org.netbeans.modules.jdbcwizard.builder.dbmodel.DBTable;
048:
049: import java.util.ArrayList;
050: import java.util.Collection;
051: import java.util.Iterator;
052: import java.util.Set;
053:
054: import java.util.ResourceBundle;
055: import org.openide.util.NbBundle;
056:
057: /**
058: * This class implements DBQueryModel
059: *
060: * @author
061: */
062: public class DatabaseModelImpl implements DatabaseModel, Cloneable {
063:
064: /* Initial buffer size for StringBuffer used in marshalling OTDs to XML */
065: private static final String LOG_CATEGORY = DatabaseModelImpl.class
066: .getName();
067:
068: /*
069: * String used to separate name, schema, and/or catalog Strings in a fully-qualified table name.
070: */
071: private static final String FQ_TBL_NAME_SEPARATOR = ".";
072:
073: /** User-supplied name */
074: protected volatile String name;
075:
076: /** User-supplied description */
077: protected volatile String description;
078:
079: /** Map of DBTable instances */
080: protected SortedMap tables;
081:
082: /** Connection name */
083: protected volatile String connectionName;
084:
085: // protected RepositoryObject source;
086:
087: /* Connection definition used to retrieve metadata */
088: protected DBConnectionDefinition connectionDefinition;
089:
090: private DatabaseModelImpl() {
091: this .tables = new TreeMap();
092: }
093:
094: /**
095: * Constructs a new instance of DatabaseModelImpl using the given name and
096: * DBConnectionDefinition.
097: *
098: * @param dName name of new DBQueryModel
099: * @param connDef DBConnectionInfo for this Data Source
100: */
101: public DatabaseModelImpl(final String modelName,
102: final DBConnectionDefinition connDef) {
103: this ();
104: final ResourceBundle cMessages = NbBundle
105: .getBundle(DatabaseModelImpl.class);
106: if (connDef == null) {
107: throw new IllegalArgumentException(
108: "connDef must be non-null");
109: }
110:
111: final String connName = connDef.getName();
112: if (connName == null || connName.trim().length() == 0) {
113: throw new IllegalArgumentException(cMessages
114: .getString("ERROR_NAME_CONNDEF")
115: + "(ERROR_NAME_CONNDEF)");
116: }
117:
118: if (modelName == null || modelName.trim().length() == 0) {
119: throw new IllegalArgumentException(cMessages
120: .getString("ERROR_NAME_MODEL")
121: + "(ERROR_NAME_MODEL)");
122: }
123:
124: this .name = modelName;
125: this .connectionDefinition = connDef;
126: }
127:
128: /**
129: * Creates a new instance of DatabaseModelImpl, cloning the contents of the given DBQueryModel
130: * implementation instance.
131: *
132: * @param src DBQueryModel instance to be cloned
133: */
134: /*
135: * public DatabaseModelImpl(DBQueryModel src) { this(); ResourceBundle cMessages =
136: * NbBundle.getBundle(DatabaseModelImpl.class); if (src == null) { throw new
137: * IllegalArgumentException( cMessages.getString("ERROR_PARAM")+"(ERROR_PARAM)"); }
138: * copyFrom(src); }
139: */
140:
141: /**
142: * @see com.stc.model.database.DBQueryModel#getModelDescription
143: */
144: public String getModelDescription() {
145: return this .description;
146: }
147:
148: /**
149: * Sets the description string of this DBQueryModel
150: *
151: * @param newDesc new description string
152: */
153: public void setDescription(final String newDesc) {
154: this .description = newDesc;
155: }
156:
157: /**
158: * Adds new DBTable to the model.
159: *
160: * @param table new DBTable to add
161: * @return true if add succeeded, false otherwise
162: */
163: public boolean addTable(final DBTable table) {
164: if (table != null) {
165: this .tables.put(this .getFullyQualifiedTableName(table),
166: table);
167: return true;
168: }
169: return false;
170: }
171:
172: /**
173: * Copies member values to those contained in the given DBQueryModel instance.
174: *
175: * @param src DBQueryModel whose contents are to be copied into this instance
176: */
177: public void copyFrom(final DatabaseModel src) {
178: if (src != null) {
179: this .name = src.getModelName();
180: this .description = src.getModelDescription();
181:
182: final DBConnectionDefinition def = src
183: .getConnectionDefinition();
184: if (def instanceof DBConnectionDefinitionImpl) {
185: this .connectionDefinition = def;
186: } else {
187: this .connectionDefinition = new DBConnectionDefinitionImpl(
188: def);
189: }
190:
191: this .tables.clear();
192: final List srcTables = src.getTables();
193: if (srcTables != null) {
194: final Iterator iter = srcTables.iterator();
195: while (iter.hasNext()) {
196: final DBTable tbl = (DBTable) iter.next();
197: this .addTable(new DBTableImpl(tbl));
198: }
199: }
200: }
201: }
202:
203: /**
204: * Create DBTable with the given table name, schema name and catalog name.
205: *
206: * @param tableName table name.
207: * @param schemaName schema name; may be null
208: * @param catalogName catalog name; may be null
209: * @return an instance of DBTable if successfull, null if failed.
210: */
211: public DBTable createTable(final String tableName,
212: final String schemaName, final String catalogName) {
213: DBTableImpl table = null;
214: final ResourceBundle cMessages = NbBundle
215: .getBundle(DatabaseModelImpl.class);
216: if (tableName == null || tableName.length() == 0) {
217: throw new IllegalArgumentException(cMessages
218: .getString("ERROR_TABLE_NAME")
219: + "(ERROR_TABLE_NAME)");
220: }
221:
222: table = new DBTableImpl(tableName, schemaName, catalogName);
223: this .addTable(table);
224: return table;
225: }
226:
227: /**
228: * Deletes all tables associated with this data source.
229: *
230: * @return true if all tables were deleted successfully, false otherwise.
231: */
232: public boolean deleteAllTables() {
233: this .tables.clear();
234: return true;
235: }
236:
237: /**
238: * Delete table from the DatabaseModelImpl
239: *
240: * @param fqTableName fully qualified name of table to be deleted.
241: * @return true if successful. false if failed.
242: * @see com.stc.model.database.DBTable#getFullyQualifiedTableName
243: */
244: public boolean deleteTable(final String fqTableName) {
245: if (fqTableName != null && fqTableName.trim().length() != 0) {
246: this .tables.remove(fqTableName);
247: return true;
248: }
249: return false;
250: }
251:
252: /**
253: * @see com.stc.model.database.DBQueryModel#getConnectionName
254: */
255: public String getConnectionName() {
256: return this .connectionName;
257:
258: }
259:
260: /**
261: * @see com.stc.model.database.DBQueryModel#getModelName
262: */
263: public String getModelName() {
264: return this .name;
265: }
266:
267: /**
268: * @see com.stc.model.database.DBQueryModel#getTable(String, String, String)
269: */
270: public DBTable getTable(final String tableName,
271: final String schemaName, final String catalogName) {
272: return this .getTable(this .getFullyQualifiedTableName(tableName,
273: schemaName, catalogName));
274: }
275:
276: /**
277: * @see com.stc.model.database.DBQueryModel#getTable(String)
278: */
279: public DBTable getTable(final String fqTableName) {
280: return (DBTable) this .tables.get(fqTableName);
281: }
282:
283: /**
284: * @see com.stc.model.database.DBQueryModel#getTables
285: */
286: public List getTables() {
287: List list = Collections.EMPTY_LIST;
288: final Collection tableColl = this .tables.values();
289:
290: if (tableColl.size() != 0) {
291: list = new ArrayList(tableColl.size());
292: list.addAll(tableColl);
293: }
294:
295: return Collections.unmodifiableList(list);
296: }
297:
298: /**
299: * Gets a read-only Map of table names to available DBTable instances in this model.
300: *
301: * @return readonly Map of table names to DBTable instances
302: */
303: public Map getTableMap() {
304: return Collections.unmodifiableMap(this .tables);
305: }
306:
307: /**
308: * Sets the Connection Name associated with connection name
309: *
310: * @param theConName associated with this DataSource
311: */
312: public void setConnectionName(final String theConName) {
313: this .connectionName = theConName;
314: }
315:
316: /**
317: * @see java.lang.Object#equals
318: */
319: public boolean equals(final Object refObj) {
320: // Check for reflexivity.
321: if (this == refObj) {
322: return true;
323: }
324:
325: boolean result = false;
326:
327: // Ensure castability (also checks for null refObj)
328: if (refObj instanceof DatabaseModelImpl) {
329: final DatabaseModelImpl aSrc = (DatabaseModelImpl) refObj;
330:
331: result = aSrc.name != null ? aSrc.name.equals(this .name)
332: : this .name == null;
333:
334: boolean connCheck = aSrc.connectionName != null ? aSrc.connectionName
335: .equals(this .connectionName)
336: : this .connectionName == null;
337: result &= connCheck;
338:
339: connCheck = aSrc.connectionDefinition != null ? aSrc.connectionDefinition
340: .equals(this .connectionDefinition)
341: : this .connectionDefinition == null;
342: result &= connCheck;
343:
344: if (this .tables != null && aSrc.tables != null) {
345: final Set objTbls = aSrc.tables.keySet();
346: final Set myTbls = this .tables.keySet();
347:
348: // Must be identical (no subsetting), hence the pair of tests.
349: final boolean tblCheck = myTbls.containsAll(objTbls)
350: && objTbls.containsAll(myTbls);
351: result &= tblCheck;
352: }
353: }
354:
355: return result;
356: }
357:
358: /**
359: * Overrides default implementation to compute hashCode value for those members used in equals()
360: * for comparison.
361: *
362: * @return hash code for this object
363: * @see java.lang.Object#hashCode
364: */
365: public int hashCode() {
366: int myHash = this .name != null ? this .name.hashCode() : 0;
367:
368: myHash += this .connectionName != null ? this .connectionName
369: .hashCode() : 0;
370: myHash += this .connectionDefinition != null ? this .connectionDefinition
371: .hashCode()
372: : 0;
373:
374: if (this .tables != null) {
375: myHash += this .tables.keySet().hashCode();
376: }
377:
378: return myHash;
379: }
380:
381: /**
382: * Overrides default implementation to return name of this DBQueryModel.
383: *
384: * @return model name.
385: */
386: public String toString() {
387: return this .getModelName();
388: }
389:
390: /**
391: * Clones this object.
392: *
393: * @return shallow copy of this DatabaseModelImpl
394: */
395: public Object clone() {
396: try {
397: final DatabaseModelImpl myClone = (DatabaseModelImpl) super
398: .clone();
399:
400: myClone.name = this .name;
401: myClone.description = this .description;
402: myClone.connectionName = myClone.connectionName;
403: myClone.tables = new TreeMap();
404: this .tables.putAll(this .tables);
405: myClone.connectionDefinition = new DBConnectionDefinitionImpl(
406: this .connectionDefinition);
407:
408: return myClone;
409: } catch (final CloneNotSupportedException e) {
410: throw new InternalError(e.toString());
411: }
412: }
413:
414: /**
415: * Gets DBConnectionDefinition of the DatabaseModelImpl object
416: *
417: * @return ConnectionDefinition of the DatabaseModelImpl object
418: */
419: public DBConnectionDefinition getConnectionDefinition() {
420: return this .connectionDefinition;
421: }
422:
423: /**
424: * @see com.stc.model.database.DBQueryModel#getFullyQualifiedTableName(DBTable)
425: */
426: public String getFullyQualifiedTableName(final DBTable tbl) {
427: return tbl != null ? this .getFullyQualifiedTableName(tbl
428: .getName(), tbl.getSchema(), tbl.getCatalog()) : "";
429: }
430:
431: /**
432: * @see com.stc.model.database.DBQueryModel#getFullyQualifiedTableName(String, String, String)
433: */
434: public String getFullyQualifiedTableName(final String tblName,
435: final String schName, final String catName) {
436: if (tblName == null) {
437: final ResourceBundle cMessages = NbBundle
438: .getBundle(DatabaseModelImpl.class);
439: throw new IllegalArgumentException(cMessages
440: .getString("ERROR_NULL_TABLE_NAME")
441: + "ERROR_NULL_TABLE_NAME");
442: }
443:
444: final StringBuffer buf = new StringBuffer(50);
445:
446: /**
447: * TODO:RE:Mar11/2004 Per rex we need to provide option in the wizard to use catalog name or
448: * not. Disabling for now.
449: */
450:
451: /*
452: * if (catName != null && catName.trim().length() != 0) { buf.append(catName.trim());
453: * buf.append(FQ_TBL_NAME_SEPARATOR); }
454: */
455: if (schName != null && schName.trim().length() != 0) {
456: buf.append(schName.trim());
457: buf.append(DatabaseModelImpl.FQ_TBL_NAME_SEPARATOR);
458: }
459:
460: buf.append(tblName.trim());
461:
462: return buf.toString();
463: }
464:
465: /**
466: * Gets repository object, if any, providing underlying data for this DBQueryModel.
467: *
468: * @return RepositoryObject hosting this object's metadata, or null if data are not held by a
469: * RepositoryObject.
470: */
471: /*
472: * public RepositoryObject getSource() { return source; } public void setSource(RepositoryObject
473: * newSource) { source = newSource; }
474: */
475:
476: }
|