KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > FileStorage


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
20 package org.netbeans.editor.ext;
21
22 import java.io.File JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.RandomAccessFile JavaDoc;
25 import org.netbeans.editor.Analyzer;
26
27 /**
28 * Management of storage of the data for the java completion.
29 *
30 * @author Miloslav Metelka, Martin Roskanin
31 * @version 1.00
32 */

33
34 public class FileStorage {
35
36     /** Constant for checking the maximum size of the string.
37     * If the string size exceeds this value the error is thrown
38     * as there's very likely corruption of the file.
39     */

40     private static final int MAX_STRING = 60000;
41
42     private static final int BYTES_INCREMENT = 2048;
43
44     private static final byte[] EMPTY_BYTES = new byte[0];
45     
46     Thread JavaDoc currentLock;
47
48     protected boolean openedForWrite;
49     
50     public boolean fileNotFound = false;
51
52     protected DataAccessor da;
53     protected boolean opened = false;
54
55     /** Current offset in the bytes array */
56     protected int offset;
57
58     /** Byte array holding the data that were read from file */
59     protected byte[] bytes = EMPTY_BYTES;
60
61     /** Shared char array to use for reading strings */
62     char[] chars = Analyzer.EMPTY_CHAR_ARRAY;
63
64     /** String cache */
65     StringCache strCache;
66
67     /** How many times current writer requested writing */
68     private int lockDeep;
69     
70     /** file unlock without previous file lock */
71     private static final String JavaDoc WRITE_LOCK_MISSING
72     = "Unlock file without previous lock file"; // NOI18N
73

74     /** Version of read database file */
75     private int version = 1; // set to default version
76

77     /** 7th bit
78      * 1 - more bytes were used for encoding of the int value
79      * 0 - only one byte has been used. The int value is less than 128.
80      */

81     private static final int BIT7 = (1 << 7);
82     
83     /** 5th and 6th bit
84      * 6th | 5th
85      * 0 | 0 - 1 byte will succed
86      * 0 | 1 - 2 bytes will succed
87      * 1 | 0 - 3 bytes will succed
88      * 1 | 1 - 4 bytes will succed
89      */

90     private static final int BIT6 = (1 << 6);
91     private static final int BIT5 = (1 << 5);
92     
93     /** @param fileName name of file to operate over
94     */

95     public FileStorage(String JavaDoc fileName) {
96         this(fileName, new StringCache());
97     }
98     
99     public FileStorage(String JavaDoc fileName, StringCache strCache) {
100         da = new FileAccessor(new File JavaDoc(fileName));
101         this.strCache = strCache;
102     }
103     
104     public FileStorage(DataAccessor da, StringCache strCache){
105         this.da = da;
106         this.strCache = strCache;
107     }
108
109     /** Setter for version of Code Completion DB file. */
110     public void setVersion(int ver){
111         version = ver;
112     }
113     
114     public void open(boolean requestWrite) throws IOException JavaDoc {
115         if (openedForWrite == requestWrite) {
116             ensureOpen(requestWrite);
117             da.seek(getFileLength());
118             return; // already opened with correct type
119
} else { // opened with different type
120
close();
121         }
122
123         // open the file
124
ensureOpen(requestWrite);
125         da.seek(getFileLength());
126         openedForWrite = requestWrite;
127         offset = 0;
128     }
129
130     private void ensureOpen(boolean requestWrite) throws IOException JavaDoc {
131         if (!opened) {
132             da.open(requestWrite);
133             opened = true;
134         }
135     }
136     
137     
138     public void close() throws IOException JavaDoc {
139         opened = false;
140         da.close();
141     }
142
143     /** Check size of bytes[] array */
144     protected void checkBytesSize(int len) {
145         if (bytes.length < len) {
146             byte[] newBytes = new byte[len + BYTES_INCREMENT];
147             System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
148             bytes = newBytes;
149         }
150     }
151
152     /** Read some part of the file into the begining of bytes array
153     * and reset offset to zero.
154     */

155     public void read(int len) throws IOException JavaDoc {
156         checkBytesSize(len);
157         da.read(bytes, 0, len);
158         offset = 0;
159     }
160
161     /** Write bytes array (with offset length) to the file */
162     public void write() throws IOException JavaDoc {
163         if (offset > 0) {
164             da.append(bytes, 0, offset);
165         }
166         offset = 0;
167     }
168
169     public void seek(int filePointer) throws IOException JavaDoc {
170         da.seek(filePointer);
171     }
172
173     public String JavaDoc getFileName() {
174         return da.toString();
175     }
176
177     public int getFilePointer() throws IOException JavaDoc {
178         return (int)da.getFilePointer();
179     }
180
181     public void setOffset(int offset) {
182         this.offset = offset;
183     }
184
185     public int getOffset() {
186         return offset;
187     }
188
189     public int getFileLength() throws IOException JavaDoc {
190         return da.getFileLength();
191     }
192
193     public void resetBytes() {
194         bytes = EMPTY_BYTES;
195     }
196
197     /** Reset the size of the file and set current offset to zero. */
198     public void resetFile() throws IOException JavaDoc {
199         open(true);
200         offset = 0;
201         da.resetFile();
202         close();
203     }
204
205     /** Get the integer value from the bytes[] array */
206     public int getInteger() {
207         if (version == 1){
208             int i = bytes[offset++];
209             i = (i << 8) + (bytes[offset++] & 255);
210             i = (i << 8) + (bytes[offset++] & 255);
211             i = (i << 8) + (bytes[offset++] & 255);
212             return i;
213         }
214         
215         if (version == 2){
216             return decodeInteger();
217         }
218         return 0;
219     }
220
221     /** Get the string value from the bytes[] array */
222     public String JavaDoc getString() {
223         int len = getInteger(); // length of string
224

225         if (len < 0) {
226             throw new RuntimeException JavaDoc("Consistency error: read string length=" + len); // NOI18N
227
}
228         
229         if (len > MAX_STRING) {
230             throw new RuntimeException JavaDoc("FileStorage: String len is " + len // NOI18N
231
+ ". There's probably a corruption in the file '" // NOI18N
232
+ getFileName() + "'."); // NOI18N
233
}
234         
235         if(version == 1){
236             if (chars.length < len) { // check chars array size
237
chars = new char[2 * len];
238             }
239             for (int i = 0; i < len; i++) {
240                 chars[i] = (char)((bytes[offset] << 8) + (bytes[offset + 1] & 255));
241                 offset += 2;
242             }
243             
244             String JavaDoc s = null;
245             if (len >= 0) {
246                 if (strCache != null) {
247                     s = strCache.getString(chars, 0, len);
248                 } else { // no string cache
249
s = new String JavaDoc(chars, 0, len);
250                 }
251             }
252             
253             return s;
254             
255         }else if (version == 2){
256             try{
257                 String JavaDoc s = new String JavaDoc(bytes,offset,len,getEncoding());
258                 offset += len;
259                 return s;
260             }catch(java.io.UnsupportedEncodingException JavaDoc e){
261                 e.printStackTrace();
262                 return "";
263             }
264             catch(ArrayIndexOutOfBoundsException JavaDoc ex){
265                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc(len);
266                 for (int i=0;i<len;i++){
267                     sb.append((char)bytes[offset+i]);
268                 }
269                 String JavaDoc st = sb.toString();
270                 
271                 throw new RuntimeException JavaDoc("Debug of #12932: If this bug occurs, please send the stacktrace as attachment to Issuezilla's #12932."+"\n"+ // NOI18N
272
"http://www.netbeans.org/issues/show_bug.cgi?id=12932"+"\n"+ // NOI18N
273
"debug 2"+"\n"+ // NOI18N
274
"File:"+this.toString()+"\n"+ // NOI18N
275
"File Version:"+version+"\n"+ // NOI18N
276
"Offest: "+offset+"\n"+ // NOI18N
277
"Read length: "+len+"\n"+ // NOI18N
278
"bytes.length: "+bytes.length+"\n"+ // NOI18N
279
"String:"+st+"\n"+ // NOI18N
280
"Error:"+ex); // NOI18N
281
}
282         }
283         return "";
284     }
285
286     /** Put the integer into bytes[] array. It is stored as four bytes
287     * in big endian.
288     */

289     public void putInteger(int i) {
290         if (version == 1){
291             checkBytesSize(offset + 4); // int size
292
bytes[offset + 3] = (byte)(i & 255);
293             i >>>= 8;
294             bytes[offset + 2] = (byte)(i & 255);
295             i >>>= 8;
296             bytes[offset + 1] = (byte)(i & 255);
297             i >>>= 8;
298             bytes[offset] = (byte)i;
299             offset += 4;
300         }
301         
302         if (version == 2){
303             encodeInteger(i);
304         }
305     }
306
307     /** Put the string into bytes[] array. First the length is stored
308     * by putInteger() and then all the characters as two bytes each in big
309     * endian.
310     */

311     public void putString(String JavaDoc s) {
312         if (s == null) {
313             return;
314         }
315         
316         if (version == 1){
317             int len = s.length();
318             putInteger(len);
319             
320             if (len > 0) {
321                 checkBytesSize(offset + len * 2);
322                 for (int i = 0; i < len; i++) {
323                     char ch = s.charAt(i);
324                     bytes[offset + 1] = (byte)(ch & 255);
325                     ch >>>= 8;
326                     bytes[offset] = (byte)(ch & 255);
327                     offset += 2;
328                 }
329             }
330         }else if (version == 2){
331         /* Encode string to appropriate byte array
332          * according to the version of file */

333             byte encodedBytes[];
334             try{
335                 encodedBytes = s.getBytes(getEncoding());
336             }catch(java.io.UnsupportedEncodingException JavaDoc e){
337                 return;
338             }
339             
340             /* put the length of encoded byte array */
341             int len = java.lang.reflect.Array.getLength(encodedBytes);
342             if (len < 0) {
343                 return;
344             }
345             putInteger(len);
346             
347             checkBytesSize(offset + len);
348             System.arraycopy(encodedBytes,0,bytes,offset,len);
349             offset += len;
350         }
351     }
352
353     /** Returns decoded integer */
354     private int decodeInteger(){
355         int i = bytes[offset++]&255;
356         if ((i & BIT7) == 0){
357             return i;
358         }
359         int level = 1;
360         if ((i & BIT6)!= 0) level +=2;
361         if ((i & BIT5)!= 0) level +=1;
362         i &= ~(BIT7 | BIT6 | BIT5); // reset first three bits.
363

364         for(int j=1; j<=level; j++){
365             i = (i << 8) + (bytes[offset++]&255);
366         }
367         return i;
368     }
369     
370
371     /** Encodes the given Integer */
372     private void encodeInteger(int y){
373         int level = 0;
374         
375         if (y >= 536870912) level += 4; //256*256*256*32
376
else if (y >= 2097152) level += 3; //256*256*32
377
else if (y >= 8192) level += 2; //256*32
378
else if (y >= 128) level += 1; //128
379

380         checkBytesSize(offset + level + 1); // adjust the byte array
381

382         for (int j=level; j>0; j--){
383             bytes[offset+j] = (byte) (y & 255);
384             y >>>= 8;
385         }
386
387         bytes[offset] = (byte) y;
388         
389         // set compression type bits.
390
switch( level ) {
391             case 2:
392                 bytes[offset] |= BIT5;
393                 break;
394             case 3:
395                 bytes[offset] |= BIT6;
396                 break;
397             case 4:
398                 bytes[offset] |= BIT5;
399                 bytes[offset] |= BIT6;
400                 break;
401         }
402         if (level > 0) bytes[offset] |= BIT7; // Setting compression flag
403
level++;
404         offset += level;
405     }
406     
407     /** Get encoding according to file version */
408     private String JavaDoc getEncoding(){
409         switch( version ) {
410             case 1:
411                 return "UTF-16BE"; //NOI18N
412
case 2:
413                 return "UTF-8"; //NOI18N
414
default:
415                 return "UTF-16BE"; //NOI18N
416
}
417     }
418     
419     /** Locks the file and disable other threads to write */
420     public synchronized final void lockFile() {
421         if ((currentLock == null) || (Thread.currentThread() != currentLock)) {
422             try{
423                 if (currentLock == null){
424                     currentLock = Thread.currentThread();
425                     lockDeep = 0;
426                 }else{
427                     wait();
428                 }
429             }catch(InterruptedException JavaDoc ie){
430                 throw new RuntimeException JavaDoc(ie.toString());
431             }catch(IllegalMonitorStateException JavaDoc imse){
432                 throw new RuntimeException JavaDoc(imse.toString());
433             }
434         } else { // inner locking block
435
lockDeep++; // only increase write deepness
436
}
437     }
438
439     /** Unlocks the file and notifies wqiting threads */
440     public synchronized final void unlockFile() {
441         if (Thread.currentThread() != currentLock) {
442             throw new RuntimeException JavaDoc(WRITE_LOCK_MISSING);
443         }
444         if (lockDeep == 0) { // most outer locking block
445
resetBytes();
446             notify();
447             currentLock=null;
448         } else { // just inner locking block
449
lockDeep--;
450         }
451     }
452     
453     /** Returns name of the file */
454     public String JavaDoc toString(){
455         return getFileName();
456     }
457
458 }
459
Popular Tags