KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > mdr > persistence > jdbcimpl > JdbcStorage


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.mdr.persistence.jdbcimpl;
20
21 import org.netbeans.mdr.persistence.*;
22 import org.netbeans.mdr.util.*;
23
24 import java.sql.*;
25 import java.util.*;
26 import java.io.*;
27
28 /**
29  * JdbcStorage implements the MDR Storage interface using JDBC.
30  *
31  * @author John V. Sichi
32  * @version $Id: JdbcStorage.java,v 1.14 2006/06/30 20:56:10 jtulach Exp $
33  */

34 class JdbcStorage implements Storage
35 {
36     public static final String JavaDoc MOFID_SEQ_TABLE_NAME = "MOFID_SEQ";
37
38     public static final String JavaDoc MOFID_SEQ_COL_NAME = "MOFID_SEQ_NEXT";
39
40     public static final String JavaDoc KEY_COL_PREFIX = "IDX_KEY";
41     
42     public static final String JavaDoc SINGLE_VAL_COL_PREFIX = "IDX_SVAL";
43     
44     public static final String JavaDoc MULTI_VAL_COL_PREFIX = "IDX_MVAL";
45     
46     public static final String JavaDoc ORDINAL_COL_NAME = "IDX_ORD";
47     
48     public static final String JavaDoc SURROGATE_COL_NAME = "IDX_SUR";
49
50     public static final String JavaDoc PRIMARY_INDEX_NAME = "PRIMARY_INDEX";
51     
52     private Connection jdbcConnection;
53
54     private final DatabaseMetaData dbMetaData;
55
56     private final String JavaDoc idQuote;
57
58     private final String JavaDoc schemaName;
59
60     private final String JavaDoc schemaAuthName;
61
62     private final String JavaDoc userName;
63
64     private final String JavaDoc storageId;
65
66     private final boolean realSchema;
67
68     private final boolean debugPrint;
69
70     private final boolean queryDuplicates;
71
72     private final Map entryTypeToDataTypeMap;
73
74     private Statement jdbcStmt;
75     
76     private ResultSet jdbcResultSet;
77
78     private long firstSerialNumber;
79     
80     private long nextSerialNumber;
81     
82     private Map nameToIndexMap;
83
84     private LazyPreparedStatement sqlUpdateSerialNumber;
85
86     // REVIEW: if this gets too bloated for a big model, may need to turn this
87
// into a cache instead of a map
88
private Map sqlToPreparedStatementMap;
89
90     private List lazyPreparedStatements;
91
92     private JdbcPrimaryIndex primaryIndex;
93
94     JdbcStorage(
95         Properties properties,
96         String JavaDoc storageId)
97         throws StorageException
98     {
99         this.storageId = storageId;
100         
101         schemaName = properties.getProperty(
102             JdbcStorageFactory.STORAGE_SCHEMA_NAME);
103         schemaAuthName = properties.getProperty(
104             JdbcStorageFactory.STORAGE_SCHEMA_AUTH_NAME);
105         userName = properties.getProperty(
106             JdbcStorageFactory.STORAGE_USER_NAME);
107
108         entryTypeToDataTypeMap = new HashMap();
109         createTypeMap(properties);
110         
111         String JavaDoc url = properties.getProperty(
112             JdbcStorageFactory.STORAGE_URL);
113         String JavaDoc password = properties.getProperty(
114             JdbcStorageFactory.STORAGE_PASSWORD);
115         String JavaDoc firstSerialNumberString = properties.getProperty(
116             JdbcStorageFactory.STORAGE_FIRST_SERIAL_NUMBER);
117         if (firstSerialNumberString == null) {
118             firstSerialNumber = 1;
119         } else {
120             try {
121                 firstSerialNumber =
122                     Long.decode(firstSerialNumberString).longValue();
123             } catch (NumberFormatException JavaDoc ex) {
124                 throw new StorageBadRequestException(ex.toString());
125             }
126         }
127         debugPrint = getBooleanProperty(
128             properties,
129             JdbcStorageFactory.STORAGE_DEBUG_PRINT,
130             false);
131         queryDuplicates = getBooleanProperty(
132             properties,
133             JdbcStorageFactory.STORAGE_QUERY_DUPLICATES,
134             false);
135
136         sqlToPreparedStatementMap = new HashMap();
137         lazyPreparedStatements = new ArrayList();
138         
139         boolean success = false;
140         
141         try {
142             // REVIEW: maybe connect/disconnect should correspond to
143
// open/close instead of constructor/shutdown?
144
jdbcConnection =
145                 DriverManager.getConnection(url,userName,password);
146             jdbcConnection.setAutoCommit(false);
147             jdbcStmt = jdbcConnection.createStatement();
148             dbMetaData = jdbcConnection.getMetaData();
149             realSchema = dbMetaData.supportsSchemasInTableDefinitions();
150             idQuote = dbMetaData.getIdentifierQuoteString();
151             success = true;
152         } catch (SQLException ex) {
153             throw newJdbcException(ex);
154         } finally {
155             if (!success) {
156                 rollbackConnection();
157                 closeConnection();
158             }
159         }
160     }
161
162     private static boolean getBooleanProperty(
163         Properties properties,
164         String JavaDoc propName,
165         boolean defaultValue)
166     {
167         String JavaDoc value = properties.getProperty(propName);
168         if (value == null) {
169             return defaultValue;
170         }
171         return value.equalsIgnoreCase("true");
172     }
173
174     private JdbcStorageException newJdbcException(SQLException ex)
175     {
176         if (debugPrint) {
177             ex.printStackTrace();
178         }
179         return new JdbcStorageException(ex);
180     }
181
182     private void createTypeMap(Properties properties)
183     {
184         entryTypeToDataTypeMap.put(
185             EntryType.MOFID,
186             properties.getProperty(
187                 JdbcStorageFactory.STORAGE_DATATYPE_MOFID,
188                 "BIGINT"));
189         
190         entryTypeToDataTypeMap.put(
191             EntryType.STREAMABLE,
192             properties.getProperty(
193                 JdbcStorageFactory.STORAGE_DATATYPE_STREAMABLE,
194                 "LONGVARBINARY"));
195         
196         entryTypeToDataTypeMap.put(
197             EntryType.STRING,
198             properties.getProperty(
199                 JdbcStorageFactory.STORAGE_DATATYPE_STRING,
200                 "VARCHAR(2000)"));
201         
202         entryTypeToDataTypeMap.put(
203             EntryType.INT,
204             properties.getProperty(
205                 JdbcStorageFactory.STORAGE_DATATYPE_INT,
206                 "BIGINT"));
207     }
208
209     // implement Storage
210
public String JavaDoc getName()
211     {
212         return schemaName + ".jdbc";
213     }
214     
215     // implement Storage
216
public String JavaDoc getStorageId ()
217     {
218         return storageId;
219     }
220
221     private void writeSerialNumber(long serialNumber)
222         throws StorageException
223     {
224         executeUpdate(
225             sqlUpdateSerialNumber,
226             new Object JavaDoc[]{new Long JavaDoc(serialNumber)});
227     }
228     
229     // implement Storage
230
public synchronized long getSerialNumber()
231     {
232         return nextSerialNumber++;
233     }
234     
235     // implement Storage
236
public MOFID readMOFID (java.io.InputStream JavaDoc inputStream)
237         throws StorageException
238     {
239         // NOTE: ripped from memoryimpl
240
try {
241             String JavaDoc storageId = IOUtils.readString(inputStream);
242             if (storageId == null) {
243                 storageId = this.storageId;
244             }
245             long serial = IOUtils.readLong(inputStream);
246             return new MOFID(serial, storageId);
247         } catch (java.io.IOException JavaDoc ioException) {
248             throw new StorageIOException(ioException);
249         }
250     }
251
252     // implement Storage
253
public void writeMOFID (java.io.OutputStream JavaDoc outputStream, MOFID mofid)
254         throws StorageException
255     {
256         // NOTE: ripped from memoryimpl
257
try {
258             if (storageId.equals(mofid.getStorageID())) {
259                 IOUtils.writeString(outputStream, null);
260             } else {
261                 IOUtils.writeString(outputStream, mofid.getStorageID());
262             }
263             IOUtils.writeLong(outputStream, mofid.getSerialNumber());
264         } catch (IOException ioException) {
265             throw new StorageIOException(ioException);
266         }
267     }
268
269     DatabaseMetaData getDatabaseMetaData()
270     {
271         return dbMetaData;
272     }
273
274     private String JavaDoc getQualifiedTableName(String JavaDoc tableName)
275     {
276         if (realSchema) {
277             return idQuote + schemaName + idQuote + "." + idQuote
278                 + tableName + idQuote;
279         } else {
280             return idQuote + schemaName + "_" + tableName + idQuote;
281         }
282     }
283     
284     private String JavaDoc getQualifiedSchemaName()
285     {
286         return idQuote + schemaName + idQuote;
287     }
288
289     private void rollbackConnection()
290     {
291         closeResultSet();
292         if (jdbcConnection != null) {
293             try {
294                 jdbcConnection.rollback();
295             } catch (SQLException ex) {
296                 // TODO: trace
297
}
298         }
299     }
300
301     private long readSerialNumber()
302     {
303         try {
304             jdbcResultSet = jdbcStmt.executeQuery(
305                 "select * from "+getQualifiedTableName(MOFID_SEQ_TABLE_NAME));
306             jdbcResultSet.next();
307             long x = jdbcResultSet.getLong(1);
308             return x;
309         } catch (SQLException ex) {
310             return -1;
311         }
312     }
313     
314     // implement Storage
315
public synchronized boolean exists() throws StorageException
316     {
317         long x = readSerialNumber();
318         return x != -1;
319     }
320     
321     // implement Storage
322
public synchronized boolean delete() throws StorageException
323     {
324         rollbackConnection();
325         try {
326             if (realSchema) {
327                 jdbcResultSet = dbMetaData.getSchemas();
328                 boolean found = false;
329                 while (jdbcResultSet.next()) {
330                     String JavaDoc name = jdbcResultSet.getString(1);
331                     if (name.equals(schemaName)) {
332                         found = true;
333                         break;
334                     }
335                 }
336                 closeResultSet();
337                 if (!found) {
338                     // schema doesn't even exist
339
return true;
340                 }
341                 jdbcStmt.execute(
342                     "drop schema " + getQualifiedSchemaName() + " cascade");
343             } else {
344                 jdbcResultSet = dbMetaData.getTables(
345                     null,null,schemaName + "%",null);
346                 List tables = new ArrayList();
347                 while (jdbcResultSet.next()) {
348                     tables.add(jdbcResultSet.getString("TABLE_NAME"));
349                 }
350                 closeResultSet();
351                 Iterator iter = tables.iterator();
352                 while (iter.hasNext()) {
353                     String JavaDoc tableName = (String JavaDoc) iter.next();
354                     jdbcStmt.execute(
355                         "drop table " + idQuote + tableName + idQuote);
356                 }
357             }
358             jdbcConnection.commit();
359             return true;
360         } catch (SQLException ex) {
361             rollbackConnection();
362             return false;
363         }
364     }
365
366     private boolean isBlank(String JavaDoc s)
367     {
368         return (s == null) || (s.length() == 0);
369     }
370     
371     // implement Storage
372
public synchronized void create(boolean replace, ObjectResolver resolver)
373         throws StorageException
374     {
375         try {
376             if (replace) {
377                 delete();
378             }
379             rollbackConnection();
380             if (realSchema) {
381                 String JavaDoc sql = "create schema " + getQualifiedSchemaName();
382                 String JavaDoc authName = null;
383                 if (!isBlank(schemaAuthName)) {
384                     if (!schemaAuthName.equals("!NONE")) {
385                         authName = schemaAuthName;
386                     }
387                 } else if (!isBlank(userName)) {
388                     authName = userName;
389                 }
390                 if (authName != null) {
391                     sql = sql + " authorization " + authName;
392                 }
393                 jdbcStmt.execute(sql);
394             }
395             String JavaDoc intType = getDataType(EntryType.INT);
396             jdbcStmt.execute(
397                 "create table " + getQualifiedTableName(MOFID_SEQ_TABLE_NAME)
398                 + "(" + MOFID_SEQ_COL_NAME + " " + intType
399                 + " not null primary key)");
400             jdbcStmt.executeUpdate(
401                 "insert into " + getQualifiedTableName(MOFID_SEQ_TABLE_NAME)
402                 + " values(1)");
403             nextSerialNumber = firstSerialNumber;
404             openImpl();
405             createSinglevaluedIndex(
406                 PRIMARY_INDEX_NAME,
407                 EntryType.MOFID,
408                 EntryType.STREAMABLE);
409             loadPrimaryIndex();
410             jdbcConnection.commit();
411         } catch (SQLException ex) {
412             rollbackConnection();
413             throw newJdbcException(ex);
414         }
415     }
416     
417     // implement Storage
418
public synchronized void open(
419         boolean createOnNoExist, ObjectResolver resolver)
420         throws StorageException
421     {
422         nextSerialNumber = readSerialNumber();
423         if (nextSerialNumber == -1) {
424             if (createOnNoExist) {
425                 create(false,resolver);
426                 return;
427             } else {
428                 throw new StorageBadRequestException(
429                     "Storage " + getName() + " does not exist.");
430             }
431         }
432         try {
433             openImpl();
434             loadPrimaryIndex();
435         } catch (SQLException ex) {
436             throw newJdbcException(ex);
437         }
438     }
439
440     private void openImpl() throws SQLException
441     {
442         nameToIndexMap = new HashMap();
443         sqlUpdateSerialNumber = new LazyPreparedStatement(
444             "update " + getQualifiedTableName(MOFID_SEQ_TABLE_NAME)
445             + " set " + MOFID_SEQ_COL_NAME + " = ?");
446     }
447
448     private void loadPrimaryIndex()
449         throws StorageException
450     {
451         primaryIndex = (JdbcPrimaryIndex) getIndex(PRIMARY_INDEX_NAME);
452     }
453     
454     // implement Storage
455
public synchronized void close() throws StorageException
456     {
457         nameToIndexMap = null;
458         sqlUpdateSerialNumber = null;
459         closeAllPreparedStatements();
460         rollbackConnection();
461     }
462
463     private void closeAllPreparedStatements()
464     {
465         Iterator iter = sqlToPreparedStatementMap.values().iterator();
466         while (iter.hasNext()) {
467             PreparedStatement ps = (PreparedStatement) iter.next();
468             closePreparedStatement(ps);
469         }
470         iter = lazyPreparedStatements.iterator();
471         while (iter.hasNext()) {
472             LazyPreparedStatement lps = (LazyPreparedStatement) iter.next();
473             lps.ps = null;
474         }
475         sqlToPreparedStatementMap = new HashMap();
476         lazyPreparedStatements = new ArrayList();
477     }
478
479     private void closePreparedStatement(PreparedStatement ps)
480     {
481         if (ps == null) {
482             return;
483         }
484         try {
485             ps.close();
486         } catch (SQLException ex) {
487             // TODO: trace
488
}
489     }
490
491     private void closeStatement()
492     {
493         if (jdbcStmt == null) {
494             return;
495         }
496         try {
497             jdbcStmt.close();
498         } catch (SQLException ex) {
499             // TODO: trace
500
} finally {
501             jdbcStmt = null;
502         }
503     }
504
505     private void closeResultSet()
506     {
507         if (jdbcResultSet == null) {
508             return;
509         }
510         try {
511             jdbcResultSet.close();
512         } catch (SQLException ex) {
513             // TODO: trace
514
} finally {
515             jdbcResultSet = null;
516         }
517     }
518
519     private void closeConnection()
520     {
521         if (jdbcConnection == null) {
522             return;
523         }
524         try {
525             jdbcConnection.close();
526         } catch (SQLException ex) {
527             // TODO: trace
528
} finally {
529             jdbcConnection = null;
530         }
531     }
532
533     // implement Storage
534
public synchronized SinglevaluedIndex createSinglevaluedIndex(
535         String JavaDoc name, EntryType keyType,
536         EntryType valueType) throws StorageException
537     {
538         createIndex(name,keyType,valueType,true,true,false);
539         return getSinglevaluedIndex(name);
540     }
541
542     // implement Storage
543
public synchronized MultivaluedOrderedIndex createMultivaluedOrderedIndex(
544         String JavaDoc name, EntryType keyType, EntryType valueType, boolean unique)
545         throws StorageException
546     {
547         // NOTE: ignore unique because it appears to lie
548
createIndex(name,keyType,valueType,false,false,true);
549         return getMultivaluedOrderedIndex(name);
550     }
551
552     // implement Storage
553
public synchronized MultivaluedIndex createMultivaluedIndex(
554         String JavaDoc name, EntryType keyType, EntryType valueType, boolean unique)
555         throws StorageException
556     {
557         createIndex(name,keyType,valueType,false,unique,false);
558         return getMultivaluedIndex(name);
559     }
560
561     private String JavaDoc getDataType(EntryType entryType)
562     {
563         return (String JavaDoc) entryTypeToDataTypeMap.get(entryType);
564     }
565
566     private EntryType getEntryType(ResultSetMetaData md,int i)
567         throws SQLException
568     {
569         String JavaDoc colName = md.getColumnName(i).toUpperCase();
570         int lastUnderscore = colName.lastIndexOf('_');
571         String JavaDoc entryTypeName =
572             colName.substring(lastUnderscore + 1);
573         return EntryType.decodeEntryType(entryTypeName);
574     }
575
576     private String JavaDoc stripMofId(String JavaDoc indexName)
577     {
578         int i = indexName.indexOf(storageId);
579         if (i == -1) {
580             return indexName;
581         }
582         int j = i + storageId.length();
583         if (indexName.charAt(j) != ':') {
584             return indexName;
585         }
586         int n = indexName.length();
587         for (++j; j < n; ++j) {
588             if (indexName.charAt(j) != '0') {
589                 break;
590             }
591         }
592         return indexName.substring(0,i) + indexName.substring(j);
593     }
594     
595     private String JavaDoc getTableNameForIndex(String JavaDoc indexName)
596     {
597         // Assume we're getting something of the form
598
// <prefix>:<mofid1>:<mofid2> for indexName.
599
// Replace this with
600
// <prefix>_<serial1>_<serial2>
601
indexName = stripMofId(indexName);
602         indexName = stripMofId(indexName);
603         // MySQL doesn't like ':' even in quoted identifiers, so
604
// replace it with an innocuous underscore.
605
indexName = indexName.replace(':','_');
606         return getQualifiedTableName(indexName);
607     }
608     
609     private void createIndex(
610         String JavaDoc name, EntryType keyType, EntryType valueType,
611         boolean singleValued,boolean uniqueValued,boolean ordered)
612         throws StorageException
613     {
614         try {
615             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
616             sb.append("create table ");
617             sb.append(getTableNameForIndex(name));
618             sb.append("(");
619
620             String JavaDoc keyColName = KEY_COL_PREFIX + "_" + keyType;
621             sb.append(keyColName);
622             sb.append(" ");
623             sb.append(getDataType(keyType));
624             sb.append(" not null, ");
625
626             String JavaDoc valColName;
627             if (singleValued) {
628                 valColName = SINGLE_VAL_COL_PREFIX;
629             } else {
630                 valColName = MULTI_VAL_COL_PREFIX;
631             }
632             valColName = valColName + "_" + valueType;
633             sb.append(valColName);
634             sb.append(" ");
635             sb.append(getDataType(valueType));
636             sb.append(" not null,");
637
638             String JavaDoc intType = getDataType(EntryType.INT);
639             
640             if (ordered) {
641                 sb.append(ORDINAL_COL_NAME);
642                 sb.append(" ");
643                 sb.append(intType);
644                 sb.append(" not null,");
645             }
646
647             if (!uniqueValued) {
648                 sb.append(SURROGATE_COL_NAME);
649                 sb.append(" ");
650                 sb.append(intType);
651                 sb.append(" not null,");
652             }
653             
654             sb.append(" primary key(");
655             sb.append(keyColName);
656             if (singleValued) {
657                 // nothing more needed
658
} else if (uniqueValued) {
659                 sb.append(",");
660                 sb.append(valColName);
661             } else {
662                 if (ordered) {
663                     // NOTE: could use just (KEY,ORDINAL) as primary key.
664
// However, we have to be able to modify ordinals, and even
665
// PostgreSQL doesn't get the deferred constraint
666
// enforcement right in that case. So, throw in both the
667
// ORDINAL and the SURROGATE so that ORDER BY can use the
668
// index.
669
sb.append(",");
670                     sb.append(ORDINAL_COL_NAME);
671                 }
672                 sb.append(",");
673                 sb.append(SURROGATE_COL_NAME);
674             }
675             sb.append(")");
676             
677             sb.append(")");
678             jdbcStmt.execute(sb.toString());
679         } catch (SQLException ex) {
680             throw newJdbcException(ex);
681         }
682     }
683
684     // implement Storage
685
public synchronized SinglevaluedIndex getPrimaryIndex()
686         throws StorageException
687     {
688         return getSinglevaluedIndex(PRIMARY_INDEX_NAME);
689     }
690
691     private Index loadIndex(String JavaDoc name)
692         throws StorageException
693     {
694         PreparedStatement ps = null;
695         try {
696             ps = jdbcConnection.prepareStatement(
697                 "select * from "+getTableNameForIndex(name));
698             ResultSetMetaData md = null;
699             try {
700                 md = ps.getMetaData();
701             } catch (SQLException ex) {
702                 // Some drivers don't support metadata pre-execution.
703
// Fall through to recovery below.
704
}
705             if (md == null) {
706                 jdbcResultSet = ps.executeQuery();
707                 md = jdbcResultSet.getMetaData();
708             }
709             EntryType keyType = getEntryType(md,1);
710             EntryType valueType = getEntryType(md,2);
711             boolean singleValued = false;
712             boolean ordered = false;
713             boolean needSurrogate = false;
714             String JavaDoc keyColName = md.getColumnName(1).toUpperCase();
715             String JavaDoc valColName = md.getColumnName(2).toUpperCase();
716             if (valColName.startsWith(SINGLE_VAL_COL_PREFIX)) {
717                 singleValued = true;
718             }
719             for (int i = 3; i <= md.getColumnCount(); ++i) {
720                 String JavaDoc colName = md.getColumnName(i).toUpperCase();
721                 if (colName.equals(ORDINAL_COL_NAME)) {
722                     ordered = true;
723                 } else if (colName.equals(SURROGATE_COL_NAME)) {
724                     needSurrogate = true;
725                 } else {
726                     // TODO: assert
727
}
728             }
729             JdbcIndex index;
730             if (singleValued) {
731                 if (name.equals(PRIMARY_INDEX_NAME)) {
732                     index = new JdbcPrimaryIndex();
733                 } else {
734                     index = new JdbcSinglevaluedIndex();
735                 }
736             } else {
737                 if (ordered) {
738                     index = new JdbcMultivaluedOrderedIndex();
739                 } else {
740                     index = new JdbcMultivaluedIndex();
741                 }
742                 if (queryDuplicates && !needSurrogate) {
743                     ((JdbcMultivaluedIndex) index).queryDuplicates = true;
744                 }
745             }
746             index.init(
747                 this,
748                 getTableNameForIndex(name),
749                 name,keyColName,valColName,keyType,valueType,
750                 needSurrogate);
751             nameToIndexMap.put(name,index);
752             return index;
753         } catch (SQLException ex) {
754             throw newJdbcException(ex);
755         } finally {
756             closeResultSet();
757             closePreparedStatement(ps);
758         }
759     }
760
761     // implement Storage
762
public synchronized Index getIndex(String JavaDoc name) throws StorageException
763     {
764         synchronized(nameToIndexMap) {
765             Index index = (Index) nameToIndexMap.get(name);
766             if (index == null) {
767                 index = loadIndex(name);
768             }
769             return index;
770         }
771     }
772     
773     // implement Storage
774
public synchronized SinglevaluedIndex getSinglevaluedIndex(String JavaDoc name)
775         throws StorageException
776     {
777         return (SinglevaluedIndex) getIndex(name);
778     }
779     
780     // implement Storage
781
public synchronized MultivaluedIndex getMultivaluedIndex(String JavaDoc name)
782         throws StorageException
783     {
784         return (MultivaluedIndex) getIndex(name);
785     }
786     
787     // implement Storage
788
public synchronized MultivaluedOrderedIndex getMultivaluedOrderedIndex(
789         String JavaDoc name) throws StorageException
790     {
791         return (MultivaluedOrderedIndex) getIndex(name);
792     }
793     
794     // implement Storage
795
public synchronized void dropIndex(String JavaDoc name) throws StorageException
796     {
797         try {
798             jdbcStmt.execute("drop table "+getTableNameForIndex(name));
799         } catch (SQLException ex) {
800             throw newJdbcException(ex);
801         }
802         nameToIndexMap.remove(name);
803     }
804
805     // implement Storage
806
public void objectStateWillChange(Object JavaDoc key) throws StorageException
807     {
808         // ignore
809
}
810     
811     // implement Storage
812
public synchronized void objectStateChanged(Object JavaDoc key)
813         throws StorageException
814     {
815         primaryIndex.objectStateChanged(key);
816     }
817     
818     // implement Storage
819
public synchronized void commitChanges() throws StorageException
820     {
821         try {
822             writeSerialNumber(nextSerialNumber);
823             primaryIndex.flushChanges();
824             if (!dbMetaData.supportsOpenStatementsAcrossCommit()) {
825                 closeAllPreparedStatements();
826             }
827             jdbcConnection.commit();
828         } catch (SQLException ex) {
829             throw newJdbcException(ex);
830         }
831     }
832
833     // implement Storage
834
public synchronized void rollBackChanges () throws StorageException
835     {
836         try {
837             if (!dbMetaData.supportsOpenStatementsAcrossRollback()) {
838                 closeAllPreparedStatements();
839             }
840             jdbcConnection.rollback();
841         } catch (SQLException ex) {
842             throw newJdbcException(ex);
843         }
844         if (primaryIndex != null) {
845             primaryIndex.shutDown();
846         }
847         nameToIndexMap = new HashMap();
848         loadPrimaryIndex();
849     }
850     
851     // implement Storage
852
public synchronized void shutDown() throws StorageException
853     {
854         if (sqlUpdateSerialNumber != null) {
855             commitChanges();
856         }
857         closeStatement();
858         closeConnection();
859     }
860
861     private PreparedStatement prepareStatement(
862         LazyPreparedStatement lps)
863         throws StorageException
864     {
865         if (lps.ps != null) {
866             // lps is already prepared
867
return lps.ps;
868         }
869         lazyPreparedStatements.add(lps);
870         PreparedStatement ps = (PreparedStatement)
871             sqlToPreparedStatementMap.get(lps.sql);
872         if (ps != null) {
873             lps.ps = ps;
874             return ps;
875         }
876         try {
877             ps = jdbcConnection.prepareStatement(lps.sql);
878             sqlToPreparedStatementMap.put(lps.sql,ps);
879             lps.ps = ps;
880             return ps;
881         } catch (SQLException ex) {
882             throw newJdbcException(ex);
883         }
884     }
885
886     private void bindArgs(PreparedStatement ps,Object JavaDoc [] args)
887         throws SQLException, StorageException
888     {
889         if (args == null) {
890             return;
891         }
892         for (int i = 0; i < args.length; ++i) {
893             Object JavaDoc arg = args[i];
894             int iParam = i + 1;
895             if (arg instanceof MOFID) {
896                 MOFID mofid = (MOFID) arg;
897                 if (!mofid.getStorageID().equals(storageId)) {
898                     throw new IllegalArgumentException JavaDoc("Foreign MOFID");
899                 }
900                 ps.setLong(
901                     iParam,
902                     mofid.getSerialNumber());
903             } else if (arg instanceof Streamable) {
904                 ps.setBytes(
905                     iParam,
906                     writeByteArray((Streamable) arg));
907             } else {
908                 ps.setObject(
909                     iParam,
910                     arg);
911             }
912         }
913     }
914
915     private Object JavaDoc getResultObj(EntryType entryType)
916         throws StorageException, SQLException
917     {
918         if (entryType == EntryType.MOFID) {
919             return new MOFID(
920                 jdbcResultSet.getLong(1),
921                 storageId);
922         } else if (entryType == EntryType.STRING) {
923             return jdbcResultSet.getString(1);
924         } else if (entryType == EntryType.INT) {
925             return new Long JavaDoc(jdbcResultSet.getLong(1));
926         } else {
927             byte [] bytes = jdbcResultSet.getBytes(1);
928             // make a copy in case JDBC driver reuses buffer
929
byte [] copy = new byte[bytes.length];
930             System.arraycopy(bytes,0,copy,0,bytes.length);
931             return copy;
932         }
933     }
934
935     synchronized ListIterator getResultSetIterator(
936         LazyPreparedStatement lps,Object JavaDoc [] args,EntryType entryType)
937         throws StorageException
938     {
939         try {
940             PreparedStatement ps = prepareStatement(lps);
941             bindArgs(ps,args);
942             jdbcResultSet = ps.executeQuery();
943             // TODO: assert exactly one column
944
List list = new ArrayList();
945             try {
946                 while (jdbcResultSet.next()) {
947                     Object JavaDoc obj = getResultObj(entryType);
948                     list.add(obj);
949                 }
950             } finally {
951                 closeResultSet();
952             }
953             if (entryType == EntryType.STREAMABLE) {
954                 // Postprocess the returned byte arrays, converting them
955
// into real objects. Note that we do this outside of the
956
// main fetch loop to avoid nasty reentrancy issues.
957
ListIterator listIter = list.listIterator();
958                 while (listIter.hasNext()) {
959                     byte [] bytes = (byte []) listIter.next();
960                     listIter.set(readByteArray(bytes));
961                 }
962             }
963             return list.listIterator();
964         } catch (SQLException ex) {
965             throw newJdbcException(ex);
966         }
967     }
968
969     synchronized int getResultSetCount(
970         LazyPreparedStatement lps,Object JavaDoc [] args)
971         throws StorageException
972     {
973         try {
974             PreparedStatement ps = prepareStatement(lps);
975             bindArgs(ps,args);
976             jdbcResultSet = ps.executeQuery();
977             try {
978                 int n = 0;
979                 while (jdbcResultSet.next()) {
980                     ++n;
981                 }
982                 return n;
983             } finally {
984                 closeResultSet();
985             }
986         } catch (SQLException ex) {
987             throw newJdbcException(ex);
988         }
989     }
990
991     synchronized int getSingletonInt(
992         LazyPreparedStatement lps,Object JavaDoc [] args)
993         throws StorageException
994     {
995         try {
996             PreparedStatement ps = prepareStatement(lps);
997             bindArgs(ps,args);
998             jdbcResultSet = ps.executeQuery();
999             try {
1000                // TODO: assert exactly one column
1001
if (!jdbcResultSet.next()) {
1002                    return -1;
1003                }
1004                int n = jdbcResultSet.getInt(1);
1005                return n;
1006            } finally {
1007                closeResultSet();
1008            }
1009        } catch (SQLException ex) {
1010            throw newJdbcException(ex);
1011        }
1012    }
1013
1014    private byte [] writeByteArray(Streamable data)
1015        throws StorageException
1016    {
1017        try {
1018            ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
1019            DataOutputStream dataStream = new DataOutputStream(byteStream);
1020            dataStream.writeUTF(data.getClass().getName());
1021            data.write(dataStream);
1022            dataStream.flush();
1023            return byteStream.toByteArray();
1024        } catch (IOException ex) {
1025            throw new StorageIOException(ex);
1026        }
1027    }
1028
1029    private Streamable readByteArray(byte [] bytes)
1030        throws StorageException
1031    {
1032        ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
1033        DataInputStream dataStream = new DataInputStream(byteStream);
1034
1035        // TODO: rip classCode stuff from BtreeDatabase
1036
String JavaDoc className;
1037        Streamable data;
1038        
1039        try {
1040            className = dataStream.readUTF();
1041        } catch (IOException ex) {
1042            throw new StorageIOException(ex);
1043        }
1044        try {
1045            Class JavaDoc cls = Class.forName(className);
1046            data = (Streamable)cls.newInstance();
1047        } catch (Exception JavaDoc ex) {
1048            throw new StoragePersistentDataException(ex.getMessage());
1049        }
1050        if (data instanceof StorageClient) {
1051            ((StorageClient)data).setStorage(this);
1052        }
1053        data.read(dataStream);
1054        return data;
1055    }
1056
1057    synchronized int executeUpdate(LazyPreparedStatement lps,Object JavaDoc [] args)
1058        throws StorageException
1059    {
1060        try {
1061            PreparedStatement ps = prepareStatement(lps);
1062            bindArgs(ps,args);
1063            return ps.executeUpdate();
1064        } catch (SQLException ex) {
1065            throw newJdbcException(ex);
1066        }
1067    }
1068}
1069
1070// End JdbcStorage.java
1071
Popular Tags