001: /*
002: * $Id: ExternalAxionDBTable.java,v 1.3 2005/12/20 18:32:28 ahimanikya Exp $
003: * =======================================================================
004: * Copyright (c) 2005 Axion Development Team. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above
011: * copyright notice, this list of conditions and the following
012: * disclaimer.
013: *
014: * 2. Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * 3. The names "Tigris", "Axion", nor the names of its contributors may
020: * not be used to endorse or promote products derived from this
021: * software without specific prior written permission.
022: *
023: * 4. Products derived from this software may not be called "Axion", nor
024: * may "Tigris" or "Axion" appear in their names without specific prior
025: * written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
030: * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
032: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
033: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
034: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
035: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
036: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
037: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
038: * =======================================================================
039: */
040: package org.axiondb.engine.tables;
041:
042: import java.io.File;
043: import java.util.ArrayList;
044: import java.util.HashSet;
045: import java.util.Iterator;
046: import java.util.List;
047: import java.util.Properties;
048: import java.util.Set;
049:
050: import org.apache.commons.collections.primitives.IntCollection;
051: import org.apache.commons.logging.Log;
052: import org.apache.commons.logging.LogFactory;
053: import org.axiondb.AxionException;
054: import org.axiondb.Column;
055: import org.axiondb.ColumnIdentifier;
056: import org.axiondb.Constraint;
057: import org.axiondb.Database;
058: import org.axiondb.DatabaseLink;
059: import org.axiondb.ExternalTable;
060: import org.axiondb.Index;
061: import org.axiondb.Row;
062: import org.axiondb.RowCollection;
063: import org.axiondb.RowDecorator;
064: import org.axiondb.RowIterator;
065: import org.axiondb.RowSource;
066: import org.axiondb.Selectable;
067: import org.axiondb.Sequence;
068: import org.axiondb.Table;
069: import org.axiondb.TransactableTable;
070: import org.axiondb.engine.Databases;
071: import org.axiondb.engine.TransactableTableImpl;
072: import org.axiondb.event.BaseTableModificationPublisher;
073: import org.axiondb.event.ColumnEvent;
074: import org.axiondb.jdbc.ConnectionFactory;
075:
076: /**
077: * Axion external table implementation of ExternalTable interface.
078: *
079: * @version $Revision: 1.3 $ $Date: 2005/12/20 18:32:28 $
080: * @author Ahimanikya Satapathy
081: * @see org.axiondb.DatabaseLink
082: * @see org.axiondb.engine.tables.ExternalDatabaseTable
083: */
084: public class ExternalAxionDBTable extends
085: BaseTableModificationPublisher implements ExternalTable {
086:
087: private static Log _log = LogFactory
088: .getLog(ExternalAxionDBTable.class);
089:
090: /** Set of recognized keys for organization properties */
091: private static final Set PROPERTY_KEYS = new HashSet(6);
092:
093: /** Set of required keys for organization properties */
094: private static final Set REQUIRED_KEYS = new HashSet(1);
095:
096: static {
097: // Build set of recognized property keys for external db tables.
098: PROPERTY_KEYS.add(PROP_DB);
099: PROPERTY_KEYS.add(PROP_REMOTETABLE);
100: PROPERTY_KEYS.add(PROP_VENDOR);
101:
102: // Build set of required property keys for external db tables.
103: REQUIRED_KEYS.add(PROP_DB);
104: }
105:
106: public ExternalAxionDBTable(String name, Database db) {
107: _name = name;
108: _type = EXTERNAL_DB_TABLE_TYPE;
109: _db = db;
110: }
111:
112: public void addColumn(Column col) throws AxionException {
113: _cols.add(col);
114: publishEvent(new ColumnEvent(this , col));
115: }
116:
117: public void addConstraint(Constraint constraint)
118: throws AxionException {
119: }
120:
121: public void addIndex(Index index) throws AxionException {
122: _remoteTable.addIndex(index);
123: }
124:
125: public void addRow(Row row) throws AxionException {
126: _remoteTable.addRow(row);
127: }
128:
129: public void applyDeletes(IntCollection rowIds)
130: throws AxionException {
131: _remoteTable.applyDeletes(rowIds);
132: }
133:
134: public void applyInserts(RowCollection rows) throws AxionException {
135: _remoteTable.applyInserts(rows);
136: }
137:
138: public void applyUpdates(RowCollection rows) throws AxionException {
139: _remoteTable.applyUpdates(rows);
140: }
141:
142: public void checkpoint() throws AxionException {
143: }
144:
145: public void deleteRow(Row row) throws AxionException {
146: _remoteTable.deleteRow(row);
147: }
148:
149: public void drop() throws AxionException {
150: if (_remoteTable != null) {
151: _remoteTable.drop();
152: cleanUp();
153: }
154: }
155:
156: public void freeRowId(int id) {
157: _remoteTable.freeRowId(id);
158: }
159:
160: public Column getColumn(int index) {
161: return _remoteTable.getColumn(index);
162: }
163:
164: public Column getColumn(String name) {
165: return _remoteTable.getColumn(name);
166: }
167:
168: public int getColumnCount() {
169: return _remoteTable.getColumnCount();
170: }
171:
172: public List getColumnIdentifiers() {
173: return _remoteTable.getColumnIdentifiers();
174: }
175:
176: public int getColumnIndex(String name) throws AxionException {
177: return _remoteTable.getColumnIndex(name);
178: }
179:
180: public Iterator getConstraints() {
181: return _remoteTable.getConstraints();
182: }
183:
184: public String getDBLinkName() {
185: return _dblink;
186: }
187:
188: public RowIterator getIndexedRows(RowSource source,
189: Selectable node, boolean readOnly) throws AxionException {
190: return _remoteTable.getIndexedRows(source, node, readOnly);
191: }
192:
193: public RowIterator getIndexedRows(Selectable node, boolean readOnly)
194: throws AxionException {
195: return _remoteTable.getIndexedRows(node, readOnly);
196: }
197:
198: public Index getIndexForColumn(Column column) {
199: return _remoteTable.getIndexForColumn(column);
200: }
201:
202: public Iterator getIndices() {
203: return _remoteTable.getIndices();
204: }
205:
206: public RowIterator getMatchingRows(List selectables, List values,
207: boolean readOnly) throws AxionException {
208: return _remoteTable.getMatchingRows(selectables, values,
209: readOnly);
210: }
211:
212: public String getName() {
213: return _name;
214: }
215:
216: public int getNextRowId() {
217: return _remoteTable.getNextRowId();
218: }
219:
220: public Row getRow(int id) throws AxionException {
221: return _remoteTable.getRow(id);
222: }
223:
224: public int getRowCount() {
225: return _remoteTable.getRowCount();
226: }
227:
228: public RowIterator getRowIterator(boolean readOnly)
229: throws AxionException {
230: return _remoteTable.getRowIterator(readOnly);
231: }
232:
233: public Sequence getSequence() {
234: return _remoteTable.getSequence();
235: }
236:
237: public Properties getTableProperties() {
238: return context.getTableProperties();
239: }
240:
241: public String getType() {
242: return _type;
243: }
244:
245: public boolean hasColumn(ColumnIdentifier id) {
246: boolean result = false;
247: String tableName = id.getTableName();
248: if (tableName == null || tableName.equals(getName())) {
249: result = (getColumn(id.getName()) != null);
250: }
251: return result;
252: }
253:
254: public boolean hasIndex(String name) throws AxionException {
255: return _remoteTable.hasIndex(name);
256: }
257:
258: public boolean isColumnIndexed(Column column) {
259: return _remoteTable.isColumnIndexed(column);
260: }
261:
262: public boolean isPrimaryKeyConstraintExists(String columnName) {
263: return _remoteTable.isPrimaryKeyConstraintExists(columnName);
264: }
265:
266: public boolean isUniqueConstraintExists(String columnName) {
267: return _remoteTable.isUniqueConstraintExists(columnName);
268: }
269:
270: public boolean loadExternalTable(Properties props)
271: throws AxionException {
272: context = new ExternalDatabaseTableOrganizationContext();
273: context.readOrSetDefaultProperties(props);
274: context.updateProperties();
275: return true;
276: }
277:
278: public RowDecorator makeRowDecorator() {
279: return _remoteTable.makeRowDecorator();
280: }
281:
282: public TransactableTable makeTransactableTable() {
283: return new TransactableTableImpl(this );
284: }
285:
286: public void migrate() throws AxionException {
287: }
288:
289: public void populateIndex(Index index) throws AxionException {
290: _remoteTable.populateIndex(index);
291: }
292:
293: public void remount() throws AxionException {
294: }
295:
296: public void remount(File dir, boolean datafilesonly)
297: throws AxionException {
298: }
299:
300: public Constraint removeConstraint(String name) {
301: return _remoteTable.removeConstraint(name);
302: }
303:
304: public Constraint getConstraint(String name) {
305: return _remoteTable.getConstraint(name);
306: }
307:
308: public void removeIndex(Index index) throws AxionException {
309: _remoteTable.removeIndex(index);
310: }
311:
312: public void rename(String oldName, String newName)
313: throws AxionException {
314: _remoteTable.rename(oldName, newName);
315: }
316:
317: public void setSequence(Sequence seq) throws AxionException {
318: }
319:
320: public void shutdown() throws AxionException {
321: cleanUp();
322: }
323:
324: public String toString() {
325: return getName();
326: }
327:
328: public void truncate() throws AxionException {
329: _remoteTable.truncate();
330: }
331:
332: public void updateRow(Row oldrow, Row newrow) throws AxionException {
333: _remoteTable.updateRow(oldrow, newrow);
334: }
335:
336: private void assertColumns() throws AxionException {
337: Iterator iter = _cols.iterator();
338: while (iter.hasNext()) {
339: Column col = (Column) iter.next();
340: if (!hasColumn(new ColumnIdentifier(null, col.getName(),
341: null, col.getDataType()))) {
342: throw new AxionException("Column " + col
343: + "does not exist in remote table"
344: + _remoteTableName);
345: }
346: }
347: }
348:
349: private void cleanUp() throws AxionException {
350: _remoteDb = null;
351: _remoteTable = null;
352: }
353:
354: private void setUp(DatabaseLink server) throws AxionException {
355: if (_remoteDb == null) {
356: String url = server.getJdbcUrl();
357: String name;
358: File path = null;
359: String prefixStripped = url
360: .substring(ConnectionFactory.URL_PREFIX.length());
361: int colon = prefixStripped.indexOf(":");
362: if (colon == -1 || (prefixStripped.length() - 1 == colon)) {
363: name = prefixStripped;
364: } else {
365: name = prefixStripped.substring(0, colon);
366: path = new File(prefixStripped.substring(colon + 1));
367: }
368:
369: _remoteDb = Databases.getOrCreateDatabase(name, path);
370: _remoteTable = _remoteDb.getTable(_remoteTableName);
371: }
372:
373: if (_remoteTable == null) {
374: throw new AxionException(
375: "Initialization error for remote table "
376: + getName());
377: }
378: }
379:
380: private class ExternalDatabaseTableOrganizationContext extends
381: BaseTableOrganizationContext {
382:
383: public Set getPropertyKeys() {
384: Set baseKeys = getBasePropertyKeys();
385: Set keys = new HashSet(baseKeys.size()
386: + PROPERTY_KEYS.size());
387: keys.addAll(baseKeys);
388: keys.addAll(PROPERTY_KEYS);
389:
390: return keys;
391: }
392:
393: public Set getRequiredPropertyKeys() {
394: Set baseRequiredKeys = getBaseRequiredPropertyKeys();
395: Set keys = new HashSet(baseRequiredKeys.size()
396: + REQUIRED_KEYS.size());
397: keys.addAll(baseRequiredKeys);
398: keys.addAll(REQUIRED_KEYS);
399:
400: return keys;
401: }
402:
403: public void readOrSetDefaultProperties(Properties props)
404: throws AxionException {
405: // Validate all supplied property keys to ensure they are recognized.
406: super .assertValidPropertyKeys(props);
407:
408: _dblink = props.getProperty(PROP_DB);
409: if (_dblink == null || _dblink.trim().length() == 0
410: || !_db.hasDatabaseLink(_dblink)) {
411: throw new AxionException(
412: "Please provide a valid server name");
413: }
414:
415: DatabaseLink server = _db.getDatabaseLink(_dblink);
416: if (server == null) {
417: throw new AxionException("Database link " + _dblink
418: + " does not exist.");
419: }
420:
421: _remoteTableName = props.getProperty(PROP_REMOTETABLE);
422: _remoteTableName = (_remoteTableName != null) ? _remoteTableName
423: : getName();
424:
425: setUp(server);
426: assertColumns();
427:
428: _log.debug("External DB Table " + _remoteTableName
429: + " created.");
430: }
431:
432: public void updateProperties() {
433: super .updateProperties();
434:
435: setProperty(PROP_DB, _dblink);
436: setProperty(PROP_REMOTETABLE, _remoteTableName);
437: setProperty(PROP_LOADTYPE, ExternalTableFactory.TYPE_REMOTE);
438: setProperty(PROP_VENDOR, "AXION");
439: }
440: }
441:
442: private List _cols = new ArrayList();
443:
444: private Database _db;
445: private String _dblink;
446:
447: private String _name = null;
448:
449: private Database _remoteDb;
450: private Table _remoteTable;
451: private String _remoteTableName;
452:
453: private String _type = null;
454:
455: private ExternalDatabaseTableOrganizationContext context;
456:
457: }
|