001: /*
002: Very Quick Wiki - WikiWikiWeb clone
003: Copyright (C) 2001-2002 Gareth Cronin
004:
005: This program is free software; you can redistribute it and/or modify
006: it under the terms of the latest version of the GNU Lesser General
007: Public License as published by the Free Software Foundation;
008:
009: This program is distributed in the hope that it will be useful,
010: but WITHOUT ANY WARRANTY; without even the implied warranty of
011: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: GNU Lesser General Public License for more details.
013:
014: You should have received a copy of the GNU Lesser General Public License
015: along with this program (gpl.txt); if not, write to the Free Software
016: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: */
018: package vqwiki;
019:
020: import org.apache.log4j.Logger;
021: import vqwiki.db.DBDate;
022: import vqwiki.db.DatabaseChangeLog;
023: import vqwiki.db.DatabaseHandler;
024: import vqwiki.db.DatabaseNotify;
025: import vqwiki.db.DatabaseSearchEngine;
026: import vqwiki.db.DatabaseVersionManager;
027: import vqwiki.db.DatabaseWikiMembers;
028: import vqwiki.file.FileChangeLog;
029: import vqwiki.file.FileExtensionFilter;
030: import vqwiki.file.FileHandler;
031: import vqwiki.file.FileNotify;
032: import vqwiki.file.FileSearchEngine;
033: import vqwiki.file.FileVersionManager;
034: import vqwiki.file.FileWikiMembers;
035: import vqwiki.lex.AbstractParser;
036: import vqwiki.lex.BackLinkLex;
037: import vqwiki.lex.LexExtender;
038: import vqwiki.lex.Lexer;
039: import vqwiki.lex.MakeTableOfContents;
040: import vqwiki.users.LdapUsergroup;
041: import vqwiki.users.NoUsergroup;
042: import vqwiki.users.Usergroup;
043:
044: import java.io.BufferedInputStream;
045: import java.io.BufferedOutputStream;
046: import java.io.BufferedReader;
047: import java.io.ByteArrayOutputStream;
048: import java.io.File;
049: import java.io.IOException;
050: import java.io.InputStream;
051: import java.io.Reader;
052: import java.io.StringReader;
053: import java.lang.reflect.Constructor;
054: import java.lang.reflect.InvocationTargetException;
055: import java.util.ArrayList;
056: import java.util.Calendar;
057: import java.util.Collection;
058: import java.util.Date;
059: import java.util.HashSet;
060: import java.util.Iterator;
061: import java.util.List;
062: import java.util.Locale;
063: import java.util.ResourceBundle;
064: import java.util.Set;
065: import java.util.StringTokenizer;
066: import java.util.TreeSet;
067:
068: /**
069: * Base class for Wiki. Handles all basic Viki stuff.
070: *
071: * @author $author$
072: * @version $Revision: 685 $
073: */
074: public class WikiBase {
075:
076: /** An instance to myself. Singleton pattern. */
077: private static WikiBase instance;
078: /** The topics are stored in a flat file */
079: public static final int FILE = 0;
080: /** The topics are stored in a database */
081: public static final int DATABASE = 1;
082: /** Members are retrieved from LDAP */
083: public static final int LDAP = 2;
084: /** Name of the default wiki */
085: public static final String DEFAULT_VWIKI = "jsp";
086: /** Name of the Plugins-Directory */
087: public static final String PLUGINS_DIR = "plugins";
088: /** Log output */
089: private static final Logger logger = Logger
090: .getLogger(WikiBase.class);
091: /** The handler that looks after read/write operations for a persitence type */
092: protected Handler handler;
093: /** Listeners for topic changes */
094: private List topicListeners;
095: /** Number of virtual wikis */
096: private int virtualWikiCount;
097:
098: /**
099: * Creates a new WikiBase object.
100: *
101: * @param persistenceType Which type of persistence is used
102: * @throws Exception If the handler cannot be instanciated.
103: */
104: private WikiBase(int persistenceType) throws Exception {
105: switch (persistenceType) {
106: case FILE:
107: this .handler = new FileHandler();
108: break;
109: case DATABASE:
110: this .handler = new DatabaseHandler();
111: break;
112: }
113: new SearchRefreshThread(Environment.getInstance()
114: .getIndexRefreshInterval());
115: PluginManager.getInstance().installAll();
116: this .topicListeners = new ArrayList();
117: this .topicListeners.addAll(PluginManager.getInstance()
118: .getTopicListeners());
119: }
120:
121: /**
122: * Get a reference of this class. Implements singleton pattern.
123: *
124: * @return Instance of this class
125: * @throws Exception If the storage produces errors
126: */
127: public static WikiBase getInstance() throws Exception {
128: int persistenceType = Environment.getInstance()
129: .getPersistenceType();
130: if (instance == null) {
131: instance = new WikiBase(persistenceType);
132: }
133: return instance;
134: }
135:
136: /**
137: * Get an instance to the search enginge.
138: *
139: * @return Reference to the SearchEngine
140: * @throws Exception the current search engine
141: */
142: public SearchEngine getSearchEngineInstance() throws Exception {
143: switch (Environment.getInstance().getPersistenceType()) {
144: case FILE:
145: return FileSearchEngine.getInstance();
146: case DATABASE:
147: return DatabaseSearchEngine.getInstance();
148: default:
149: return FileSearchEngine.getInstance();
150: }
151: }
152:
153: /**
154: * Get an instance of the user group
155: *
156: * @return Reference to the SearchEngine
157: * @throws Exception the current search engine
158: */
159: public Usergroup getUsergroupInstance() throws Exception {
160: switch (Environment.getInstance().getUsergroupType()) {
161: case LDAP:
162: return LdapUsergroup.getInstance();
163: //TODO case DATABASE:
164: // return DatabaseUsergroup.getInstance();
165: default:
166: return NoUsergroup.getInstance();
167: }
168: }
169:
170: /**
171: * TODO: DOCUMENT ME!
172: *
173: * @return TODO: DOCUMENT ME!
174: * @throws Exception TODO: DOCUMENT ME!
175: */
176: public VersionManager getVersionManagerInstance() throws Exception {
177: switch (Environment.getInstance().getPersistenceType()) {
178: case FILE:
179: return FileVersionManager.getInstance();
180: case DATABASE:
181: return DatabaseVersionManager.getInstance();
182: default:
183: return FileVersionManager.getInstance();
184: }
185: }
186:
187: /**
188: * TODO: DOCUMENT ME!
189: *
190: * @return TODO: DOCUMENT ME!
191: * @throws Exception TODO: DOCUMENT ME!
192: */
193: public ChangeLog getChangeLogInstance() throws Exception {
194: switch (Environment.getInstance().getPersistenceType()) {
195: case FILE:
196: return FileChangeLog.getInstance();
197: case DATABASE:
198: return DatabaseChangeLog.getInstance();
199: default:
200: return FileChangeLog.getInstance();
201: }
202: }
203:
204: /**
205: * TODO: DOCUMENT ME!
206: *
207: * @param virtualWiki TODO: DOCUMENT ME!
208: * @param topic TODO: DOCUMENT ME!
209: * @return TODO: DOCUMENT ME!
210: * @throws Exception TODO: DOCUMENT ME!
211: */
212: public Notify getNotifyInstance(String virtualWiki, String topic)
213: throws Exception {
214: switch (Environment.getInstance().getPersistenceType()) {
215: case FILE:
216: return new FileNotify(virtualWiki, topic);
217: case DATABASE:
218: return new DatabaseNotify(virtualWiki, topic);
219: default:
220: return new FileNotify();
221: }
222: }
223:
224: /**
225: * TODO: DOCUMENT ME!
226: *
227: * @param virtualWiki TODO: DOCUMENT ME!
228: * @return TODO: DOCUMENT ME!
229: * @throws Exception TODO: DOCUMENT ME!
230: */
231: public WikiMembers getWikiMembersInstance(String virtualWiki)
232: throws Exception {
233: switch (Environment.getInstance().getPersistenceType()) {
234: case FILE:
235: return new FileWikiMembers(virtualWiki);
236: case DATABASE:
237: return new DatabaseWikiMembers(virtualWiki);
238: default:
239: return new FileWikiMembers(virtualWiki);
240: }
241: }
242:
243: /**
244: * Register a topic listener
245: *
246: * @param listener listener
247: */
248: public void addTopicListener(TopicListener listener) {
249: if (!this .topicListeners.contains(listener)) {
250: this .topicListeners.add(listener);
251: }
252: }
253:
254: /**
255: * Finds a default topic file and returns the contents
256: */
257: public static String readDefaultTopic(String topicName)
258: throws Exception {
259: String resourceName = "/" + topicName + ".txt";
260: java.net.URL resource = WikiBase.class
261: .getResource(resourceName);
262: if (resource == null) {
263: throw new IllegalArgumentException(
264: "unknown default topic: " + topicName);
265: }
266: File f = new File(WikiBase.class.getResource(resourceName)
267: .getFile());
268: logger.debug("Found the default topic: " + f);
269: // Previous implementation using Readers (UTF-8) was adding a \n to the end
270: // of the file resulting in an unwanted <br> in pages, and causing problems
271: // when rendering them in a layout of composed wiki pages
272: // (top-area, bottom-area, etc).
273: InputStream in = WikiBase.class
274: .getResourceAsStream(resourceName);
275: BufferedInputStream is = new BufferedInputStream(in);
276: ByteArrayOutputStream baos = new ByteArrayOutputStream();
277: BufferedOutputStream os = new BufferedOutputStream(baos);
278: String output = null;
279: try {
280: int c;
281: while ((c = is.read()) != -1) {
282: os.write(c); // also... it uses the buffers
283: }
284: os.flush();
285: output = baos.toString();
286: } catch (IOException e) {
287: e.printStackTrace();
288: } finally {
289: // Closes the streams, if necessary
290: if (is != null) {
291: try {
292: is.close();
293: } catch (Exception ignore) {
294: logger
295: .warn(
296: "exception closing file (you can ignore this warning)",
297: ignore);
298: }
299: }
300: if (os != null) {
301: try {
302: os.close();
303: } catch (Exception ignore) {
304: logger
305: .warn(
306: "exception closing output stream (you can ignore this warning)",
307: ignore);
308: }
309: }
310: in.close();
311: }
312: return output;
313: }
314:
315: /**
316: * Reads a file and returns the raw contents. Used for the editing version.
317: */
318: public synchronized String readRaw(String virtualWiki,
319: String topicName) throws Exception {
320: return handler.read(virtualWiki, topicName);
321: }
322:
323: /**
324: * TODO: DOCUMENT ME!
325: *
326: * @param virtualWiki TODO: DOCUMENT ME!
327: * @param topicName TODO: DOCUMENT ME!
328: * @return TODO: DOCUMENT ME!
329: * @throws Exception TODO: DOCUMENT ME!
330: */
331: public synchronized boolean exists(String virtualWiki,
332: String topicName) throws Exception {
333: if (PseudoTopicHandler.getInstance().isPseudoTopic(topicName)) {
334: return true;
335: }
336: return handler.exists(virtualWiki, topicName);
337: }
338:
339: /**
340: * Returns a topic's content that has been formatted to Wiki conventions.
341: *
342: * @param virtualWiki the virtual wiki to use
343: * @param topicName the topic
344: */
345: public synchronized String readCooked(String virtualWiki,
346: String topicName) throws Exception {
347: String s = handler.read(virtualWiki, topicName);
348: BufferedReader in = new BufferedReader(new StringReader(s));
349: return cook(in, virtualWiki);
350: }
351:
352: /**
353: * TODO: DOCUMENT ME!
354: *
355: * @param virtualWiki TODO: DOCUMENT ME!
356: * @param topicName TODO: DOCUMENT ME!
357: * @param formatLexClass TODO: DOCUMENT ME!
358: * @param layoutLexClass TODO: DOCUMENT ME!
359: * @param linkLexClass TODO: DOCUMENT ME!
360: * @return TODO: DOCUMENT ME!
361: * @throws Exception TODO: DOCUMENT ME!
362: */
363: public synchronized String readCooked(String virtualWiki,
364: String topicName, String formatLexClass,
365: String layoutLexClass, String linkLexClass, boolean export)
366: throws Exception {
367: String s = handler.read(virtualWiki, topicName);
368: BufferedReader in = new BufferedReader(new StringReader(s));
369: return cook(in, virtualWiki, formatLexClass, layoutLexClass,
370: linkLexClass, export);
371: }
372:
373: /**
374: * TODO: DOCUMENT ME!
375: *
376: * @param in TODO: DOCUMENT ME!
377: * @param virtualWiki TODO: DOCUMENT ME!
378: * @return TODO: DOCUMENT ME!
379: * @throws ClassNotFoundException TODO: DOCUMENT ME!
380: * @throws NoSuchMethodException TODO: DOCUMENT ME!
381: * @throws InstantiationException TODO: DOCUMENT ME!
382: * @throws IllegalAccessException TODO: DOCUMENT ME!
383: * @throws InvocationTargetException TODO: DOCUMENT ME!
384: * @throws IOException TODO: DOCUMENT ME!
385: */
386: public synchronized String cook(BufferedReader in,
387: String virtualWiki) throws ClassNotFoundException,
388: NoSuchMethodException, InstantiationException,
389: IllegalAccessException, InvocationTargetException,
390: IOException {
391: Environment en = Environment.getInstance();
392: return cook(in, virtualWiki, en
393: .getStringSetting(Environment.PROPERTY_FORMAT_LEXER),
394: en.getStringSetting(Environment.PROPERTY_LAYOUT_LEXER),
395: en.getStringSetting(Environment.PROPERTY_LINK_LEXER),
396: false);
397: }
398:
399: /**
400: * TODO: DOCUMENT ME!
401: *
402: * @param in TODO: DOCUMENT ME!
403: * @param virtualWiki TODO: DOCUMENT ME!
404: * @param formatLexClass TODO: DOCUMENT ME!
405: * @param layoutLexClass TODO: DOCUMENT ME!
406: * @param linkLexClass TODO: DOCUMENT ME!
407: * @return TODO: DOCUMENT ME!
408: * @throws ClassNotFoundException TODO: DOCUMENT ME!
409: * @throws NoSuchMethodException TODO: DOCUMENT ME!
410: * @throws InstantiationException TODO: DOCUMENT ME!
411: * @throws IllegalAccessException TODO: DOCUMENT ME!
412: * @throws InvocationTargetException TODO: DOCUMENT ME!
413: * @throws IOException TODO: DOCUMENT ME!
414: */
415: public synchronized String cook(BufferedReader in,
416: String virtualWiki, String formatLexClass,
417: String layoutLexClass, String linkLexClass, boolean export)
418: throws ClassNotFoundException, NoSuchMethodException,
419: InstantiationException, IllegalAccessException,
420: InvocationTargetException, IOException {
421: Environment en = Environment.getInstance();
422: // FIXME (PARSER_TEMP) - remove this condition after parser conversion is complete
423: if (en.getBooleanSetting(Environment.PROPERTY_USE_NEW_PARSER)) {
424: String parserClass = en
425: .getStringSetting(Environment.PROPERTY_PARSER);
426: logger.debug("Using parser: " + parserClass);
427: Class clazz = Class.forName(parserClass);
428: Constructor constructor = clazz.getConstructor(null);
429: AbstractParser parser = (AbstractParser) constructor
430: .newInstance(null);
431: String line;
432: StringBuffer raw = new StringBuffer();
433: while ((line = in.readLine()) != null) {
434: raw.append(line).append("\n");
435: }
436: return ((export) ? parser.parseExportHTML(raw.toString(),
437: virtualWiki) : parser.parseHTML(raw.toString(),
438: virtualWiki));
439: }
440: // FIXME (PARSER_TEMP) - remove all code below after parser conversion is complete
441: StringBuffer contents = new StringBuffer();
442: Lexer lexer;
443: String formatted;
444: logger.debug("Using format lexer: " + formatLexClass);
445: Class clazz = Class.forName(formatLexClass);
446: Constructor constructor = clazz
447: .getConstructor(new Class[] { Reader.class });
448: lexer = (Lexer) constructor.newInstance(new Object[] { in });
449: lexer.setVirtualWiki(virtualWiki);
450: boolean external = false;
451: String tag = null;
452: StringBuffer externalContents = null;
453: while (true) {
454: String line = null;
455: try {
456: line = lexer.yylex();
457: } catch (ArrayIndexOutOfBoundsException e) {
458: logger.debug(e);
459: }
460: logger.debug(line);
461: if (line == null) {
462: break;
463: }
464: if (line.startsWith("[<")) {
465: if (!external) {
466: external = true;
467: tag = line.substring(2, line.length() - 2);
468: logger.debug("External lex call (tag=" + tag + ")");
469: externalContents = new StringBuffer();
470: contents.append(line);
471: } else {
472: external = false;
473: String converted = LexExtender.getInstance()
474: .lexify(tag, externalContents.toString());
475: if (converted != null) {
476: contents.append(converted);
477: }
478: contents.append(line);
479: logger.debug("External ends");
480: }
481: } else {
482: if (!external) {
483: contents.append(line);
484: } else {
485: externalContents.append(line);
486: }
487: }
488: }
489: if (en.isMakeToc()) {
490: formatted = MakeTableOfContents.addTableOfContents(contents
491: .toString());
492: } else {
493: formatted = contents.toString();
494: }
495: String laidOut = formatted;
496: if (!(layoutLexClass.equals("null") || layoutLexClass
497: .equals(""))) {
498: logger.debug("Using layout lexer: " + layoutLexClass);
499: contents = new StringBuffer();
500: clazz = Class.forName(layoutLexClass);
501: constructor = clazz
502: .getConstructor(new Class[] { Reader.class });
503: lexer = (Lexer) constructor
504: .newInstance(new Object[] { new StringReader(
505: formatted) });
506: lexer.setVirtualWiki(virtualWiki);
507: while (true) {
508: String line = lexer.yylex();
509: if (line == null) {
510: break;
511: }
512: contents.append(line);
513: }
514: laidOut = contents.toString();
515: }
516: String linked = laidOut;
517: if (!(linkLexClass.equals("null") || linkLexClass.equals(""))) {
518: logger.debug("Using link lexer: " + linkLexClass);
519: contents = new StringBuffer();
520: clazz = Class.forName(linkLexClass);
521: constructor = clazz
522: .getConstructor(new Class[] { Reader.class });
523: lexer = (Lexer) constructor
524: .newInstance(new Object[] { new StringReader(
525: laidOut) });
526: lexer.setVirtualWiki(virtualWiki);
527: while (true) {
528: String line = lexer.yylex();
529: if (line == null) {
530: break;
531: }
532: contents.append(line);
533: }
534: linked = contents.toString();
535: }
536: // remove trailing returns at the end of the site.
537: // TODO better do this with StringBuffer, but actually no more
538: // time for a proper cleanup.
539: if (linked.endsWith("<br/>\n")) {
540: linked = linked.substring(0, linked.length() - 6);
541: while (linked.endsWith("<br/>")) {
542: linked = linked.substring(0, linked.length() - 5);
543: }
544: }
545: return linked;
546: }
547:
548: /**
549: * TODO: DOCUMENT ME!
550: *
551: * @param virtualWiki TODO: DOCUMENT ME!
552: * @param topicName TODO: DOCUMENT ME!
553: * @param contents TODO: DOCUMENT ME!
554: */
555: private void fireTopicSaved(String virtualWiki, String topicName,
556: String contents, String user, Date time) {
557: logger.debug("topic saved event: " + topicListeners);
558: if (topicListeners == null) {
559: return;
560: }
561: for (Iterator iterator = topicListeners.iterator(); iterator
562: .hasNext();) {
563: TopicListener listener = (TopicListener) iterator.next();
564: listener.topicSaved(new TopicSavedEvent(virtualWiki,
565: topicName, contents, user, time));
566: }
567: }
568:
569: /**
570: * TODO: DOCUMENT ME!
571: *
572: * @param virtualWiki TODO: DOCUMENT ME!
573: * @param contents TODO: DOCUMENT ME!
574: * @param convertTabs TODO: DOCUMENT ME!
575: * @param topicName TODO: DOCUMENT ME!
576: * @throws Exception TODO: DOCUMENT ME!
577: */
578: public synchronized void write(String virtualWiki, String contents,
579: boolean convertTabs, String topicName, String user)
580: throws Exception {
581: // If the last line is not a return value, the parser can be tricked out.
582: // (got this from wikipedia)
583: if (!contents.endsWith("\n")) {
584: contents += "\n";
585: }
586: fireTopicSaved(virtualWiki, topicName, contents, user,
587: new Date());
588: handler.write(virtualWiki, contents, convertTabs, topicName);
589: }
590:
591: /**
592: * TODO: DOCUMENT ME!
593: *
594: * @param virtualWiki TODO: DOCUMENT ME!
595: * @param topicName TODO: DOCUMENT ME!
596: * @param key TODO: DOCUMENT ME!
597: * @return TODO: DOCUMENT ME!
598: * @throws Exception TODO: DOCUMENT ME!
599: */
600: public synchronized boolean holdsLock(String virtualWiki,
601: String topicName, String key) throws Exception {
602: return handler.holdsLock(virtualWiki, topicName, key);
603: }
604:
605: /**
606: * TODO: DOCUMENT ME!
607: *
608: * @param virtualWiki TODO: DOCUMENT ME!
609: * @param topicName TODO: DOCUMENT ME!
610: * @param key TODO: DOCUMENT ME!
611: * @return TODO: DOCUMENT ME!
612: * @throws Exception TODO: DOCUMENT ME!
613: */
614: public synchronized boolean lockTopic(String virtualWiki,
615: String topicName, String key) throws Exception {
616: return handler.lockTopic(virtualWiki, topicName, key);
617: }
618:
619: /**
620: * TODO: DOCUMENT ME!
621: *
622: * @param virtualWiki TODO: DOCUMENT ME!
623: * @param topicName TODO: DOCUMENT ME!
624: * @throws Exception TODO: DOCUMENT ME!
625: */
626: public synchronized void unlockTopic(String virtualWiki,
627: String topicName) throws Exception {
628: handler.unlockTopic(virtualWiki, topicName);
629: }
630:
631: /**
632: * Get recent changes for a given number of days
633: *
634: * @deprecated This method seems to be unused and will be removed.
635: */
636: public Collection listRecentChanges(String virtualWiki, int numDays)
637: throws Exception {
638: TreeSet changes = new TreeSet();
639: try {
640: ChangeLog changeLog = this .getChangeLogInstance();
641: Calendar cal = Calendar.getInstance();
642: for (int i = 0; i <= numDays; i++) {
643: Date aDate = cal.getTime();
644: Collection col = changeLog.getChanges(virtualWiki,
645: aDate);
646: if (col != null) {
647: changes.addAll(col);
648: }
649: }
650: cal.add(Calendar.DATE, -1);
651: } catch (IOException e1) {
652: logger.error(e1);
653: } catch (ClassNotFoundException e1) {
654: logger.error(e1);
655: }
656: return changes;
657: }
658:
659: /**
660: * TODO: DOCUMENT ME!
661: *
662: * @param virtualWiki TODO: DOCUMENT ME!
663: * @param topicName TODO: DOCUMENT ME!
664: * @return TODO: DOCUMENT ME!
665: * @throws Exception TODO: DOCUMENT ME!
666: */
667: protected boolean isTopicReadOnly(String virtualWiki,
668: String topicName) throws Exception {
669: return this .handler.isTopicReadOnly(virtualWiki, topicName);
670: }
671:
672: /**
673: * TODO: DOCUMENT ME!
674: *
675: * @param virtualWiki TODO: DOCUMENT ME!
676: * @return TODO: DOCUMENT ME!
677: * @throws Exception TODO: DOCUMENT ME!
678: */
679: public Collection getReadOnlyTopics(String virtualWiki)
680: throws Exception {
681: return this .handler.getReadOnlyTopics(virtualWiki);
682: }
683:
684: /**
685: * TODO: DOCUMENT ME!
686: *
687: * @param virtualWiki TODO: DOCUMENT ME!
688: * @param topicName TODO: DOCUMENT ME!
689: * @throws Exception TODO: DOCUMENT ME!
690: */
691: public void addReadOnlyTopic(String virtualWiki, String topicName)
692: throws Exception {
693: this .handler.addReadOnlyTopic(virtualWiki, topicName);
694: }
695:
696: /**
697: * TODO: DOCUMENT ME!
698: *
699: * @param virtualWiki TODO: DOCUMENT ME!
700: * @param topicName TODO: DOCUMENT ME!
701: * @throws Exception TODO: DOCUMENT ME!
702: */
703: public void removeReadOnlyTopic(String virtualWiki, String topicName)
704: throws Exception {
705: this .handler.removeReadOnlyTopic(virtualWiki, topicName);
706: }
707:
708: /**
709: * TODO: DOCUMENT ME!
710: *
711: * @return TODO: DOCUMENT ME!
712: */
713: protected String fileBase() {
714: return Environment.getInstance().getHomeDir();
715: }
716:
717: /**
718: * TODO: DOCUMENT ME!
719: *
720: * @throws Exception TODO: DOCUMENT ME!
721: */
722: public static void initialise() throws Exception {
723: int persistenceType = Environment.getInstance()
724: .getPersistenceType();
725: WikiMail.init();
726: instance = new WikiBase(persistenceType);
727: }
728:
729: /**
730: * Find all topics without links to them
731: */
732: public Collection getOrphanedTopics(String virtualWiki)
733: throws Exception {
734: Collection results = new HashSet();
735: Collection all = getSearchEngineInstance().getAllTopicNames(
736: virtualWiki);
737: for (Iterator iterator = all.iterator(); iterator.hasNext();) {
738: String topicName = (String) iterator.next();
739: Collection matches = getSearchEngineInstance()
740: .findLinkedTo(virtualWiki, topicName);
741: logger
742: .debug(topicName + ": " + matches.size()
743: + " matches");
744: if (matches.size() == 0) {
745: results.add(topicName);
746: }
747: }
748: logger.debug(results.size() + " orphaned topics found");
749: return results;
750: }
751:
752: /**
753: * Find all topics that haven't been written but are linked to
754: */
755: public Collection getToDoWikiTopics(String virtualWiki)
756: throws Exception {
757: Collection results = new TreeSet();
758: Collection all = getSearchEngineInstance().getAllTopicNames(
759: virtualWiki);
760: Set topicNames = new HashSet();
761: for (Iterator iterator = all.iterator(); iterator.hasNext();) {
762: String topicName = (String) iterator.next();
763: String content = handler.read(virtualWiki, topicName);
764: StringReader reader = new StringReader(content);
765: BackLinkLex lexer = new BackLinkLex(reader);
766: while (lexer.yylex() != null) {
767: ;
768: }
769: reader.close();
770: topicNames.addAll(lexer.getLinks());
771: }
772: for (Iterator iterator = topicNames.iterator(); iterator
773: .hasNext();) {
774: String topicName = (String) iterator.next();
775: if (!PseudoTopicHandler.getInstance().isPseudoTopic(
776: topicName)
777: && !handler.exists(virtualWiki, topicName)
778: && !"\\\\\\\\link\\\\\\\\".equals(topicName)) {
779: results.add(topicName);
780: }
781: }
782: logger.debug(results.size() + " todo topics found");
783: return results;
784: }
785:
786: /**
787: * Return a list of all virtual wikis on the server
788: */
789: public Collection getVirtualWikiList() throws Exception {
790: return this .handler.getVirtualWikiList();
791: }
792:
793: /**
794: * Return a list of available templates
795: */
796: public Collection getTemplates(String virtualWiki) throws Exception {
797: return this .handler.getTemplateNames(virtualWiki);
798: }
799:
800: /**
801: * Return a given template
802: */
803: public String getTemplate(String virtualWiki, String name)
804: throws Exception {
805: return this .handler.getTemplate(virtualWiki, name);
806: }
807:
808: /**
809: * Purge deleted files
810: *
811: * @return a collection of strings that are the deleted topic names
812: */
813: public Collection purgeDeletes(String virtualWiki) throws Exception {
814: return this .handler.purgeDeletes(virtualWiki);
815: }
816:
817: /**
818: * Add virtual wiki
819: */
820: public void addVirtualWiki(String virtualWiki) throws Exception {
821: this .handler.addVirtualWiki(virtualWiki);
822: }
823:
824: /**
825: * purge versions older than a certain date
826: */
827: public void purgeVersionsOlderThan(String virtualWiki, DBDate date)
828: throws Exception {
829: this .handler.purgeVersionsOlderThan(virtualWiki, date);
830: }
831:
832: /**
833: * save the contents as a template
834: */
835: public void saveAsTemplate(String virtualWiki, String templateName,
836: String contents) throws Exception {
837: // If the last line is not a return value, the parser can be tricked out.
838: // (got this from wikipedia)
839: if (!contents.endsWith("\n")) {
840: contents += "\n";
841: }
842: this .handler
843: .saveAsTemplate(virtualWiki, templateName, contents);
844: }
845:
846: /**
847: * get a count of the number of virtual wikis in the system
848: *
849: * @return the number of virtual wikis
850: */
851: public int getVirtualWikiCount() {
852: if (virtualWikiCount == 0) {
853: try {
854: virtualWikiCount = getVirtualWikiList().size();
855: } catch (Exception e) {
856: logger.warn(e);
857: }
858: }
859: return virtualWikiCount;
860: }
861:
862: /**
863: * return the current handler instance
864: *
865: * @return the current handler instance
866: */
867: public Handler getHandler() {
868: return handler;
869: }
870:
871: /**
872: * Do emergency repairs by clearing all locks and deleting recent changes files
873: */
874: public void panic() {
875: Collection wikis = null;
876: try {
877: wikis = getVirtualWikiList();
878: } catch (Exception e) {
879: logger.error("problem getting the virtual wiki list", e);
880: return;
881: }
882: for (Iterator iterator = wikis.iterator(); iterator.hasNext();) {
883: String virtualWikiName = (String) iterator.next();
884: try {
885: List lockList = handler.getLockList(virtualWikiName);
886: for (Iterator lockIterator = lockList.iterator(); lockIterator
887: .hasNext();) {
888: TopicLock lock = (TopicLock) lockIterator.next();
889: handler.unlockTopic(virtualWikiName, lock
890: .getTopicName());
891: }
892: } catch (Exception e) {
893: logger.error("", e);
894: }
895: // destroy recent changes
896: if (Environment.getInstance().getPersistenceType() != DATABASE) {
897: try {
898: FileHandler.getPathFor(virtualWikiName,
899: "recent.xml").delete();
900: } catch (Exception e) {
901: logger.error("error removing recent.xml", e);
902: }
903: }
904: // failsafe
905: if (Environment.getInstance().getPersistenceType() != DATABASE) {
906: try {
907: File wikiDir = FileHandler.getPathFor(
908: virtualWikiName, null);
909: File[] locks = wikiDir
910: .listFiles(new FileExtensionFilter(".lock"));
911: for (int i = 0; i < locks.length; i++) {
912: File lock = locks[i];
913: lock.delete();
914: }
915: } catch (Exception e) {
916: logger.error("error removing recent.xml", e);
917: }
918: }
919: }
920: }
921:
922: /**
923: * Return true if the given topic is marked as "admin only", i.e. it is present in the admin only topics topic
924: *
925: * @param virtualWiki
926: * @param topicName
927: * @return
928: */
929: public boolean isAdminOnlyTopic(Locale locale, String virtualWiki,
930: String topicName) throws Exception {
931: String adminOnlyTopics = readRaw(virtualWiki, getMessages(
932: locale).getString("specialpages.adminonlytopics"));
933: StringTokenizer tokenizer = new StringTokenizer(adminOnlyTopics);
934: while (tokenizer.hasMoreTokens()) {
935: String token = tokenizer.nextToken();
936: if (token.equals(topicName)) {
937: return true;
938: }
939: }
940: return false;
941: }
942:
943: /**
944: * Get messages for the given locale
945: * @param locale locale
946: * @return
947: */
948: private ResourceBundle getMessages(Locale locale) {
949: ResourceBundle messages = ResourceBundle.getBundle(
950: "ApplicationResources", locale);
951: return messages;
952: }
953: }
|