001: //wikiBoard.java
002: //-------------------------------------
003: //(C) by Michael Peter Christen; mc@anomic.de
004: //first published on http://www.anomic.de
005: //Frankfurt, Germany, 2004
006: //last major change: 20.07.2004
007:
008: //This program is free software; you can redistribute it and/or modify
009: //it under the terms of the GNU General Public License as published by
010: //the Free Software Foundation; either version 2 of the License, or
011: //(at your option) any later version.
012:
013: //This program is distributed in the hope that it will be useful,
014: //but WITHOUT ANY WARRANTY; without even the implied warranty of
015: //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: //GNU General Public License for more details.
017:
018: //You should have received a copy of the GNU General Public License
019: //along with this program; if not, write to the Free Software
020: //Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
021:
022: //Using this software in any meaning (reading, learning, copying, compiling,
023: //running) means that you agree that the Author(s) is (are) not responsible
024: //for cost, loss of data or any harm that may be caused directly or indirectly
025: //by usage of this softare or this documentation. The usage of this software
026: //is on your own risk. The installation and usage (starting/running) of this
027: //software may allow other people or application to access your computer and
028: //any attached devices and is highly dependent on the configuration of the
029: //software which must be done by the user of the software; the author(s) is
030: //(are) also not responsible for proper configuration and usage of the
031: //software, even if provoked by documentation provided together with
032: //the software.
033:
034: //Any changes to this file according to the GPL as documented in the file
035: //gpl.txt aside this file in the shipment you received can be done to the
036: //lines that follows this copyright notice here, but changes must not be
037: //done inside the copyright notive above. A re-distribution must contain
038: //the intact and unchanged copyright notice.
039: //Contributions and changes to the program code must be marked as such.
040:
041: package de.anomic.data;
042:
043: import java.io.File;
044: import java.io.IOException;
045: import java.text.ParseException;
046: import java.text.SimpleDateFormat;
047: import java.util.Date;
048: import java.util.HashMap;
049: import java.util.Iterator;
050: import java.util.TimeZone;
051:
052: import de.anomic.kelondro.kelondroBase64Order;
053: import de.anomic.kelondro.kelondroDyn;
054: import de.anomic.kelondro.kelondroMapObjects;
055: import de.anomic.kelondro.kelondroNaturalOrder;
056:
057: public class wikiBoard {
058:
059: public static final int keyLength = 64;
060: private static final String dateFormat = "yyyyMMddHHmmss";
061: private static final int recordSize = 512;
062:
063: private static SimpleDateFormat SimpleFormatter = new SimpleDateFormat(
064: dateFormat);
065:
066: static {
067: SimpleFormatter.setTimeZone(TimeZone.getTimeZone("GMT"));
068: }
069:
070: private kelondroMapObjects datbase = null;
071: private kelondroMapObjects bkpbase = null;
072: private static HashMap<String, String> authors = new HashMap<String, String>();
073:
074: public wikiBoard(File actpath, File bkppath, long preloadTime) {
075: new File(actpath.getParent()).mkdirs();
076: if (datbase == null) {
077: datbase = new kelondroMapObjects(new kelondroDyn(actpath,
078: true, true, preloadTime, keyLength, recordSize,
079: '_', kelondroNaturalOrder.naturalOrder, true,
080: false, false), 500);
081: }
082: new File(bkppath.getParent()).mkdirs();
083: if (bkpbase == null) {
084: bkpbase = new kelondroMapObjects(new kelondroDyn(bkppath,
085: true, true, preloadTime, keyLength
086: + dateFormat.length(), recordSize, '_',
087: kelondroNaturalOrder.naturalOrder, true, false,
088: false), 500);
089: }
090: }
091:
092: public int sizeOfTwo() {
093: return datbase.size() + bkpbase.size();
094: }
095:
096: public int size() {
097: return datbase.size();
098: }
099:
100: public void close() {
101: datbase.close();
102: bkpbase.close();
103: }
104:
105: private static String dateString() {
106: return dateString(new Date());
107: }
108:
109: public static String dateString(Date date) {
110: synchronized (SimpleFormatter) {
111: return SimpleFormatter.format(date);
112: }
113: }
114:
115: private static String normalize(String key) {
116: if (key == null)
117: return "null";
118: return key.trim().toLowerCase();
119: }
120:
121: public static String webalize(String key) {
122: if (key == null)
123: return "null";
124: key = key.trim().toLowerCase();
125: int p;
126: while ((p = key.indexOf(" ")) >= 0)
127: key = key.substring(0, p) + "%20" + key.substring(p + 1);
128: return key;
129: }
130:
131: public static String guessAuthor(String ip) {
132: String author = authors.get(ip);
133: //yacyCore.log.logDebug("DEBUG: guessing author for ip = " + ip + " is '" + author + "', authors = " + authors.toString());
134: return author;
135: }
136:
137: public static void setAuthor(String ip, String author) {
138: authors.put(ip, author);
139: }
140:
141: public entry newEntry(String subject, String author, String ip,
142: String reason, byte[] page) throws IOException {
143: return new entry(normalize(subject), author, ip, reason, page);
144: }
145:
146: public class entry {
147:
148: String key;
149: HashMap<String, String> record;
150:
151: public entry(String subject, String author, String ip,
152: String reason, byte[] page) throws IOException {
153: record = new HashMap<String, String>();
154: key = subject;
155: if (key.length() > keyLength)
156: key = key.substring(0, keyLength);
157: record.put("date", dateString());
158: if ((author == null) || (author.length() == 0))
159: author = "anonymous";
160: record.put("author", kelondroBase64Order.enhancedCoder
161: .encode(author.getBytes("UTF-8")));
162: if ((ip == null) || (ip.length() == 0))
163: ip = "";
164: record.put("ip", ip);
165: if ((reason == null) || (reason.length() == 0))
166: reason = "";
167: record.put("reason", kelondroBase64Order.enhancedCoder
168: .encode(reason.getBytes("UTF-8")));
169: if (page == null)
170: record.put("page", "");
171: else
172: record.put("page", kelondroBase64Order.enhancedCoder
173: .encode(page));
174: authors.put(ip, author);
175: //System.out.println("DEBUG: setting author " + author + " for ip = " + ip + ", authors = " + authors.toString());
176: }
177:
178: private entry(String key, HashMap<String, String> record) {
179: this .key = key;
180: this .record = record;
181: }
182:
183: public String subject() {
184: return key;
185: }
186:
187: public Date date() {
188: try {
189: String c = record.get("date");
190: if (c == null) {
191: System.out
192: .println("DEBUG - ERROR: date field missing in wikiBoard");
193: return new Date();
194: }
195: synchronized (SimpleFormatter) {
196: return SimpleFormatter.parse(c);
197: }
198: } catch (ParseException e) {
199: return new Date();
200: }
201: }
202:
203: public String author() {
204: String a = record.get("author");
205: if (a == null)
206: return "anonymous";
207: byte[] b = kelondroBase64Order.enhancedCoder.decode(a,
208: "de.anomic.data.wikiBoard.author()");
209: if (b == null)
210: return "anonymous";
211: return new String(b);
212: }
213:
214: public String reason() {
215: String r = record.get("reason");
216: if (r == null)
217: return "";
218: byte[] b = kelondroBase64Order.enhancedCoder.decode(r,
219: "de.anomic.data.wikiBoard.reason()");
220: if (b == null)
221: return "unknown";
222: return new String(b);
223: }
224:
225: public byte[] page() {
226: String m = record.get("page");
227: if (m == null)
228: return new byte[0];
229: byte[] b = kelondroBase64Order.enhancedCoder.decode(m,
230: "de.anomic.data.wikiBoard.page()");
231: if (b == null)
232: return "".getBytes();
233: return b;
234: }
235:
236: private void setAncestorDate(Date date) {
237: record.put("bkp", dateString(date));
238: }
239:
240: private Date getAncestorDate() {
241: try {
242: String c = record.get("date");
243: if (c == null)
244: return null;
245: synchronized (SimpleFormatter) {
246: return SimpleFormatter.parse(c);
247: }
248: } catch (ParseException e) {
249: return null;
250: }
251: }
252:
253: /*
254: public boolean hasAncestor() {
255: Date ancDate = getAncestorDate();
256: if (ancDate == null) return false;
257: try {
258: return bkpbase.has(key + dateString(ancDate));
259: } catch (IOException e) {
260: return false;
261: }
262: }
263: */
264:
265: public entry getAncestor() {
266: Date ancDate = getAncestorDate();
267: if (ancDate == null)
268: return null;
269: return read(key + dateString(ancDate), bkpbase);
270: }
271:
272: private void setChild(String subject) {
273: record.put("child", kelondroBase64Order.enhancedCoder
274: .encode(subject.getBytes()));
275: }
276:
277: private String getChildName() {
278: String c = record.get("child");
279: if (c == null)
280: return null;
281: byte[] subject = kelondroBase64Order.enhancedCoder.decode(
282: c, "de.anomic.data.wikiBoard.getChildName()");
283: if (subject == null)
284: return null;
285: return new String(subject);
286: }
287:
288: public boolean hasChild() {
289: String c = record.get("child");
290: if (c == null)
291: return false;
292: byte[] subject = kelondroBase64Order.enhancedCoder.decode(
293: c, "de.anomic.data.wikiBoard.hasChild()");
294: return (subject != null);
295: }
296:
297: public entry getChild() {
298: String childName = getChildName();
299: if (childName == null)
300: return null;
301: return read(childName, datbase);
302: }
303: }
304:
305: public String write(entry page) {
306: // writes a new page and returns key
307: try {
308: // first load the old page
309: entry oldEntry = read(page.key);
310: // set the bkp date of the new page to the date of the old page
311: Date oldDate = oldEntry.date();
312: page.setAncestorDate(oldDate);
313: oldEntry.setChild(page.subject());
314: // write the backup
315: //System.out.println("key = " + page.key);
316: //System.out.println("oldDate = " + oldDate);
317: //System.out.println("record = " + oldEntry.record.toString());
318: bkpbase
319: .set(page.key + dateString(oldDate),
320: oldEntry.record);
321: // write the new page
322: datbase.set(page.key, page.record);
323: return page.key;
324: } catch (IOException e) {
325: return null;
326: }
327: }
328:
329: public entry read(String key) {
330: return read(key, datbase);
331: }
332:
333: private entry read(String key, kelondroMapObjects base) {
334: try {
335: key = normalize(key);
336: if (key.length() > keyLength)
337: key = key.substring(0, keyLength);
338: HashMap<String, String> record = base.getMap(key);
339: if (record == null)
340: return newEntry(key, "anonymous", "127.0.0.1",
341: "New Page", "".getBytes());
342: return new entry(key, record);
343: } catch (IOException e) {
344: return null;
345: }
346: }
347:
348: public entry readBkp(String key) {
349: return read(key, bkpbase);
350: }
351:
352: /*
353: public boolean has(String key) {
354: try {
355: return datbase.has(normalize(key));
356: } catch (IOException e) {
357: return false;
358: }
359: }
360: */
361:
362: public Iterator<String> keys(boolean up) throws IOException {
363: return datbase.keys(up, false);
364: }
365:
366: public Iterator<String> keysBkp(boolean up) throws IOException {
367: return bkpbase.keys(up, false);
368: }
369: }
|