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.sql.Connection;
022: import java.sql.DatabaseMetaData;
023: import java.sql.SQLException;
024:
025: import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
026: import org.apache.openjpa.jdbc.sql.SQLExceptions;
027: import org.apache.openjpa.lib.conf.Configurable;
028: import org.apache.openjpa.lib.conf.Configuration;
029:
030: /**
031: * Factory that uses database metadata to construct the system schema.
032: * The lazy schema factory only loads table data as it is requested. It
033: * does not properly support operations that require knowledge of the entire
034: * schema.
035: *
036: * @author Abe White
037: */
038: public class LazySchemaFactory extends SchemaGroup implements
039: SchemaFactory, Configurable {
040:
041: private transient JDBCConfiguration _conf = null;
042: private transient Connection _conn = null;
043: private transient DatabaseMetaData _meta = null;
044: private transient SchemaGenerator _gen = null;
045:
046: private boolean _indexes = false;
047: private boolean _pks = false;
048: private boolean _fks = false;
049:
050: public boolean getPrimaryKeys() {
051: return _pks;
052: }
053:
054: public void setPrimaryKeys(boolean pks) {
055: _pks = pks;
056: }
057:
058: public boolean getForeignKeys() {
059: return _fks;
060: }
061:
062: public void setForeignKeys(boolean fks) {
063: _fks = fks;
064: }
065:
066: public boolean getIndexes() {
067: return _indexes;
068: }
069:
070: public void setIndexes(boolean idx) {
071: _indexes = idx;
072: }
073:
074: public SchemaGroup readSchema() {
075: return this ;
076: }
077:
078: public void storeSchema(SchemaGroup schema) {
079: // nothing to do
080: }
081:
082: public Table findTable(String name) {
083: if (name == null)
084: return null;
085:
086: Table table = super .findTable(name);
087: if (table != null)
088: return table;
089:
090: generateSchemaObject(name, true);
091: return super .findTable(name);
092: }
093:
094: public Sequence findSequence(String name) {
095: if (name == null)
096: return null;
097:
098: Sequence seq = super .findSequence(name);
099: if (seq != null)
100: return seq;
101:
102: generateSchemaObject(name, false);
103: return super .findSequence(name);
104: }
105:
106: /**
107: * Generate the table or sequence with the given name.
108: */
109: private void generateSchemaObject(String name, boolean isTable) {
110: // if full name, split
111: String schemaName = null;
112: String objectName = name;
113:
114: // look for the standard schema separator...
115: int dotIdx = name.indexOf('.');
116: // ... or the dictionary schema separator
117: if (dotIdx == -1) {
118: String sep = _conf.getDBDictionaryInstance().catalogSeparator;
119: if (!".".equals(sep))
120: dotIdx = name.indexOf(sep);
121: }
122:
123: if (dotIdx != -1) {
124: schemaName = name.substring(0, dotIdx);
125: objectName = name.substring(dotIdx + 1);
126: }
127:
128: // we share a single connection across all schemas, so synch
129: // on the schema group
130: synchronized (this ) {
131: boolean close = false;
132: try {
133: // use the existing connection if possible; this method
134: // might be reentrant if generating the foreign keys for
135: // this table (see below) requires loading additional
136: // tables; in that case we don't want to spawn additional
137: // connections
138: if (_conn == null) {
139: _conn = _conf.getDataSource2(null).getConnection();
140: close = true;
141: _meta = _conn.getMetaData();
142: }
143:
144: if (isTable) {
145: // generate the table from database metadata
146: _gen.generateTables(schemaName, objectName, _conn,
147: _meta);
148: Table table = super .findTable(name);
149:
150: if (table != null) {
151: if (_pks)
152: _gen.generatePrimaryKeys(table
153: .getSchemaName(), table.getName(),
154: _conn, _meta);
155: if (_indexes)
156: _gen.generateIndexes(table.getSchemaName(),
157: table.getName(), _conn, _meta);
158:
159: // generate foreign keys from the table; this might
160: // end up re-calling this getTable method if the foreign
161: // key links to a table that hasn't been loaded yet
162: if (_fks)
163: _gen.generateForeignKeys(table
164: .getSchemaName(), table.getName(),
165: _conn, _meta);
166: }
167: } else
168: _gen.generateSequences(schemaName, objectName,
169: _conn, _meta);
170: } catch (SQLException se) {
171: throw SQLExceptions.getStore(se, _conf
172: .getDBDictionaryInstance());
173: } finally {
174: if (close) {
175: try {
176: _conn.close();
177: } catch (SQLException se) {
178: }
179: _conn = null;
180: }
181: }
182: }
183: }
184:
185: public void setConfiguration(Configuration conf) {
186: _conf = (JDBCConfiguration) conf;
187: _gen = new SchemaGenerator(_conf);
188: _gen.setSchemaGroup(this );
189: }
190:
191: public void startConfiguration() {
192: }
193:
194: public void endConfiguration() {
195: }
196: }
|