1 /* 2 * Copyright (c) 2008, 2017, 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.Collection; 40 import java.util.HashMap; 41 import java.util.List; 42 import java.util.Map; 43 import org.apache.lucene.store.Directory; 44 import org.apache.lucene.store.IOContext; 45 import org.apache.lucene.store.IndexInput; 46 import org.apache.lucene.store.IndexOutput; 47 import org.apache.lucene.store.Lock; 48 49 /** 50 * A very simple implementation of lucene Directory, it reads a index from the classpath in a directory called index 51 * under the package that contains this file. It depends on a "listAll.txt" file written into that directory containing 52 * the names of all the other files and their sizes. In the format "name:length" one file per line. When a file needs 53 * to be read the whole file is loaded into memory. 54 */ 55 public class ClasspathDirectory extends Directory { 56 private String[] allFiles; 57 private final Map<String,Long> fileLengthMap = new HashMap<>(); 58 59 public ClasspathDirectory() { 60 // load list of all files 61 try { 62 BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("index/listAll.txt"))); 63 String line; 64 List<String> fileNames = new ArrayList<>(); 65 while ((line = reader.readLine()) != null) { 66 String[] parts = line.split(":"); 67 fileNames.add(parts[0]); 68 fileLengthMap.put(parts[0], Long.parseLong(parts[1])); 69 } 70 reader.close(); 71 allFiles = fileNames.toArray(new String[fileNames.size()]); 72 } catch (IOException e) { 73 e.printStackTrace(); 74 } 75 } 76 77 @Override public String[] listAll() throws IOException { 78 return allFiles; 79 } 80 81 @Override public IndexInput openInput(String s, IOContext ioc) throws IOException { 82 return new ClassPathIndexInput( 83 s, 84 getClass().getResourceAsStream("index/"+s), 85 fileLengthMap.get(s).intValue() 86 ); 87 } 88 89 private static class ClassPathIndexInput extends IndexInput { 90 private byte[] data; 91 private int pointer = 0; 92 private int length; 93 94 private ClassPathIndexInput(String resourceDescription, InputStream in, int length) throws IOException { 95 super(resourceDescription); 96 this.length = length; 97 // read whole file into memory, so we can provide random access 98 data = new byte[length]; 99 // read in upto 20k chunks 100 // this is needed as the amount of bytes read in any call in not 101 // garenteed to be number asked for 102 final byte[] buf = new byte[1024*20]; 103 int offset = 0, remaining = length, read; 104 do { 105 read = in.read(buf,0,Math.min(remaining, buf.length)); 106 // copy read bytes to data 107 if (read > 0) { 108 System.arraycopy(buf, 0, data, offset, read); 109 offset += read; 110 remaining -= read; 111 } 112 } while (read != -1 && remaining > 0); 113 in.close(); 114 } 115 116 private ClassPathIndexInput(String resourceDescription, byte[] data) { 117 super(resourceDescription); 118 this.data = data; 119 this.pointer = 0; 120 this.length = data.length; 121 } 122 123 @Override public byte readByte() throws IOException { 124 return data[pointer ++]; 125 } 126 127 @Override public void readBytes(byte[] bytes, int offset, int len) throws IOException { 128 System.arraycopy(data, pointer, bytes, offset, len); 129 pointer += len; 130 } 131 132 @Override public void close() throws IOException {} 133 134 @Override public long getFilePointer() { return pointer; } 135 136 @Override public void seek(long l) throws IOException { pointer = (int)l; } 137 138 @Override public long length() { return length; } 139 140 @Override 141 public IndexInput slice(String sliceDescription, long offset, long length) throws IOException { 142 int o = (int) offset; 143 int l = (int) length; 144 byte[] sliceData = new byte[l]; 145 System.arraycopy(data, o, sliceData, 0, l); 146 return new ClassPathIndexInput(sliceDescription, sliceData); 147 } 148 } 149 150 @Override public void close() throws IOException {} 151 @Override public void deleteFile(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 152 @Override public long fileLength(String s) throws IOException { throw new UnsupportedOperationException("Not implemented"); } 153 @Override 154 public IndexOutput createOutput(String string, IOContext ioc) throws IOException { 155 throw new UnsupportedOperationException("Not implemented"); 156 } 157 158 @Override 159 public IndexOutput createTempOutput(String string, String string1, IOContext ioc) throws IOException { 160 throw new UnsupportedOperationException("Not implemented"); 161 } 162 163 @Override 164 public void sync(Collection<String> clctn) throws IOException { 165 throw new UnsupportedOperationException("Not implemented"); 166 } 167 168 @Override 169 public void rename(String string, String string1) throws IOException { 170 throw new UnsupportedOperationException("Not implemented"); 171 } 172 173 @Override 174 public void syncMetaData() throws IOException { 175 throw new UnsupportedOperationException("Not implemented"); 176 } 177 178 @Override 179 public Lock obtainLock(String string) throws IOException { 180 throw new UnsupportedOperationException("Not implemented"); 181 } 182 183 }