001: // kelondroStack.java
002: // -----------------------
003: // part of The Kelondro Database
004: // (C) by Michael Peter Christen; mc@anomic.de
005: // first published on http://www.anomic.de
006: // Frankfurt, Germany, 2004
007: // last change: 11.01.2004
008: //
009: // This program is free software; you can redistribute it and/or modify
010: // it under the terms of the GNU General Public License as published by
011: // the Free Software Foundation; either version 2 of the License, or
012: // (at your option) any later version.
013: //
014: // This program is distributed in the hope that it will be useful,
015: // but WITHOUT ANY WARRANTY; without even the implied warranty of
016: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017: // GNU General Public License for more details.
018: //
019: // You should have received a copy of the GNU General Public License
020: // along with this program; if not, write to the Free Software
021: // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: //
023: // Using this software in any meaning (reading, learning, copying, compiling,
024: // running) means that you agree that the Author(s) is (are) not responsible
025: // for cost, loss of data or any harm that may be caused directly or indirectly
026: // by usage of this softare or this documentation. The usage of this software
027: // is on your own risk. The installation and usage (starting/running) of this
028: // software may allow other people or application to access your computer and
029: // any attached devices and is highly dependent on the configuration of the
030: // software which must be done by the user of the software; the author(s) is
031: // (are) also not responsible for proper configuration and usage of the
032: // software, even if provoked by documentation provided together with
033: // the software.
034: //
035: // Any changes to this file according to the GPL as documented in the file
036: // gpl.txt aside this file in the shipment you received can be done to the
037: // lines that follows this copyright notice here, but changes must not be
038: // done inside the copyright notive above. A re-distribution must contain
039: // the intact and unchanged copyright notice.
040: // Contributions and changes to the program code must be marked as such.
041:
042: /*
043: This class extends the kelondroRecords and adds a stack structure
044: */
045:
046: package de.anomic.kelondro;
047:
048: import java.io.BufferedReader;
049: import java.io.File;
050: import java.io.FileReader;
051: import java.io.IOException;
052: import java.io.RandomAccessFile;
053: import java.util.Iterator;
054: import java.util.StringTokenizer;
055:
056: public final class kelondroStack extends kelondroFullRecords {
057:
058: // define the Over-Head-Array
059: private static short this OHBytes = 0; // our record definition does not need extra bytes
060: private static short this OHHandles = 2; // and two handles overhead for a double-chained list
061: private static short this FHandles = 2; // two file handles for root handle and handle to last element
062:
063: // define pointers for OH array access
064: protected static final int left = 0; // pointer for OHHandle-array: handle()-Value of left child Node
065: protected static final int right = 1; // pointer for OHHandle-array: handle()-Value of right child Node
066: protected static final int root = 0; // pointer for FHandles-array: pointer to root node
067: protected static final int toor = 1; // pointer for FHandles-array: pointer to root node
068:
069: public kelondroStack(File file, kelondroRow rowdef)
070: throws IOException {
071: // this creates a new stack
072: super (file, this OHBytes, this OHHandles, rowdef, this FHandles,
073: rowdef.columns() /* txtProps */, 80 /* txtPropWidth */);
074: if (super .fileExisted) {
075: //if ((getHandle(root) == null) && (getHandle(toor) == null)) clear();
076: } else {
077: setHandle(root, null); // define the root value
078: setHandle(toor, null); // define the toor value
079: }
080: }
081:
082: public static final kelondroStack open(File file, kelondroRow rowdef) {
083: try {
084: return new kelondroStack(file, rowdef);
085: } catch (IOException e) {
086: file.delete();
087: try {
088: return new kelondroStack(file, rowdef);
089: } catch (IOException ee) {
090: System.out
091: .println("kelondroStack: cannot open or create file "
092: + file.toString());
093: e.printStackTrace();
094: ee.printStackTrace();
095: return null;
096: }
097: }
098: }
099:
100: public static kelondroStack reset(kelondroStack stack) {
101: // memorize settings to this file
102: File f = new File(stack.filename);
103: kelondroRow row = stack.row();
104:
105: // close and delete the file
106: try {
107: stack.close();
108: } catch (Exception e) {
109: }
110: if (f.exists())
111: f.delete();
112:
113: // re-open a database with same settings as before
114: return open(f, row);
115: }
116:
117: public Iterator<kelondroRow.Entry> stackIterator(boolean up) {
118: // iterates the elements in an ordered way.
119: // returns kelondroRow.Entry - type Objects
120: return new stackIterator(up);
121: }
122:
123: public class stackIterator implements Iterator<kelondroRow.Entry> {
124: kelondroHandle nextHandle = null;
125: kelondroHandle lastHandle = null;
126: boolean up;
127:
128: public stackIterator(boolean up) {
129: this .up = up;
130: nextHandle = getHandle((up) ? root : toor);
131: }
132:
133: public boolean hasNext() {
134: return (nextHandle != null);
135: }
136:
137: public kelondroRow.Entry next() {
138: lastHandle = nextHandle;
139: try {
140: nextHandle = new EcoNode(nextHandle)
141: .getOHHandle((up) ? right : left);
142: return row().newEntry(
143: new EcoNode(lastHandle).getValueRow());
144: } catch (IOException e) {
145: throw new kelondroException(filename,
146: "IO error at Counter:next()");
147: }
148: }
149:
150: public void remove() {
151: try {
152: unlinkNode(new EcoNode(lastHandle));
153: } catch (IOException e) {
154: e.printStackTrace();
155: }
156: }
157: }
158:
159: public int size() {
160: return super .size();
161: }
162:
163: public synchronized void push(kelondroRow.Entry row)
164: throws IOException {
165: // check if there is already a stack
166: if (getHandle(toor) == null) {
167: if (getHandle(root) != null)
168: throw new RuntimeException(
169: "push: internal organisation of root and toor");
170: // create node
171: kelondroNode n = new EcoNode(row.bytes());
172: n.setOHHandle(left, null);
173: n.setOHHandle(right, null);
174: n.commit();
175: // assign handles
176: setHandle(root, n.handle());
177: setHandle(toor, n.handle());
178: // thats it
179: } else {
180: // expand the list at the end
181: kelondroNode n = new EcoNode(row.bytes());
182: n.setOHHandle(left, getHandle(toor));
183: n.setOHHandle(right, null);
184: kelondroNode n1 = new EcoNode(getHandle(toor));
185: n1.setOHHandle(right, n.handle());
186: n.commit();
187: n1.commit();
188: // assign handles
189: setHandle(toor, n.handle());
190: // thats it
191: }
192: }
193:
194: public synchronized kelondroRow.Entry pop() throws IOException {
195: // return row ontop of the stack and shrink stack by one
196: kelondroNode n = topNode();
197: if (n == null)
198: return null;
199: kelondroRow.Entry ret = row().newEntry(n.getValueRow());
200:
201: // remove node
202: unlinkNode(n);
203: deleteNode(n.handle());
204:
205: return ret;
206: }
207:
208: public synchronized kelondroRow.Entry top() throws IOException {
209: // return row ontop of the stack
210: kelondroNode n = topNode();
211: if (n == null)
212: return null;
213: return row().newEntry(n.getValueRow());
214: }
215:
216: public synchronized kelondroRow.Entry pot() throws IOException {
217: // return row on the bottom of the stack and remove record
218: kelondroNode n = botNode();
219: if (n == null)
220: return null;
221: kelondroRow.Entry ret = row().newEntry(n.getValueRow());
222:
223: // remove node
224: unlinkNode(n);
225: deleteNode(n.handle());
226:
227: return ret;
228: }
229:
230: public synchronized kelondroRow.Entry bot() throws IOException {
231: // return row on the bottom of the stack
232: kelondroNode n = botNode();
233: if (n == null)
234: return null;
235: return row().newEntry(n.getValueRow());
236: }
237:
238: private void unlinkNode(kelondroNode n) throws IOException {
239: // join chaines over node
240: kelondroHandle l = n.getOHHandle(left);
241: kelondroHandle r = n.getOHHandle(right);
242: // look left
243: if (l == null) {
244: // reached the root on left side
245: setHandle(root, r);
246: } else {
247: // un-link the previous record
248: kelondroNode k = new EcoNode(l);
249: k.setOHHandle(left, k.getOHHandle(left));
250: k.setOHHandle(right, r);
251: k.commit();
252: }
253: // look right
254: if (r == null) {
255: // reached the root on right side
256: setHandle(toor, l);
257: } else {
258: // un-link the following record
259: kelondroNode k = new EcoNode(r);
260: k.setOHHandle(left, l);
261: k.setOHHandle(right, k.getOHHandle(right));
262: k.commit();
263: }
264: }
265:
266: private kelondroNode topNode() throws IOException {
267: // return node ontop of the stack
268: if (size() == 0)
269: return null;
270: kelondroHandle h = getHandle(toor);
271: if (h == null)
272: return null;
273: return new EcoNode(h);
274: }
275:
276: private kelondroNode botNode() throws IOException {
277: // return node on bottom of the stack
278: if (size() == 0)
279: return null;
280: kelondroHandle h = getHandle(root);
281: if (h == null)
282: return null;
283: return new EcoNode(h);
284: }
285:
286: public int imp(File file, String separator) throws IOException {
287: // imports a value-separated file, returns number of records that have been read
288: RandomAccessFile f = null;
289: try {
290: f = new RandomAccessFile(file, "r");
291: String s;
292: StringTokenizer st;
293: int recs = 0;
294: kelondroRow.Entry buffer = row().newEntry();
295: int c;
296: int line = 0;
297: while ((s = f.readLine()) != null) {
298: s = s.trim();
299: line++;
300: if ((s.length() > 0) && (!(s.startsWith("#")))) {
301: st = new StringTokenizer(s, separator);
302: // buffer the entry
303: c = 0;
304: while ((c < row().columns())
305: && (st.hasMoreTokens())) {
306: buffer.setCol(c++, st.nextToken().trim()
307: .getBytes());
308: }
309: if ((st.hasMoreTokens()) || (c != row().columns())) {
310: System.err
311: .println("inapropriate number of entries in line "
312: + line);
313: } else {
314: push(buffer);
315: recs++;
316: }
317:
318: }
319: }
320: return recs;
321: } finally {
322: if (f != null)
323: try {
324: f.close();
325: } catch (Exception e) {
326: }
327: }
328: }
329:
330: public String hp(kelondroHandle h) {
331: if (h == null)
332: return "NULL";
333: else
334: return h.toString();
335: }
336:
337: public void print() throws IOException {
338: super .print();
339: Iterator<kelondroRow.Entry> it = stackIterator(true);
340: kelondroRow.Entry r;
341: while (it.hasNext()) {
342: r = it.next();
343: System.out.print(" KEY:'" + r.getColString(0, null) + "'");
344: for (int j = 1; j < row().columns(); j++)
345: System.out.print(", V[" + j + "]:'"
346: + r.getColString(j, null) + "'");
347: System.out.println();
348: }
349: System.out.println();
350: }
351:
352: private static void cmd(String[] args) {
353: System.out.print("kelondroStack ");
354: for (int i = 0; i < args.length; i++)
355: System.out.print(args[i] + " ");
356: System.out.println("");
357: byte[] ret = null;
358: kelondroRow lens = new kelondroRow("byte[] key-"
359: + Integer.parseInt(args[1]) + ", byte[] value-"
360: + Integer.parseInt(args[2]),
361: kelondroNaturalOrder.naturalOrder, 0);
362: try {
363: if ((args.length > 4) || (args.length < 2)) {
364: System.err
365: .println("usage: kelondroStack -c|-p|-v|-g|-i|-s [file]|[key [value]] <db-file>");
366: System.err
367: .println("( create, push, view, (g)pop, imp, shell)");
368: System.exit(0);
369: } else if (args.length == 2) {
370: kelondroStack fm = new kelondroStack(new File(args[1]),
371: lens);
372: if (args[0].equals("-v")) {
373: fm.print();
374: ret = null;
375: } else if (args[0].equals("-g")) {
376: fm = new kelondroStack(new File(args[1]), lens);
377: kelondroRow.Entry ret2 = fm.pop();
378: ret = ((ret2 == null) ? null : ret2.getColBytes(1));
379: fm.close();
380: }
381: fm.close();
382: } else if (args.length == 3) {
383: if (args[0].equals("-i")) {
384: kelondroStack fm = new kelondroStack(new File(
385: args[2]), lens);
386: int i = fm.imp(new File(args[1]), ";");
387: fm.close();
388: ret = (i + " records imported").getBytes();
389: } else if (args[0].equals("-s")) {
390: String db = args[2];
391: BufferedReader f = null;
392: try {
393: f = new BufferedReader(new FileReader(args[1]));
394:
395: String m;
396: while (true) {
397: m = f.readLine();
398: if (m == null)
399: break;
400: if ((m.length() > 1)
401: && (!m.startsWith("#"))) {
402: m = m + " " + db;
403: cmd(line2args(m));
404: }
405: }
406: ret = null;
407: } finally {
408: if (f != null)
409: try {
410: f.close();
411: } catch (Exception e) {
412: }
413: }
414: } else if (args[0].equals("-g")) {
415: kelondroStack fm = new kelondroStack(new File(
416: args[2]), lens);
417: kelondroRow.Entry ret2 = fm.pop();
418: ret = ((ret2 == null) ? null : ret2.getColBytes(1));
419: fm.close();
420: }
421: } else if (args.length == 4) {
422: if (args[0].equals("-c")) {
423: // create <keylen> <valuelen> <filename>
424: File f = new File(args[3]);
425: if (f.exists())
426: f.delete();
427: kelondroStack fm = new kelondroStack(f, lens);
428: fm.close();
429: } else if (args[0].equals("-p")) {
430: kelondroStack fm = new kelondroStack(new File(
431: args[3]), lens);
432: fm.push(fm.row().newEntry(
433: new byte[][] { args[1].getBytes(),
434: args[2].getBytes() }));
435: fm.close();
436: }
437: }
438: if (ret == null)
439: System.out.println("NULL");
440: else
441: System.out.println(new String(ret));
442: } catch (Exception e) {
443: e.printStackTrace();
444: }
445: }
446:
447: public static void main(String[] args) {
448: // -c 10 20 test.stack
449: // -p a a1 test.stack
450: // -p b b1 test.stack
451: // -p c c1 test.stack
452: // -v test.stack
453: // -g test.stack
454: // -v test.stack
455: // -g 1 test.stack
456: cmd(args);
457: /*
458: kelondroStack s = new kelondroStack(new File("/Users/admin/dev/yacy/trunk/test.stack"), 1024, new int[]{10,10}, false);
459: try {
460: s.push(s.row().newEntry(new byte[][]{"test123".getBytes(), "abcdefg".getBytes()}));
461: s.close();
462: } catch (IOException e) {
463: // TODO Auto-generated catch block
464: e.printStackTrace();
465: }
466: */
467: }
468:
469: }
|