1 /* 2 * Copyright (c) 2008, 2014, Oracle and/or its affiliates. 3 * All rights reserved. Use is subject to license terms. 4 * 5 * This file is available and licensed under the following license: 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the distribution. 16 * - Neither the name of Oracle Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package ensemble.search; 33 34 import java.io.BufferedReader; 35 import java.io.IOException; 36 import java.io.InputStream; 37 import java.io.InputStreamReader; 38 import java.util.ArrayList; 39 import java.util.HashMap; 40 import java.util.List; 41 import java.util.Map; 42 import org.apache.lucene.store.Directory; 43 import org.apache.lucene.store.IndexInput; 44 import org.apache.lucene.store.IndexOutput; 45 46 /** 47 * A very simple implementation of lucene Directory, it reads a index from the classpath in a directory called index 48 * under the package that contains this file. It depends on a "listAll.txt" file written into that directory containing 49 * the names of all the other files and their sizes. In the format "name:length" one file per line. When a file needs 50 * to be read the whole file is loaded into memory. 51 */ 52 public class ClasspathDirectory extends Directory { 53 private String[] allFiles; 54 private final Map<String,Long> fileLengthMap = new HashMap<>(); 55 56 public ClasspathDirectory() { 57 // load list of all files 58 try { 59 BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("index/listAll.txt"))); 60 String line; 61 List<String> fileNames = new ArrayList<>(); 62 while ((line = reader.readLine()) != null) { 63 String[] parts = line.split(":"); 64 fileNames.add(parts[0]); 65 fileLengthMap.put(parts[0], Long.parseLong(parts[1])); 66 } 67 reader.close(); 68 allFiles = fileNames.toArray(new String[fileNames.size()]); 69 } catch (IOException e) { 70 e.printStackTrace(); 71 } 72 } 73 74 @Override public String[] listAll() throws IOException { 75 return allFiles; 76 } 77 78 @Override public IndexInput openInput(String s) throws IOException { 79 return new ClassPathIndexInput( 80 getClass().getResourceAsStream("index/"+s), 81 fileLengthMap.get(s).intValue() 82 ); 83 } 84 85 private static class ClassPathIndexInput extends IndexInput { 86 private byte[] data; 87 private int pointer = 0; 88 private int length; 89 90 private ClassPathIndexInput(InputStream in, int length) throws IOException { 91 this.length = length; 92 // read whole file into memory, so we can provide random access 93 data = new byte[length]; 94 // read in upto 20k chunks 95 // this is needed as the amount of bytes read in any call in not 96 // garenteed to be number asked for 97 final byte[] buf = new byte[1024*20]; 98 int offset = 0, remaining = length, read; 99 do { 100 read = in.read(buf,0,Math.min(remaining, buf.length)); 101 // copy read bytes to data 102 if (read > 0) { 103 System.arraycopy(buf, 0, data, offset, read); 104 offset += read; 105 remaining -= read; 106 } 107 } while (read != -1 && remaining > 0); 108 in.close(); 109 } 110 111 @Override public byte readByte() throws IOException { 112 return data[pointer ++]; 113 } 114 115 @Override public void readBytes(byte[] bytes, int offset, int len) throws IOException { 116 System.arraycopy(data, pointer, bytes, offset, len); 117 pointer += len; 118 } 119 120 @Override public void close() throws IOException {} 121 122 @Override public long getFilePointer() { return pointer; } 123 124 @Override public void seek(long l) throws IOException { pointer = (int)l; } 125 126 @Override public long length() { return length; } 127 } 128 129 @Override public void close() throws IOException {} 130 @Override public boolean fileExists(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 131 @Override public long fileModified(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 132 @Override @Deprecated public void touchFile(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 133 @Override public void deleteFile(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 134 @Override public long fileLength(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 135 @Override public IndexOutput createOutput(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 136 }