TextIndex.java-extract the assignment
[aaf/authz.git] / auth / auth-core / src / main / java / org / onap / aaf / auth / local / TextIndex.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.auth.local;
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.io.RandomAccessFile;
27 import java.nio.ByteBuffer;
28 import java.nio.IntBuffer;
29 import java.nio.channels.FileChannel;
30 import java.util.ArrayList;
31 import java.util.Collections;
32 import java.util.LinkedList;
33 import java.util.List;
34
35 import org.onap.aaf.auth.local.DataFile.Token;
36 import org.onap.aaf.auth.local.DataFile.Token.Field;
37 import org.onap.aaf.misc.env.Env;
38 import org.onap.aaf.misc.env.TimeTaken;
39 import org.onap.aaf.misc.env.Trans;
40
41 public class TextIndex {
42     private static final int REC_SIZE=8;
43
44     private File file;
45     private DataFile dataFile=null;
46
47     public TextIndex(File theFile) {
48         file = theFile;
49     }
50
51     public void open() throws IOException {
52         dataFile = new DataFile(file,"r");
53         dataFile.open();
54     }
55
56     public void close() throws IOException {
57         if (dataFile!=null) {
58             dataFile.close();
59             dataFile=null;
60         }
61     }
62
63     public int find(Object key, AbsData.Reuse reuse, int offset) throws IOException {
64         return find(key,reuse.tokenData,reuse.getFieldData(),offset);
65     }
66
67     public int find(Object key, DataFile.Token dtok, Field df, int offset) throws IOException {
68         if (dataFile==null) {
69             throw new IOException("File not opened");
70         }
71         long hash = hashToLong(key.hashCode());
72         int min=0, max = (int)(dataFile.size()/REC_SIZE);
73         Token ttok = dataFile.new Token(REC_SIZE);
74         IntBuffer tib = ttok.getIntBuffer();
75         long lhash;
76         int curr;
77         while ((max-min)>100) {
78             curr=(min+(max-min)/2);
79             ttok.pos(curr*REC_SIZE);
80             tib.rewind();
81             lhash = hashToLong(tib.get());
82             if (lhash<hash) {
83                 min=curr+1;
84             } else if (lhash>hash) {
85                 max=curr-1;
86             } else {
87                 min=curr-40;
88                 max=curr+40;
89                 break;
90             }
91         }
92
93         List<Integer> entries = new ArrayList<>();
94         for (int i=min;i<=max;++i) {
95             ttok.pos(i*REC_SIZE);
96             tib.rewind();
97             lhash = hashToLong(tib.get());
98             if (lhash==hash) {
99                 entries.add(tib.get());
100             } else if (lhash>hash) {
101                 break;
102             }
103         }
104
105         for (Integer i : entries) {
106             dtok.pos(i);
107             if (df.at(offset).equals(key)) {
108                 return i;
109             }
110         }
111         return -1;
112     }
113
114
115     /*
116      * Have to change Bytes into a Long, to avoid the inevitable signs in the Hash
117      */
118     private static long hashToLong(int hash) {
119         long rv;
120         if (hash<0) {
121             rv = 0xFFFFFFFFL & hash;
122         } else {
123             rv = hash;
124         }
125         return rv;
126     }
127
128     public void create(final Trans trans,final DataFile data, int maxLine, char delim, int fieldOffset, int skipLines) throws IOException {
129         FileChannel fos;
130
131         List<Idx> list = new LinkedList<>(); // Some hashcodes will double... DO NOT make a set
132         TimeTaken tt2 = trans.start("Open Files", Env.SUB);
133         RandomAccessFile raf=null;
134         try {
135             try {
136                 raf = new RandomAccessFile(file,"rw");
137                 raf.setLength(0L);
138                 fos = raf.getChannel();
139             } finally {
140                 tt2.done();
141             }
142
143             try {
144
145                 Token t = data.new Token(maxLine);
146                 Field f = t.new Field(delim);
147
148                 int count = 0;
149                 if (skipLines>0) {
150                     trans.info().log("Skipping",skipLines,"line"+(skipLines==1?" in":"s in"),data.file().getName());
151                 }
152                 for (int i=0;i<skipLines;++i) {
153                     t.nextLine();
154                 }
155                 tt2 = trans.start("Read", Env.SUB);
156                 try {
157                     while (t.nextLine()) {
158                         list.add(new Idx(f.at(fieldOffset),t.pos()));
159                         ++count;
160                     }
161                 } finally {
162                     tt2.done();
163                 }
164                 trans.checkpoint("    Read " + count + " records");
165                 tt2 = trans.start("Sort List", Env.SUB);
166                 Collections.sort(list);
167                 tt2.done();
168                 tt2 = trans.start("Write Idx", Env.SUB);
169                 try {
170                     ByteBuffer bb = ByteBuffer.allocate(8*1024);
171                     IntBuffer ib = bb.asIntBuffer();
172                     for (Idx idx : list) {
173                         if (!ib.hasRemaining()) {
174                             fos.write(bb);
175                             ib.clear();
176                             bb.rewind();
177                         }
178                         ib.put(idx.hash);
179                         ib.put(idx.pos);
180                     }
181                     bb.limit(4*ib.position());
182                     fos.write(bb);
183                 } finally {
184                     tt2.done();
185                 }
186             } finally {
187                 fos.close();
188             }
189         } finally {
190             if (raf!=null) {
191                 raf.close(); // closed by fos
192             }
193         }
194     }
195
196     public class Iter {
197         private int idx;
198         private Token t;
199         private long end;
200         private IntBuffer ib;
201
202
203         public Iter() {
204             try {
205                 idx = 0;
206                 end = dataFile.size();
207                 t  = dataFile.new Token(REC_SIZE);
208                 ib = t.getIntBuffer();
209
210             } catch (IOException e) {
211                 end = -1L;
212             }
213         }
214
215         public int next() {
216             t.pos(idx);
217             ib.clear();
218             ib.get();
219             int rec = ib.get();
220             idx += REC_SIZE;
221             return rec;
222         }
223
224         public boolean hasNext() {
225             return idx<end;
226         }
227     }
228
229     private static class Idx implements Comparable<Idx> {
230         public int hash, pos;
231         public Idx(Object obj, int pos) {
232             hash = obj.hashCode();
233             this.pos = pos;
234         }
235
236         @Override
237         public int compareTo(Idx ib) {
238             long a = hashToLong(hash);
239             long b = hashToLong(ib.hash);
240             return a>b?1:a<b?-1:0;
241         }
242
243         /* (non-Javadoc)
244          * @see java.lang.Object#equals(java.lang.Object)
245          */
246         @Override
247         public boolean equals(Object o) {
248             if (o!=null && o instanceof Idx) {
249                 return hash == ((Idx)o).hash;
250             }
251             return false;
252         }
253
254         /* (non-Javadoc)
255          * @see java.lang.Object#hashCode()
256          */
257         @Override
258         public int hashCode() {
259             return hash;
260         }
261     }
262 }