001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.openjpa.jdbc.schema;
020:
021: import java.util.Collection;
022: import java.util.HashMap;
023: import java.util.LinkedList;
024: import java.util.Map;
025:
026: /**
027: * Represents a grouping of schemas used in a database.
028: *
029: * @author Abe White
030: */
031: public class SchemaGroup extends NameSet implements Cloneable {
032:
033: private Map _schemaMap = null;
034:
035: // cache
036: private Schema[] _schemas = null;
037:
038: /**
039: * Return all schemas.
040: */
041: public Schema[] getSchemas() {
042: if (_schemas == null)
043: _schemas = (_schemaMap == null) ? new Schema[0]
044: : (Schema[]) _schemaMap.values().toArray(
045: new Schema[_schemaMap.size()]);
046: return _schemas;
047: }
048:
049: /**
050: * Return the schema with the given name, or null if none.
051: */
052: public Schema getSchema(String name) {
053: if (_schemaMap == null)
054: return null;
055: if (name != null)
056: name = name.toUpperCase();
057: return (Schema) _schemaMap.get(name);
058: }
059:
060: /**
061: * Add a schema to the group.
062: */
063: public Schema addSchema() {
064: return addSchema(null);
065: }
066:
067: /**
068: * Add a schema to the group.
069: */
070: public Schema addSchema(String name) {
071: addName(name, false);
072: Schema schema = newSchema(name);
073: if (name != null)
074: name = name.toUpperCase();
075: if (_schemaMap == null)
076: _schemaMap = new HashMap();
077: _schemaMap.put(name, schema);
078: _schemas = null;
079: return schema;
080: }
081:
082: /**
083: * Remove the given schema from the group.
084: *
085: * @return true if the schema was removed, false if not in the group
086: */
087: public boolean removeSchema(Schema schema) {
088: if (schema == null)
089: return false;
090:
091: String name = schema.getName();
092: if (name != null)
093: name = name.toUpperCase();
094: Schema rem = (Schema) _schemaMap.get(name);
095: if (schema.equals(rem)) {
096: _schemaMap.remove(name);
097: removeName(schema.getName());
098: _schemas = null;
099: schema.remove();
100: return true;
101: }
102: return false;
103: }
104:
105: /**
106: * Import a schema from another group. Foreign keys are not imported.
107: */
108: public Schema importSchema(Schema schema) {
109: if (schema == null)
110: return null;
111:
112: Schema copy = addSchema(schema.getName());
113: Sequence[] seqs = schema.getSequences();
114: for (int i = 0; i < seqs.length; i++)
115: copy.importSequence(seqs[i]);
116:
117: Table[] tables = schema.getTables();
118: Index[] idxs;
119: Unique[] unqs;
120: Table tab;
121: for (int i = 0; i < tables.length; i++) {
122: tab = copy.importTable(tables[i]);
123: idxs = tables[i].getIndexes();
124: for (int j = 0; j < idxs.length; j++)
125: tab.importIndex(idxs[j]);
126: unqs = tables[i].getUniques();
127: for (int j = 0; j < unqs.length; j++)
128: tab.importUnique(unqs[j]);
129: }
130: return copy;
131: }
132:
133: /**
134: * Return true if the given table is known to exist. While
135: * {@link #findTable} may exhibit dynamic behavior in some schema group
136: * implementations, this method only returns true if the table has been
137: * added to this group or is known to exist in the database.
138: */
139: public boolean isKnownTable(Table table) {
140: return findTable(table) != null;
141: }
142:
143: /**
144: * Return true if the given table is known to exist. While
145: * {@link #findTable} may exhibit dynamic behavior in some schema group
146: * implementations, this method only returns true if the table has been
147: * added to this group or is known to exist in the database.
148: */
149: public boolean isKnownTable(String name) {
150: return findTable(name) != null;
151: }
152:
153: /**
154: * Find the equivalent of the given table in this schema group. The
155: * given table that may have come from another schema group.
156: */
157: public Table findTable(Table table) {
158: return findTable(table.getFullName());
159: }
160:
161: /**
162: * Find the table with the given name in the group, using '.' as the
163: * catalog separator. Returns null if no table found.
164: */
165: public Table findTable(String name) {
166: if (name == null)
167: return null;
168:
169: int dotIdx = name.indexOf('.');
170: if (dotIdx != -1) {
171: String schemaName = name.substring(0, dotIdx);
172: name = name.substring(dotIdx + 1);
173: Schema schema = getSchema(schemaName);
174: if (schema != null)
175: return schema.getTable(name);
176: } else {
177: Schema[] schemas = getSchemas();
178: Table tab;
179: for (int i = 0; i < schemas.length; i++) {
180: tab = schemas[i].getTable(name);
181: if (tab != null)
182: return tab;
183: }
184: }
185: return null;
186: }
187:
188: /**
189: * Find the table with the given name in the group, using '.' as the catalog
190: * separator. Returns null if no table found.
191: */
192: public Table findTable(Schema inSchema, String name) {
193: if (name == null)
194: return null;
195:
196: int dotIdx = name.indexOf('.');
197: if (dotIdx != -1) {
198: String schemaName = name.substring(0, dotIdx);
199: name = name.substring(dotIdx + 1);
200: Schema schema = getSchema(schemaName);
201: if (schema != null)
202: return schema.getTable(name);
203: } else {
204: Schema[] schemas = getSchemas();
205: for (int i = 0; i < schemas.length; i++) {
206: Table tab = schemas[i].getTable(name);
207: // if a table is found and it has the same schema
208: // as the input schema , it means that the table
209: // exists. However, if the input schema is null,
210: // then we assume that there is only one table for the
211: // db default schema, in this case, table exists..
212: // We can't handle the case that one entity has schema name
213: // and other entity does not have schema name but both entities
214: // map to the same table.
215: if (tab != null
216: && (schemas[i] == inSchema || inSchema
217: .getName() == null))
218: return tab;
219:
220: }
221: }
222: return null;
223: }
224:
225: /**
226: * Return true if the given sequence is known to exist. While
227: * {@link #findSequence} may exhibit dynamic behavior in some schema group
228: * implementations, this method only returns true if the sequence has been
229: * added to this group or is known to exist in the database.
230: */
231: public boolean isKnownSequence(Sequence seq) {
232: return findSequence(seq) != null;
233: }
234:
235: /**
236: * Return true if the given sequence is known to exist. While
237: * {@link #findSequence} may exhibit dynamic behavior in some schema group
238: * implementations, this method only returns true if the sequence has been
239: * added to this group or is known to exist in the database.
240: */
241: public boolean isKnownSequence(String name) {
242: return findSequence(name) != null;
243: }
244:
245: /**
246: * Find the equivalent of the given sequence in this schema group. The
247: * given sequence that may have come from another schema group.
248: */
249: public Sequence findSequence(Sequence seq) {
250: return findSequence(seq.getFullName());
251: }
252:
253: /**
254: * Find the sequence with the given name in the group, using '.' as the
255: * catalog separator. Returns null if no sequence found.
256: */
257: public Sequence findSequence(String name) {
258: if (name == null)
259: return null;
260:
261: int dotIdx = name.indexOf('.');
262: if (dotIdx != -1) {
263: String schemaName = name.substring(0, dotIdx);
264: name = name.substring(dotIdx + 1);
265: Schema schema = getSchema(schemaName);
266: if (schema != null)
267: return schema.getSequence(name);
268: } else {
269: Schema[] schemas = getSchemas();
270: Sequence seq;
271: for (int i = 0; i < schemas.length; i++) {
272: seq = schemas[i].getSequence(name);
273: if (seq != null)
274: return seq;
275: }
276: }
277: return null;
278: }
279:
280: /**
281: * Find the sequence with the given name in the group, using '.' as the
282: * catalog separator. Returns null if no sequence found.
283: */
284: public Sequence findSequence(Schema inSchema, String name) {
285: if (name == null)
286: return null;
287:
288: int dotIdx = name.indexOf('.');
289: if (dotIdx != -1) {
290: String schemaName = name.substring(0, dotIdx);
291: name = name.substring(dotIdx + 1);
292: Schema schema = getSchema(schemaName);
293: if (schema != null)
294: return schema.getSequence(name);
295: } else {
296: Schema[] schemas = getSchemas();
297: Sequence seq;
298: for (int i = 0; i < schemas.length; i++) {
299: seq = schemas[i].getSequence(name);
300: if ((seq != null)
301: && (schemas[i] == inSchema || inSchema
302: .getName() == null))
303: return seq;
304: }
305:
306: }
307: return null;
308: }
309:
310: /**
311: * Find all foreign keys exported by a given primary key (all foreign keys
312: * that link to the primary key).
313: */
314: public ForeignKey[] findExportedForeignKeys(PrimaryKey pk) {
315: if (pk == null)
316: return new ForeignKey[0];
317:
318: Schema[] schemas = getSchemas();
319: Table[] tabs;
320: ForeignKey[] fks;
321: Collection exports = new LinkedList();
322: for (int i = 0; i < schemas.length; i++) {
323: tabs = schemas[i].getTables();
324: for (int j = 0; j < tabs.length; j++) {
325: fks = tabs[j].getForeignKeys();
326: for (int k = 0; k < fks.length; k++) {
327: if (fks[k].getPrimaryKeyTable() != null
328: && pk.equals(fks[k].getPrimaryKeyTable()
329: .getPrimaryKey()))
330: exports.add(fks[k]);
331: }
332: }
333: }
334: return (ForeignKey[]) exports.toArray(new ForeignKey[exports
335: .size()]);
336: }
337:
338: /**
339: * Remove unreferenced or emtpy components from the schema.
340: */
341: public void removeUnusedComponents() {
342: Schema[] schemas = getSchemas();
343: Table[] tabs;
344: Column[] cols;
345: Sequence[] seqs;
346: PrimaryKey pk;
347: ForeignKey[] fks;
348: for (int i = 0; i < schemas.length; i++) {
349: seqs = schemas[i].getSequences();
350: for (int j = 0; j < seqs.length; j++)
351: if (seqs[j].getRefCount() == 0)
352: schemas[i].removeSequence(seqs[j]);
353:
354: tabs = schemas[i].getTables();
355: for (int j = 0; j < tabs.length; j++) {
356: pk = tabs[j].getPrimaryKey();
357: fks = tabs[j].getForeignKeys();
358: cols = tabs[j].getColumns();
359:
360: if (pk != null && pk.getRefCount() == 0)
361: tabs[j].removePrimaryKey();
362:
363: for (int k = 0; k < fks.length; k++)
364: if (fks[k].getRefCount() == 0)
365: tabs[j].removeForeignKey(fks[k]);
366:
367: for (int k = 0; k < cols.length; k++)
368: if (cols[k].getRefCount() == 0)
369: tabs[j].removeColumn(cols[k]);
370:
371: if (tabs[j].getColumns().length == 0)
372: schemas[i].removeTable(tabs[j]);
373: }
374:
375: if (schemas[i].getTables().length == 0)
376: removeSchema(schemas[i]);
377: }
378: }
379:
380: public Object clone() {
381: SchemaGroup clone = newInstance();
382: clone.copy(this );
383: return clone;
384: }
385:
386: /**
387: * Create a new instance of this class.
388: */
389: protected SchemaGroup newInstance() {
390: return new SchemaGroup();
391: }
392:
393: /**
394: * Copy cloneable state from the given instance.
395: */
396: protected void copy(SchemaGroup group) {
397: Schema[] schemas = group.getSchemas();
398: for (int i = 0; i < schemas.length; i++)
399: importSchema(schemas[i]);
400:
401: // have to do fks after all schemas are imported
402: Table[] tabs;
403: ForeignKey[] fks;
404: for (int i = 0; i < schemas.length; i++) {
405: tabs = schemas[i].getTables();
406: for (int j = 0; j < tabs.length; j++) {
407: fks = tabs[j].getForeignKeys();
408: for (int k = 0; k < fks.length; k++)
409: getSchema(schemas[i].getName()).getTable(
410: tabs[j].getName()).importForeignKey(fks[k]);
411: }
412: }
413: }
414:
415: /**
416: * Return a new schema with the given name.
417: */
418: protected Schema newSchema(String name) {
419: return new Schema(name, this );
420: }
421:
422: /**
423: * Return a new sequence with the given name and owner schema.
424: */
425: protected Sequence newSequence(String name, Schema schema) {
426: return new Sequence(name, schema);
427: }
428:
429: /**
430: * Return a new table with the given name and owner schema.
431: */
432: protected Table newTable(String name, Schema schema) {
433: return new Table(name, schema);
434: }
435:
436: /**
437: * Return a new column with the given name and owner table.
438: */
439: protected Column newColumn(String name, Table table) {
440: return new Column(name, table);
441: }
442:
443: /**
444: * Return a new primary key with the given name and owner table.
445: */
446: protected PrimaryKey newPrimaryKey(String name, Table table) {
447: return new PrimaryKey(name, table);
448: }
449:
450: /**
451: * Return a new index with the given name and owner table.
452: */
453: protected Index newIndex(String name, Table table) {
454: return new Index(name, table);
455: }
456:
457: /**
458: * Return a new unique constraint with the given name and owner table.
459: */
460: protected Unique newUnique(String name, Table table) {
461: return new Unique(name, table);
462: }
463:
464: /**
465: * Return a new foreign key with the given name and owner table.
466: */
467: protected ForeignKey newForeignKey(String name, Table table) {
468: return new ForeignKey(name, table);
469: }
470: }
|