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.file;
019:
020: import JSX.ObjIn;
021: import JSX.ObjOut;
022: import org.apache.log4j.Logger;
023: import vqwiki.*;
024: import vqwiki.utils.JSPUtils;
025: import vqwiki.utils.Utilities;
026:
027: import javax.servlet.http.HttpServletRequest;
028: import java.io.*;
029: import java.util.*;
030:
031: public class FileChangeLog implements ChangeLog {
032:
033: private static final Logger logger = Logger
034: .getLogger(FileChangeLog.class);
035: private static FileChangeLog instance;
036: // recent changes file
037: public static final String RECENTFILE = "recent.xml";
038: private HashMap cache;
039:
040: /**
041: *
042: */
043: private FileChangeLog() {
044: cache = new HashMap();
045: }
046:
047: /**
048: *
049: */
050: private Hashtable getTableFor(String virtualWiki)
051: throws IOException, ClassNotFoundException {
052: if (virtualWiki == null)
053: virtualWiki = "";
054: if (cache.containsKey(virtualWiki)) {
055: return (Hashtable) cache.get(virtualWiki);
056: }
057: File changesPath = FileHandler.getPathFor(virtualWiki,
058: RECENTFILE);
059: logger.debug("reading changes for " + virtualWiki + " from "
060: + changesPath);
061: Hashtable vwikiCache;
062: if (!changesPath.exists()) {
063: logger.debug("no file exists, creating now");
064: vwikiCache = new Hashtable();
065: cache.put(virtualWiki, vwikiCache);
066: saveTableFor(virtualWiki);
067: return vwikiCache;
068: }
069: logger.debug("reading file from disk");
070: FileInputStream fileInputStream = new FileInputStream(
071: changesPath);
072: ObjIn in = new ObjIn(fileInputStream);
073: vwikiCache = (Hashtable) in.readObject();
074: cache.put(virtualWiki, vwikiCache);
075: in.close();
076: fileInputStream.close();
077: return vwikiCache;
078: }
079:
080: /**
081: *
082: */
083: private void saveTableFor(String virtualWiki) throws IOException {
084: if (virtualWiki == null)
085: virtualWiki = "";
086: File changesPath = FileHandler.getPathFor(virtualWiki,
087: RECENTFILE);
088: FileOutputStream fileOutputStream = new FileOutputStream(
089: changesPath);
090: ObjOut out = new ObjOut(fileOutputStream);
091: Object changeTable = cache.get(virtualWiki);
092: logger.debug("Change table for " + virtualWiki + ": "
093: + changeTable);
094: out.writeObject(changeTable);
095: out.close();
096: fileOutputStream.close();
097: logger.debug("wrote changes to disk: " + changesPath);
098: }
099:
100: /**
101: *
102: */
103: public static final FileChangeLog getInstance() {
104: if (instance == null)
105: instance = new FileChangeLog();
106: return instance;
107: }
108:
109: /**
110: *
111: */
112: public synchronized void logChange(Change change,
113: HttpServletRequest request) throws IOException,
114: FileNotFoundException, ClassNotFoundException {
115: logger.debug("logging change " + change);
116: String date = Utilities.formatDate(new Date());
117: String virtualWiki = change.getVirtualWiki();
118: Hashtable changesTable = getTableFor(virtualWiki);
119: Vector changesInFile;
120: if (changesTable.get(date) == null) {
121: logger.debug("no changes on " + date);
122: changesInFile = new Vector();
123: changesTable.put(date, changesInFile);
124: } else {
125: logger.debug("adding to changes for " + date);
126: changesInFile = (Vector) changesTable.get(date);
127: }
128: boolean suppressNotifyInSameDay = Environment
129: .getInstance()
130: .getBooleanSetting(
131: Environment.PROPERTY_SUPPRESS_NOTIFY_WITHIN_SAME_DAY);
132: logger.debug("changesInFile: " + changesInFile);
133: boolean changedToday = false;
134: if (changesInFile.contains(change)) {
135: if (logger.isDebugEnabled()) {
136: logger.debug("removing existing change");
137: if (suppressNotifyInSameDay) {
138: logger
139: .debug("not sending notifications because the topic has already been changed today");
140: }
141: }
142: changesInFile.remove(change);
143: changedToday = true;
144: }
145: if (!changedToday && suppressNotifyInSameDay
146: || !suppressNotifyInSameDay) {
147: try {
148: logger.debug("running notifier");
149: Notify notifier = new FileNotify(virtualWiki, change
150: .getTopic());
151: String wikiServerHostname = Environment
152: .getInstance()
153: .getStringSetting(
154: Environment.PROPERTY_WIKI_SERVER_HOSTNAME);
155: notifier.sendNotifications(JSPUtils.createRootPath(
156: request, virtualWiki, wikiServerHostname),
157: request.getLocale());
158: } catch (Exception e) {
159: logger.warn("exception occurred in notifier", e);
160: e.printStackTrace();
161: }
162: }
163: // add change to front of Vector, so that date-sorting within day works
164: // correctly.
165: logger.debug("adding change " + change);
166: changesInFile.add(0, change);
167: saveTableFor(virtualWiki);
168: }
169:
170: /**
171: * Get all recent changes for a particular date
172: *
173: * @param virtualWiki
174: * the virtual wiki
175: * @param d
176: * the date of the changes
177: * @return
178: * @throws IOException
179: * @throws FileNotFoundException
180: * @throws ClassNotFoundException
181: */
182: public Collection getChanges(String virtualWiki, Date d)
183: throws IOException, FileNotFoundException,
184: ClassNotFoundException {
185: String date = Utilities.formatDate(d);
186: return (Collection) getTableFor(virtualWiki).get(date);
187: }
188:
189: /**
190: * Delete the existing recent changes file
191: *
192: * @param virtualWiki
193: */
194: public void deleteChangeTableFile(String virtualWiki) {
195: try {
196: FileHandler.getPathFor(virtualWiki, RECENTFILE).delete();
197: } catch (Exception err) {
198: logger.error("Unable to delete recent changes file for "
199: + virtualWiki, err);
200: }
201: }
202:
203: /**
204: *
205: */
206: public void removeChanges(String virtualwiki, Collection cl)
207: throws IOException, ClassNotFoundException {
208: Hashtable changesTable = getTableFor(virtualwiki);
209: logger.debug("purging topics from the recent filelist");
210: Set changesSet = changesTable.keySet();
211: Set removesSet = new HashSet();
212: for (Iterator iter = changesSet.iterator(); iter.hasNext();) {
213: Object element = iter.next();
214: Vector changes = (Vector) changesTable.get(element);
215: Vector removeChanges = new Vector();
216: for (Iterator iterator = changes.iterator(); iterator
217: .hasNext();) {
218: Change change = (Change) iterator.next();
219: if (change.getVirtualWiki().equals(virtualwiki)
220: && cl.contains(change.getTopic())) {
221: logger
222: .debug("remove (purge) topic from the changelog: "
223: + change.getTopic());
224: removeChanges.add(change);
225: }
226: }
227: if (changes.size() == removeChanges.size()) {
228: removesSet.add(element);
229: } else {
230: changes.removeAll(removeChanges);
231: }
232: }
233: changesSet.removeAll(removesSet);
234: saveTableFor(virtualwiki);
235: }
236: }
|