KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > mdr > persistence > btreeimpl > btreestorage > BtreeStorage


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.btreeimpl.btreestorage;
20
21 import java.io.*;
22 import java.text.*;
23 import java.util.*;
24
25 import org.netbeans.mdr.persistence.btreeimpl.btreeindex.*;
26 import org.netbeans.mdr.persistence.*;
27 import org.netbeans.mdr.util.Logger;
28
29 /**
30  * This class implements Storage using Btree files. Almost all implementation
31  * is in BtreeDatabase, which see.
32  */

33 public class BtreeStorage implements Storage {
34
35     /* Key used to store value of @link #storageNumbersCounter. */
36     private static final String JavaDoc COUNTER_KEY = "counter";
37     
38     /* Suffix of the name of SinglevaluedIndex used to store storage ids -> codes mapping. */
39     private static final String JavaDoc MAP1_INDEX_PREFIX = "storageIds:";
40     
41     /* Suffix of the name of SinglevaluedIndex used to store storage codes -> ids mapping. */
42     private static final String JavaDoc MAP2_INDEX_PREFIX = "storageCodes:";
43     
44     /* The btree database we have opened */
45     private BtreeDatabase btreeDB;
46     
47     /*The cached mofid entry type info */
48     private transient EntryTypeInfo mofIdEntryTypeInfo;
49     
50     /*Buffer used for reading mofids */
51     private transient byte[] buffer = new byte[8];
52     
53     /* Our MOFID generator */
54     MofidGenerator gen;
55     
56     /* The name of our database */
57     private final String JavaDoc btreeDBName;
58     
59     String JavaDoc storageUUID;
60     
61     /* Object resolver */
62     private ObjectResolver resolver;
63     
64     /* Index storing storageId -> code of storageId mapping */
65     private SinglevaluedIndex storageIdsMap;
66     /* Index storing code of storageId -> storageId mapping */
67     private SinglevaluedIndex storageCodesMap;
68     /* Value of the last used code. */
69     private int storageNumbersCounter;
70     /* Cache for storageId -> integer mapping. */
71     private HashMap tempMap = null;
72     /* Cache for integer -> storageId mapping. */
73     private HashMap tempMap2 = null;
74     
75     private final Map properties;
76     
77     /** Create a BtreeStorage object. Note that this does not create
78      * or open the Btree repository
79      * @param name the name of the btree. This will be the base name
80      * for the btree files
81      */

82     public BtreeStorage(String JavaDoc name, Map properties) {
83         this.properties = properties;
84         Logger.getDefault().log("DATABASE: " + name);
85         btreeDBName = name;
86         storageUUID = (String JavaDoc) properties.get(BtreeFactory.STORAGE_UUID);
87         if (storageUUID != null)
88             Logger.getDefault().log("Storage UUID: " + storageUUID);
89         
90     }
91     
92     Object JavaDoc getProperty(String JavaDoc name) {
93         return properties.get(name);
94     }
95     
96     /** Return our name
97      */

98     public String JavaDoc getName() {
99         return btreeDBName;
100     }
101
102     /** Returns storage id
103      */

104     public synchronized String JavaDoc getStorageId() {
105         return gen.getMofidPrefix();
106     }
107     
108     public synchronized long getSerialNumber () {
109         return gen.getNextMofid();
110     }
111     
112     
113     /** determine if the btree currently exists
114      * @return true if it exists
115      */

116     public boolean exists() {
117         return BtreeDatabase.exists(btreeDBName);
118     }
119     
120     /** delete the btree repository.
121      * @return true if, at method end, there is no repository. false if
122      * the repository exists but could not be deleted for any reason
123      */

124     public synchronized boolean delete() throws StorageException {
125         checkRepositoryClosed();
126         return BtreeDatabase.delete(btreeDBName);
127     }
128     
129     /** Create btree repository
130      * @param replace whether to replace an existing repository
131      * @exception StorageException on any error creating the repository
132      */

133     public synchronized void create(boolean replace, ObjectResolver resolver) throws StorageException {
134         checkRepositoryClosed();
135         if (exists()) {
136             if (replace) {
137                 if (!delete()) {
138                     throw new StorageBadRequestException(
139                     MessageFormat.format(
140                     "Unable to delete btree repository {0}",
141                     new Object JavaDoc[] {btreeDBName} ) );
142                 }
143             }
144             else {
145                 throw new StorageBadRequestException(
146                 MessageFormat.format(
147                 "Btree repository {0} already exists",
148                 new Object JavaDoc[] {btreeDBName} ) );
149             }
150         }
151         
152         this.resolver = resolver;
153         btreeDB = new BtreeDatabase(btreeDBName, this, true);
154         gen = btreeDB.getMofidGenerator();
155         storageIdsMap = createSinglevaluedIndex (MAP1_INDEX_PREFIX,
156                             Storage.EntryType.STRING, Storage.EntryType.INT);
157         storageCodesMap = createSinglevaluedIndex (MAP2_INDEX_PREFIX,
158                             Storage.EntryType.INT, Storage.EntryType.STRING);
159     }
160     
161     /** Open a btree MDR
162      * @param createIfNoExist whether to create the repository if it
163      * doesn't exist
164      * @exception StorageException on any error opening or creating
165      * the repository
166      */

167     public synchronized void open(boolean createIfNoExist, ObjectResolver resolver)
168     throws StorageException {
169         checkRepositoryClosed();
170         if (exists()) {
171             this.resolver = resolver;
172             btreeDB = new BtreeDatabase(btreeDBName, this, false);
173             gen = btreeDB.getMofidGenerator();
174             storageIdsMap = getSinglevaluedIndex (MAP1_INDEX_PREFIX);
175             storageCodesMap = getSinglevaluedIndex (MAP2_INDEX_PREFIX);
176             return;
177         }
178         
179         if (createIfNoExist) {
180             create(false, resolver);
181             return;
182         }
183         
184         throw new StorageBadRequestException(
185         MessageFormat.format(
186         "Btree repository {0} does not exist",
187         new Object JavaDoc[] {btreeDBName} ) );
188     }
189     
190     /** close the btree repository. This does not commit any outstanding
191      * changes.
192      */

193     public synchronized void close() throws StorageException {
194         checkRepositoryOpen();
195         btreeDB.close();
196         btreeDB = null;
197         gen = null;
198         tempMap = null;
199     }
200     
201     /** Return the primary index (the BtreeDatabase)
202      */

203     public synchronized SinglevaluedIndex getPrimaryIndex() throws StorageException {
204         checkRepositoryOpen();
205         return btreeDB;
206     }
207     
208     /** Create index that holds exactly one value for each key.
209      * @return created index
210      * @param name name of the index
211      * @param keyType type of keys in the index
212      * @param valueType type of values in the index
213      */

214     
215     public synchronized SinglevaluedIndex createSinglevaluedIndex(String JavaDoc name, Storage.EntryType keyType, Storage.EntryType valueType) throws StorageException {
216         checkRepositoryOpen();
217         SinglevaluedBtree index =
218         new SinglevaluedBtree(name, keyType, valueType,
219         new BtreeMDRSource(this, BtreeDatabase.PAGE_SIZE));
220         btreeDB.addIndex(name, index, new MOFID(this));
221         return index;
222     }
223     
224     /** Create index that holds sorted set of values for each key.
225      * @return created index
226      * @param name name of the index
227      * @param keyType type of keys in the index
228      * @param valueType type of values in the index
229      * @param unique true if values associated with one key do not contain duplicates
230      */

231     public synchronized MultivaluedOrderedIndex createMultivaluedOrderedIndex(String JavaDoc name, Storage.EntryType keyType, Storage.EntryType valueType, boolean unique) throws StorageException {
232         checkRepositoryOpen();
233         MultivaluedOrderedBtree index =
234         new MultivaluedOrderedBtree(name, keyType, valueType, unique,
235         new BtreeMDRSource(this, BtreeDatabase.PAGE_SIZE));
236         btreeDB.addIndex(name, index, new MOFID(this));
237         return index;
238     }
239     
240     /** Create index that hold a set of values for each key. Elements in one Multivalued are
241      * not sorted. Set does not contain duplicate values.
242      * @return created index
243      * @param name name of the index
244      * @param keyType type of keys in the index
245      * @param valueType type of values in the index
246      * @param unique true if values associated with one key do not contain duplicates
247      */

248     public synchronized MultivaluedIndex createMultivaluedIndex(String JavaDoc name, Storage.EntryType keyType, Storage.EntryType valueType, boolean unique) throws StorageException {
249         checkRepositoryOpen();
250         MultivaluedBtree index =
251         new MultivaluedBtree(name, keyType, valueType, unique,
252         new BtreeMDRSource(this, BtreeDatabase.PAGE_SIZE));
253         btreeDB.addIndex(name, index, new MOFID(this));
254         return index;
255     }
256     
257     /** Retrieve index by name.
258      * @param name name of the index
259      * @return index of the specified name
260      */

261     public synchronized Index getIndex(String JavaDoc name) throws StorageException {
262         checkRepositoryOpen();
263         return (Index) btreeDB.fetchIndex(name);
264     }
265     
266     /** Retrieve index by name.
267      * @param name name of the index
268      * @return index of the specified name and type
269      */

270     public synchronized SinglevaluedIndex getSinglevaluedIndex(String JavaDoc name) throws StorageException {
271         Object JavaDoc idx = getIndex(name);
272         checkIndexType(idx, name, SinglevaluedIndex.class);
273         return (SinglevaluedIndex)idx;
274     }
275     
276     /** Retrieve index by name.
277      * @param name name of the index
278      * @return index of the specified name and type
279      */

280     public synchronized MultivaluedIndex getMultivaluedIndex(String JavaDoc name) throws StorageException {
281         Object JavaDoc idx = getIndex(name);
282         checkIndexType(idx, name, MultivaluedIndex.class);
283         return (MultivaluedIndex)idx;
284     }
285     
286     /** Retrieve index by name.
287      * @param name name of the index
288      * @return index of the specified name and type
289      */

290     public synchronized MultivaluedOrderedIndex getMultivaluedOrderedIndex(String JavaDoc name) throws StorageException {
291         Object JavaDoc idx = getIndex(name);
292         checkIndexType(idx, name, MultivaluedOrderedIndex.class);
293         return (MultivaluedOrderedIndex)idx;
294     }
295     
296     /** Delete index.
297      * @param name name of the index
298      */

299     public synchronized void dropIndex(String JavaDoc name) throws StorageException {
300         checkRepositoryOpen();
301         btreeDB.dropIndex(name);
302     }
303     
304     /** Notify the Storage that state of the object will be changed.
305      * @param key key of object that will be changed
306      */

307     public void objectStateWillChange(Object JavaDoc key) throws StorageException {
308         // do nothing
309
}
310     
311     /** Notify the Storage that state of the object was changed.
312      * @param key key of object that was changed
313      */

314     public synchronized void objectStateChanged(Object JavaDoc key) throws StorageException {
315         checkRepositoryOpen();
316         btreeDB.objectStateChanged(key);
317     }
318     
319     /** Save all objects changed since this method was last call.
320      * This operation implements transactions on the storage.
321      * It must either whole complete or whole fail.
322      */

323     public synchronized void commitChanges() throws StorageException {
324         checkRepositoryOpen();
325         btreeDB.commitChanges();
326     }
327     
328     /** Discard all changes since commitChanges() method was last called.
329      * This operation implements transactions on the storage.
330      * It must either whole complete or whole fail.
331      * Note that, after this method completes, the persistent MDR and
332      * any modified objects in memory are inconsistent, so it should
333      * be followed shortly by program exit.
334      */

335     public synchronized void rollBackChanges() throws StorageException {
336         checkRepositoryOpen();
337         btreeDB.rollbackChanges();
338         close();
339         open(false, resolver);
340     }
341     
342     /**
343      * Shutdowns btree databes (i.e. flushes cached commited data in transaction cache).
344      */

345     public synchronized void shutDown() throws StorageException {
346         checkRepositoryOpen();
347         btreeDB.shutDown();
348     }
349     
350     /** Returns true if the storage supports more than one index with type
351      * {@link Entrytype.STREAMABLE}
352      * @return true if the storage supports more than one index with type
353      * {@link Entrytype.STREAMABLE}
354      */

355     public boolean supportsMultipleStorableIndexes() {
356         /* Btree supports only one primary index */
357         return false;
358     }
359     
360     public synchronized void writeMOFID (java.io.OutputStream JavaDoc out, MOFID mofId) throws StorageException {
361        // this looks like it is not needed - MOFID's class is always org.netbeans.mdr.persistence.MOFID
362
// if (this.mofIdClassCode == -1) {
363
// this.mofIdClassCode = this.btreeDB.getClassCode (mofId.getClass());
364
// }
365

366        
367        /*
368        try {
369             out.writeInt (this.mofIdClassCode);
370        } catch (IOException ioException) {
371            throw new StorageIOException (ioException);
372        }
373        this.writeMOFIDData (out, mofId);
374         */

375        
376         // optimized write:
377
long mofidData = mofId.getSerialNumber();
378         String JavaDoc storageId = mofId.getStorageID();
379         short s;
380         if (this.getStorageId().equals(storageId)) {
381             s = (short) BtreeFactory.SAME_PREFIX_CODE;
382         } else if (BtreeFactory.INTERNAL_PREFIX.equals(storageId)) {
383             s = (short) BtreeFactory.INTERNAL_PREFIX_CODE;
384         } else {
385             s = (short) this.storageIdToNumber(storageId);
386         }
387         mofidData |= ((long) s) << 48;
388         try {
389             while (mofidData != 0) {
390                 int b = ((int) mofidData) & 0x7f;
391                 mofidData >>>= 7;
392                 if (mofidData != 0) b |= 0x80;
393                 out.write(b);
394             }
395         } catch (IOException e) {
396             throw (StorageException) Logger.getDefault().annotate(new StorageIOException(e), e);
397         }
398     }
399     
400     public final void writeMOFIDData (java.io.OutputStream JavaDoc out, MOFID mofid) throws StorageException {
401         try {
402             out.write (this.getMOFIDData(mofid));
403         } catch (IOException ioException) {
404             throw new StorageIOException (ioException);
405         }
406     }
407     
408     public synchronized final byte[] getMOFIDData (MOFID mofid) throws StorageException {
409         if (this.mofIdEntryTypeInfo == null) {
410            this.mofIdEntryTypeInfo = EntryTypeInfo.getEntryTypeInfo(Storage.EntryType.MOFID,this);
411        }
412        return this.mofIdEntryTypeInfo.toBuffer(mofid);
413     }
414      
415     // this method is always called from a thread safe code (readStreamable)
416
// thus it does not need to be synchronized
417
// if it shows up that it needs to be synchronized, a separate lock should be used
418
// for that to avoid deadlocks
419
public synchronized MOFID readMOFID (java.io.InputStream JavaDoc in) throws StorageException {
420
421         // optimized read:
422
long mofidData = 0;
423         try {
424             int b;
425             int i = 0;
426             do {
427                 b = in.read();
428                 mofidData |= ((long) (b & 0x7f)) << (i * 7);
429                 i++;
430             } while ((b & 0x80) != 0);
431             int storageNumber = (int) (mofidData >> 48);
432             String JavaDoc storageId;
433             switch (storageNumber) {
434                 case BtreeFactory.INTERNAL_PREFIX_CODE:
435                     storageId = BtreeFactory.INTERNAL_PREFIX;
436                 break;
437                 case BtreeFactory.SAME_PREFIX_CODE:
438                     storageId = this.getStorageId();
439                 break;
440                 default:
441                     storageId = this.numberToStorageId(storageNumber);
442             }
443             return new MOFID (mofidData & 0xffffffffffffL, storageId);
444         } catch (IOException e) {
445             throw (StorageException) Logger.getDefault().annotate(new StorageIOException(e), e);
446         }
447
448         /* let's rather do it in optimized way above
449         try {
450             int mofIdClassCode = in.readInt ();
451             if (mofIdClassCode != this.mofIdClassCode)
452                 throw new IllegalStateException ();
453             return this.readMOFIDData (in);
454         }catch (IOException ioException) {
455             throw new StorageIOException (ioException);
456         }
457          */

458     }
459     
460     public synchronized final MOFID readMOFIDData (java.io.InputStream JavaDoc in) throws StorageException {
461         if (this.mofIdEntryTypeInfo == null) {
462             this.mofIdEntryTypeInfo = EntryTypeInfo.getEntryTypeInfo(Storage.EntryType.MOFID, this);
463         }
464         try {
465             in.read (this.buffer);
466             return (MOFID) mofIdEntryTypeInfo.fromBuffer (this.buffer);
467         }catch (IOException ioException) {
468             throw new StorageIOException (ioException);
469         }
470     }
471     
472     /** Return the MOFID generator for this repository */
473     public synchronized MofidGenerator getMofidGenerator() {
474         return btreeDB.getMofidGenerator();
475     }
476     
477     /** Return the map of MOFID UUIDs we know about
478      */

479     public synchronized Map getMofidMap() {
480         return btreeDB.getMofidMap();
481     }
482     
483     /**
484      * Initializes storage id <-> storage code mapping.
485      */

486     private void initStorageIdsMap () throws StorageException {
487         Object JavaDoc value = storageIdsMap.getIfExists (COUNTER_KEY);
488         if (value == null) {
489             storageNumbersCounter = BtreeFactory.FIRST_EXTERNAL_CODE;
490             storageIdsMap.put (COUNTER_KEY, value = new Integer JavaDoc (storageNumbersCounter));
491         }
492         storageNumbersCounter = ((Integer JavaDoc) value).intValue ();
493         tempMap = new HashMap ();
494         tempMap2 = new HashMap ();
495     }
496     
497     /**
498      * Maps an external storage prefix to integer.
499      */

500     public synchronized int storageIdToNumber (String JavaDoc storageId) throws StorageException {
501         Object JavaDoc value;
502         if (tempMap == null)
503             initStorageIdsMap ();
504         value = tempMap.get (storageId);
505         if (value == null) {
506             value = storageIdsMap.getIfExists (storageId);
507             if (value == null) {
508                 storageNumbersCounter++;
509                 value = new Integer JavaDoc (storageNumbersCounter);
510                 storageIdsMap.replace (COUNTER_KEY, value);
511                 storageIdsMap.put (storageId, value);
512                 storageCodesMap.put (value, storageId);
513             }
514             tempMap.put (storageId, value);
515         }
516         return ((Integer JavaDoc) value).intValue ();
517     }
518     
519     /**
520      * Resolves external storage number coded by an integer.
521      */

522     public synchronized String JavaDoc numberToStorageId (int number) throws StorageException {
523         Object JavaDoc value;
524         if (tempMap == null)
525             initStorageIdsMap ();
526         Object JavaDoc code = new Integer JavaDoc (number);
527         value = tempMap2.get (code);
528         if (value == null) {
529             value = storageCodesMap.get (code);
530             if (value == null) {
531                 throw new StorageBadRequestException ("Unknown storage code requested: " + number);
532             }
533             tempMap2.put (code, value);
534         }
535         return (String JavaDoc) value;
536     }
537     
538     /**
539      * Delegates resolving of external mof ids on the object resolver.
540      */

541     public synchronized Object JavaDoc resolveObject (MOFID key) throws StorageException {
542         return resolver.resolve (key.getStorageID(), key);
543     }
544     
545     /* check that the returned index is of the correct type */
546     private void checkIndexType(Object JavaDoc idx, String JavaDoc idxName, Class JavaDoc idxType)
547     throws StorageException {
548         if (!idxType.isInstance(idx)) {
549             throw new StorageBadRequestException(
550             MessageFormat.format("{0} is not a {1}",
551             new Object JavaDoc[] { idxName, idxType.getName() } ) );
552         }
553     }
554     
555     /* We only operate on one repository at a time */
556     private void checkRepositoryClosed() throws StorageException {
557         if (btreeDB != null) {
558             throw new StorageBadRequestException(
559             MessageFormat.format(
560             "The btree repository {0} is already open",
561             new Object JavaDoc[] { btreeDBName} ) );
562         }
563     }
564     
565     /* Many operations aren't possible if the repsitory isn't open */
566     private void checkRepositoryOpen() throws StorageException {
567         if (btreeDB == null) {
568             throw new StorageBadRequestException(
569             MessageFormat.format(
570             "The btree repository {0} is not open",
571             new Object JavaDoc[] { btreeDBName} ) );
572         }
573     }
574         
575 }
576
577
Popular Tags