CompoundFileReader.java
001 package gate.creole.annic.apache.lucene.index;
002 
003 /**
004  * Copyright 2004 The Apache Software Foundation
005  *
006  * Licensed under the Apache License, Version 2.0 (the "License");
007  * you may not use this file except in compliance with the License.
008  * 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, software
013  * distributed under the License is distributed on an "AS IS" BASIS,
014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015  * See the License for the specific language governing permissions and
016  * limitations under the License.
017  */
018 
019 import gate.creole.annic.apache.lucene.store.Directory;
020 import gate.creole.annic.apache.lucene.store.InputStream;
021 import gate.creole.annic.apache.lucene.store.OutputStream;
022 import gate.creole.annic.apache.lucene.store.FSDirectory;
023 import gate.creole.annic.apache.lucene.store.Lock;
024 import java.util.HashMap;
025 import java.util.Iterator;
026 import java.io.IOException;
027 
028 
029 /**
030  * Class for accessing a compound stream.
031  * This class implements a directory, but is limited to only read operations.
032  * Directory methods that would normally modify data throw an exception.
033  *
034  @author Dmitry Serebrennikov
035  @version $Id: CompoundFileReader.java 529 2004-10-05 11:55:26Z niraj $
036  */
037 class CompoundFileReader extends Directory {
038 
039     private static final class FileEntry {
040         long offset;
041         long length;
042     }
043 
044 
045     // Base info
046     private Directory directory;
047     private String fileName;
048 
049     // Reference count
050     private boolean open;
051 
052     private InputStream stream;
053     private HashMap entries = new HashMap();
054 
055 
056     public CompoundFileReader(Directory dir, String name)
057     throws IOException
058     {
059         directory = dir;
060         fileName = name;
061 
062         boolean success = false;
063 
064         try {
065             stream = dir.openFile(name);
066 
067             // read the directory and init files
068             int count = stream.readVInt();
069             FileEntry entry = null;
070             for (int i=0; i<count; i++) {
071                 long offset = stream.readLong();
072                 String id = stream.readString();
073 
074                 if (entry != null) {
075                     // set length of the previous entry
076                     entry.length = offset - entry.offset;
077                 }
078 
079                 entry = new FileEntry();
080                 entry.offset = offset;
081                 entries.put(id, entry);
082             }
083 
084             // set the length of the final entry
085             if (entry != null) {
086                 entry.length = stream.length() - entry.offset;
087             }
088 
089             success = true;
090 
091         finally {
092             if (! success) {
093                 try {
094                     stream.close();
095                 catch (IOException e) { }
096             }
097         }
098     }
099 
100     public Directory getDirectory() {
101         return directory;
102     }
103 
104     public String getName() {
105         return fileName;
106     }
107 
108     public synchronized void close() throws IOException {
109         if (stream == null)
110             throw new IOException("Already closed");
111 
112         entries.clear();
113         stream.close();
114         stream = null;
115     }
116 
117     public synchronized InputStream openFile(String id)
118     throws IOException
119     {
120         if (stream == null)
121             throw new IOException("Stream closed");
122 
123         FileEntry entry = (FileEntryentries.get(id);
124         if (entry == null)
125             throw new IOException("No sub-file with id " + id + " found");
126 
127         return new CSInputStream(stream, entry.offset, entry.length);
128     }
129 
130     /** Returns an array of strings, one for each file in the directory. */
131     public String[] list() {
132         String res[] new String[entries.size()];
133         return (String[]) entries.keySet().toArray(res);
134     }
135 
136     /** Returns true iff a file with the given name exists. */
137     public boolean fileExists(String name) {
138         return entries.containsKey(name);
139     }
140 
141     /** Returns the time the named file was last modified. */
142     public long fileModified(String namethrows IOException {
143         return directory.fileModified(fileName);
144     }
145 
146     /** Set the modified time of an existing file to now. */
147     public void touchFile(String namethrows IOException {
148         directory.touchFile(fileName);
149     }
150 
151     /** Removes an existing file in the directory. */
152     public void deleteFile(String name)
153     {
154         throw new UnsupportedOperationException();
155     }
156 
157     /** Renames an existing file in the directory.
158     If a file already exists with the new name, then it is replaced.
159     This replacement should be atomic. */
160     public void renameFile(String from, String to)
161     {
162         throw new UnsupportedOperationException();
163     }
164 
165     /** Returns the length of a file in the directory. */
166     public long fileLength(String name)
167     throws IOException
168     {
169         FileEntry e = (FileEntryentries.get(name);
170         if (e == null)
171             throw new IOException("File " + name + " does not exist");
172         return e.length;
173     }
174 
175     /** Creates a new, empty file in the directory with the given name.
176       Returns a stream writing this file. */
177     public OutputStream createFile(String name)
178     {
179         throw new UnsupportedOperationException();
180     }
181 
182     /** Construct a {@link Lock}.
183      @param name the name of the lock file
184      */
185     public Lock makeLock(String name)
186     {
187         throw new UnsupportedOperationException();
188     }
189 
190     /** Implementation of an InputStream that reads from a portion of the
191      *  compound file. The visibility is left as "package" *only* because
192      *  this helps with testing since JUnit test cases in a different class
193      *  can then access package fields of this class.
194      */
195     static final class CSInputStream extends InputStream {
196 
197         InputStream base;
198         long fileOffset;
199 
200         CSInputStream(final InputStream base, final long fileOffset, final long length)
201           throws IOException
202         {
203             this.base = base;
204             this.fileOffset = fileOffset;
205             this.length = length;   // variable in the superclass
206         }
207 
208         /** Expert: implements buffer refill.  Reads bytes from the current
209          *  position in the input.
210          @param b the array to read bytes into
211          @param offset the offset in the array to start storing bytes
212          @param length the number of bytes to read
213          */
214         protected void readInternal(byte[] b, int offset, int len)
215         throws IOException
216         {
217             synchronized (base) {
218               long start = getFilePointer();
219               if(start + len > length) {
220                 System.out.println("I m in compound");
221                 throw new IOException("read past EOF");
222               }
223               base.seek(fileOffset + start);
224               base.readBytes(b, offset, len);
225             }
226         }
227 
228         /** Expert: implements seek.  Sets current position in this file, where
229          *  the next {@link #readInternal(byte[],int,int)} will occur.
230          @see #readInternal(byte[],int,int)
231          */
232         protected void seekInternal(long posthrows IOException {}
233 
234         /** Closes the stream to futher operations. */
235         public void close() throws IOException {}
236 
237     }
238 }