001: /**
002: * The WikiServlet handles the main interactions from the user and forwards to the
003: * appropriate servlets and JSPs
004: *
005: * Copyright 2002 Gareth Cronin
006: * This software is subject to the GNU Lesser General Public Licence (LGPL)
007: */package vqwiki.servlets;
008:
009: import java.io.BufferedReader;
010: import java.io.IOException;
011: import java.io.StringReader;
012: import java.util.Collection;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.Locale;
016: import java.util.Map;
017: import java.util.ResourceBundle;
018: import java.util.Vector;
019:
020: import javax.servlet.RequestDispatcher;
021: import javax.servlet.ServletConfig;
022: import javax.servlet.ServletContext;
023: import javax.servlet.ServletException;
024: import javax.servlet.http.Cookie;
025: import javax.servlet.http.HttpServletRequest;
026: import javax.servlet.http.HttpServletResponse;
027: import javax.servlet.http.HttpSession;
028:
029: import org.apache.log4j.Logger;
030:
031: import vqwiki.ActionManager;
032: import vqwiki.Environment;
033: import vqwiki.PseudoTopicHandler;
034: import vqwiki.SearchEngine;
035: import vqwiki.SearchResultEntry;
036: import vqwiki.Topic;
037: import vqwiki.WikiAction;
038: import vqwiki.WikiBase;
039: import vqwiki.users.Usergroup;
040: import vqwiki.utils.JSPUtils;
041: import vqwiki.utils.Utilities;
042:
043: /*
044: * TODO This Servlet is a litle bit too complex. It could be a good idea to
045: * refactorize and split resposibilities in different objects.
046: */
047:
048: public class WikiServlet extends VQWikiServlet {
049:
050: private static final Logger logger = Logger
051: .getLogger(WikiServlet.class);
052: // constants used as the action parameter in calls to this servlet
053: public static final String ACTION_ADMIN = "action_admin";
054: public static final String ACTION_ATTACH = "action_attach";
055: public static final String ACTION_CANCEL = "Cancel";
056: public static final String ACTION_DIFF = "action_diff";
057: public static final String ACTION_EDIT = "action_edit";
058: public static final String ACTION_FIRST_USE = "action_firstuse";
059: public static final String ACTION_HISTORY = "action_history";
060: public static final String ACTION_IMPORT = "action_import";
061: public static final String ACTION_LOGIN = "action_login";
062: public static final String ACTION_MEMBER = "action_member";
063: public static final String ACTION_MENU_JUMP = "action_menujump";
064: public static final String ACTION_NOTIFY = "action_notify";
065: public static final String ACTION_PRINT = "action_printable";
066: public static final String ACTION_RSS = "RSS";
067: public static final String ACTION_SAVE_USER = "action_save_user";
068: public static final String ACTION_SEARCH = "action_search";
069: public static final String ACTION_UNLOCK = "action_unlock";
070: public static final String ACTION_VIEW_ATTACHMENT = "action_view_attachment";
071: public static final String ACTION_ALL_TOPICS = "all_topics";
072: public static final String ACTION_APPEND = "append";
073: public static final String ACTION_EDIT_USER = "edit_user";
074: public static final String ACTION_LOCKLIST = "locklist";
075: public static final String ACTION_ORPHANED_TOPICS = "orphaned_topics";
076: public static final String ACTION_PREVIEW = "preview";
077: public static final String ACTION_RECENT_CHANGES = "recent_changes";
078: public static final String ACTION_SAVE = "save";
079: public static final String ACTION_SAVE_TEMPLATE = "save_template";
080: public static final String ACTION_SEARCH_RESULTS = "search_results";
081: public static final String ACTION_TODO_TOPICS = "todo_topics";
082:
083: /** Servlet context */
084: // why static? Better not to do that.
085: private static ServletContext servletContext = null;
086: private Map cachedContents = new HashMap();
087:
088: /**
089: *
090: */
091: public void init(ServletConfig config) throws ServletException {
092: super .init(config);
093: // store servlet context reference so that it can be accessed from a static
094: // context
095: servletContext = config.getServletContext();
096: }
097:
098: /**
099: * Returns a reference to the current servlet context
100: */
101: public static ServletContext getCurrentContext() {
102: return servletContext;
103: }
104:
105: /**
106: *
107: */
108: protected void doPut(HttpServletRequest httpServletRequest,
109: HttpServletResponse httpServletResponse)
110: throws ServletException, IOException {
111: super .doPut(httpServletRequest, httpServletResponse);
112: Environment.getInstance().setRealPath(
113: httpServletRequest.getSession().getServletContext()
114: .getRealPath("/"));
115: }
116:
117: /**
118: * GET requests should come from topic display requests, edit requests, diffs
119: */
120: protected void doGet(HttpServletRequest request,
121: HttpServletResponse response) throws ServletException,
122: IOException {
123: logger.debug("GET Topic: " + request.getQueryString());
124: Environment.getInstance().setRealPath(
125: request.getSession().getServletContext().getRealPath(
126: "/"));
127: request.setAttribute("lastRequest", request.getRequestURL());
128: // expire now
129: response.setDateHeader("Expires", System.currentTimeMillis()
130: - 24 * 60 * 60 * 1000);
131: String topic = request.getQueryString();
132: if (topic == null) {
133: topic = "StartingPoints";
134: }
135: if (topic.equals("")) {
136: topic = "StartingPoints";
137: }
138: if (topic.indexOf('&') > 0) {
139: topic = topic.substring(0, topic.indexOf('&'));
140: }
141: if (request.getCharacterEncoding() != null) {
142: topic = JSPUtils.decodeURL(topic, request
143: .getCharacterEncoding());
144: } else {
145: topic = JSPUtils.decodeURL(topic, response
146: .getCharacterEncoding());
147: }
148: String virtualWiki = null;
149: try {
150: virtualWiki = Utilities.extractVirtualWiki(request);
151: } catch (Exception e) {
152: e.printStackTrace();
153: }
154: logger.debug("virtual wiki: " + virtualWiki);
155: request.setAttribute("virtual-wiki", virtualWiki);
156: request.setAttribute("virtualWiki", virtualWiki);
157: buildLayout(request, virtualWiki);
158: Environment en = Environment.getInstance();
159: request.setAttribute("env", en);
160: if (en.getStringSetting(Environment.PROPERTY_BASE_CONTEXT) == null) {
161: try {
162: //StringBuffer originalURL = request.getRequestURL();
163: StringBuffer originalURL = request.getRequestURL();
164: logger.info(originalURL);
165: String baseContext = originalURL
166: .substring(0, originalURL.length()
167: - virtualWiki.length() - 6);
168: en.setSetting(Environment.PROPERTY_BASE_CONTEXT,
169: baseContext);
170: } catch (Exception e) {
171: error(request, response, e);
172: return;
173: }
174: }
175: RequestDispatcher dispatch;
176: // make decision on action if one exists
177: String action = request.getParameter("action");
178: logger.debug("action: " + action);
179: if (action != null) {
180: String actionRedirect = PseudoTopicHandler.getInstance()
181: .getRedirectURL(action);
182: if (action.equals(ACTION_EDIT)) {
183: // a request to edit a topic
184: if (Environment.getInstance().getForceUsername()) {
185: if (Utilities.getUserFromRequest(request) == null) {
186: try {
187: request.setAttribute("userList", WikiBase
188: .getInstance()
189: .getUsergroupInstance()
190: .getListOfAllUsers());
191: } catch (Exception e) {
192: }
193: dispatch = request
194: .getRequestDispatcher(PseudoTopicHandler
195: .getInstance().getRedirectURL(
196: "SetUsername"));
197: dispatch.forward(request, response);
198: return;
199: }
200: }
201: dispatch = request.getRequestDispatcher("/EditServlet");
202: dispatch.forward(request, response);
203: return;
204: } else if (action.equals(ACTION_RSS)) {
205: dispatch = request.getRequestDispatcher("/RSS");
206: dispatch.forward(request, response);
207: return;
208: } else if (actionRedirect != null) {
209: logger
210: .debug("Using redirect from pseudotopics actions: "
211: + actionRedirect);
212: dispatch(actionRedirect, request, response);
213: return;
214: } else if (ActionManager.getInstance().actionExists(action)) {
215: logger.debug("using action mapping from ActionManager");
216: try {
217: WikiAction wikiAction = ActionManager.getInstance()
218: .getActionInstance(action);
219: if (wikiAction != null) {
220: wikiAction.doAction(request, response);
221: return;
222: }
223: } catch (Exception e) {
224: logger.error("error running action", e);
225: request.setAttribute("exception", e);
226: request.setAttribute("title", "Error");
227: log("Error in " + this .getClass(), e);
228: if (e instanceof WikiServletException) {
229: request.setAttribute(
230: "javax.servlet.jsp.jspException", e);
231: }
232: dispatch("/jsp/servlet-error.jsp", request,
233: response);
234: return;
235: }
236: }
237: }
238: logger.debug("no action mappings, assuming topic");
239: request.setAttribute("topic", JSPUtils.decodeURL(topic));
240: request.setAttribute("title", JSPUtils.decodeURL(topic));
241: // make decision based on topic
242: response.setContentType("text/html");
243: String pseudotopicRedirect = PseudoTopicHandler.getInstance()
244: .getRedirectURL(topic);
245: if (pseudotopicRedirect != null) {
246: PseudoTopicHandler.getInstance().setAttributes(topic,
247: request);
248: dispatch(pseudotopicRedirect, request, response);
249: return;
250: } else {
251: dispatchTopic(request, topic, virtualWiki, response, en);
252: }
253: }
254:
255: /**
256: *
257: */
258: private void buildLayout(HttpServletRequest request,
259: String virtualWiki) {
260: // build the layout contents
261: ResourceBundle messages = getMessages(request.getLocale());
262: addIfNotEmpty(request, "leftMenu", getCachedContent(
263: virtualWiki, messages
264: .getString("specialpages.leftMenu")));
265: request.setAttribute("topArea", getCachedContent(virtualWiki,
266: messages.getString("specialpages.topArea")));
267: request.setAttribute("bottomArea", getCachedContent(
268: virtualWiki, messages
269: .getString("specialpages.bottomArea")));
270: request.setAttribute("StyleSheet", getCachedRawContent(
271: virtualWiki, messages
272: .getString("specialpages.stylesheet")));
273: }
274:
275: /**
276: *
277: */
278: private ResourceBundle getMessages(Locale locale) {
279: ResourceBundle messages = ResourceBundle.getBundle(
280: "ApplicationResources", locale);
281: return messages;
282: }
283:
284: /**
285: * Setup request and despatch to the JSP to display a topic
286: * @param request
287: * @param topic
288: * @param virtualWiki
289: * @param response
290: * @param en
291: */
292: private void dispatchTopic(HttpServletRequest request,
293: String topic, String virtualWiki,
294: // FIXME - this servlet is too complex and should be broken up
295: HttpServletResponse response, Environment en) {
296: try {
297: if (WikiBase.getInstance().isAdminOnlyTopic(
298: request.getLocale(), virtualWiki, topic)) {
299: if (!Utilities.isAdmin(request)) {
300: request.setAttribute("title", Utilities.resource(
301: "login.title", request.getLocale()));
302: logger.debug("Current URL: "
303: + request.getRequestURL());
304: String rootPath = JSPUtils.createLocalRootPath(
305: request, virtualWiki);
306: StringBuffer buffer = new StringBuffer();
307: buffer.append(rootPath);
308: buffer.append("Wiki?" + topic);
309: request.setAttribute("redirect", buffer.toString());
310: dispatch("/jsp/login.jsp", request, response);
311: return;
312: }
313: }
314: } catch (Exception e) {
315: logger.error("error checking admin only topic", e);
316: }
317: String contents = null;
318: try {
319: String rawcontents = WikiBase.getInstance().readRaw(
320: virtualWiki, topic);
321: // deal with redirection
322: if (rawcontents.startsWith("redirect:")) {
323: if (rawcontents.trim().length() > 9) {
324: // The rest until end or newline is a topic name.
325: if (rawcontents.indexOf("\n") >= 0) {
326: topic = rawcontents.substring(
327: rawcontents.indexOf(":") + 1,
328: rawcontents.indexOf("\n")).trim();
329: } else {
330: topic = rawcontents.substring(
331: rawcontents.indexOf(":") + 1).trim();
332: }
333: redirect("Wiki?"
334: + JSPUtils.encodeURL(topic, response
335: .getCharacterEncoding()), response);
336: return;
337: }
338: }
339: // convert the rawcontent to html content
340: contents = WikiBase.getInstance().cook(
341: new BufferedReader(new StringReader(rawcontents)),
342: virtualWiki);
343: } catch (Exception e) {
344: error(request, response, e);
345: return;
346: }
347: // highlight search result
348: if (request.getParameter("highlight") != null) {
349: String highlightparam = request.getParameter("highlight");
350: String highlighttext = "<b style=\"color:black;background-color:#ffff66\">###</b>";
351: contents = markToReplaceOutsideHTML(contents,
352: highlightparam);
353: for (int i = 0; i < highlightparam.length(); i++) {
354: String myhighlightparam = highlightparam
355: .substring(0, i)
356: + highlightparam.substring(i, i + 1)
357: .toUpperCase();
358: if ((i + 1) < highlightparam.length()) {
359: myhighlightparam += highlightparam.substring(i + 1);
360: }
361: String highlight = highlighttext;
362: highlight = Utilities.replaceString(highlight, "###",
363: myhighlightparam);
364: contents = replaceMarked(contents, myhighlightparam,
365: highlight);
366: myhighlightparam = highlightparam.substring(0, i)
367: + highlightparam.substring(i, i + 1)
368: .toLowerCase();
369: if ((i + 1) < highlightparam.length()) {
370: myhighlightparam += highlightparam.substring(i + 1);
371: }
372: highlight = highlighttext;
373: highlight = Utilities.replaceString(highlight, "###",
374: myhighlightparam);
375: contents = replaceMarked(contents, myhighlightparam,
376: highlight);
377: }
378: }
379: // -------------
380: // Handle page history (breadcrumb trail)
381: HttpSession session = request.getSession();
382: Vector history = (Vector) session.getAttribute("history");
383: String historyVirtualWiki = (String) session
384: .getAttribute("historyVirtualWiki");
385: if (historyVirtualWiki != null) {
386: if (!virtualWiki.equals(historyVirtualWiki)) {
387: // reset history on virtual wiki changes
388: history = new Vector();
389: session.setAttribute("historyVirtualWiki", virtualWiki);
390: }
391: } else {
392: session.setAttribute("historyVirtualWiki", virtualWiki);
393: }
394: if (history == null) {
395: history = new Vector();
396: }
397: // if user clicked on "refresh"
398: if (history.size() > 0 && topic.equals(history.lastElement())) {
399: history.remove(history.size() - 1);
400: }
401: // add current page to history
402: if (history.contains(topic)) {
403: // go back in history
404: int found = history.indexOf(topic);
405: int pos = history.size() - 1;
406: while (pos >= found) {
407: history.remove(pos);
408: pos--;
409: }
410: }
411: // store the history in the request
412: request.setAttribute("historyThisPage", new Vector(history));
413: // really add it
414: history.add(topic);
415: // store it in session
416: session.setAttribute("history", history);
417: try {
418: SearchEngine sedb = WikiBase.getInstance()
419: .getSearchEngineInstance();
420: int maxBackLinks = en
421: .getIntSetting(Environment.PROPERTY_MAXIMUM_BACKLINKS);
422: // create backlinks
423: if (topic != null) {
424: Collection results = sedb.findLinkedTo(virtualWiki,
425: topic);
426: ResourceBundle messages = getMessages(request
427: .getLocale());
428: if (results != null && results.size() > 0) {
429: StringBuffer buffer = new StringBuffer("");
430: buffer
431: .append("<br /><br /><span class=\"backlinks\">");
432: buffer.append(topic);
433: buffer.append(" ");
434: buffer.append(messages
435: .getString("topic.ismentionedon"));
436: buffer.append(" ");
437: Iterator it = results.iterator();
438: String divider = "";
439: int i = 0;
440: for (; i < maxBackLinks && it.hasNext(); i++) {
441: SearchResultEntry result = (SearchResultEntry) it
442: .next();
443: String pathRoot = JSPUtils.createLocalRootPath(
444: request, virtualWiki);
445: request.setAttribute("pathRoot", pathRoot);
446: if (!result.getTopic().equals(topic)) {
447: buffer.append(divider);
448: buffer.append("<a href=\"");
449: buffer.append(pathRoot);
450: buffer.append("Wiki?");
451: buffer.append(result.getTopic());
452: if (result.getFoundWord().length() > 0) {
453: buffer.append("&highlight=");
454: buffer.append(JSPUtils.encodeURL(result
455: .getFoundWord(), response
456: .getCharacterEncoding()));
457: }
458: buffer.append("\">");
459: buffer.append(result.getTopic());
460: buffer.append("</a>");
461: divider = " | ";
462: }
463: }
464: if (i == 20) {
465: buffer.append("...");
466: }
467: buffer.append("</span>");
468: contents += buffer.toString();
469: }
470: }
471: } catch (Exception e) {
472: logger.warn(e.getMessage(), e);
473: }
474: request.setAttribute("contents", contents);
475: logger.debug("contents: " + contents);
476: if (Environment.getInstance().isVersioningOn()) {
477: try {
478: logger.debug("topic: " + topic);
479: Topic topicData = new Topic(topic);
480: java.util.Date revDate = topicData
481: .getMostRecentRevisionDate(virtualWiki);
482: String userid = topicData
483: .getMostRecentAuthor(virtualWiki);
484: Usergroup usergroup = WikiBase.getInstance()
485: .getUsergroupInstance();
486: String author = usergroup.getFullnameById(userid);
487: if (revDate != null) {
488: request.setAttribute("lastRevisionDate", revDate);
489: if (author != null) {
490: request.setAttribute("lastAuthor", author);
491: request.setAttribute("lastAuthorDetails",
492: usergroup.getUserDetails(userid));
493: }
494: }
495: } catch (Exception e) {
496: logger.warn(e.getMessage(), e);
497: }
498: }
499: boolean readOnly = false;
500: try {
501: if (topic != null) {
502: Topic t = new Topic(topic);
503: readOnly = t.isReadOnlyTopic(virtualWiki);
504: }
505: } catch (Exception e) {
506: logger.warn(e.getMessage(), e);
507: }
508: request.setAttribute("readOnly", new Boolean(readOnly));
509: dispatch("/jsp/wiki.jsp", request, response);
510: }
511:
512: /**
513: *
514: */
515: private void addIfNotEmpty(HttpServletRequest request, String name,
516: String content) {
517: logger
518: .debug("addIfNotEmpty called for " + name + "/"
519: + content);
520: if (content == null) {
521: logger.debug("content provided is null, returning");
522: return;
523: }
524: content = content.trim();
525: if ("".equals(content)) {
526: logger.debug("content is empty, returning");
527: return;
528: }
529: if ("delete".equalsIgnoreCase(content)) {
530: logger.debug("content is marked for purging, returning");
531: return;
532: }
533: if ("This is a new topic".equalsIgnoreCase(content)) {
534: logger.debug("topic is an unchanged new topic, returning");
535: return;
536: }
537: logger.debug("setting content " + name + " = " + content);
538: request.setAttribute(name, content);
539: }
540:
541: /**
542: *
543: */
544: private interface WikiReader {
545: String read(String virtualWiki, String topic) throws Exception;
546: }
547:
548: /**
549: *
550: */
551: private static WikiReader cookedReader = new WikiReader() {
552: public String read(String virtualWiki, String topic)
553: throws Exception {
554: return WikiBase.getInstance()
555: .readCooked(virtualWiki, topic);
556: }
557: };
558:
559: /**
560: *
561: */
562: private static WikiReader rawReader = new WikiReader() {
563: public String read(String virtualWiki, String topic)
564: throws Exception {
565: return WikiBase.getInstance().readRaw(virtualWiki, topic);
566: }
567: };
568:
569: /**
570: *
571: */
572: private String getCached(String virtualWiki, String topic,
573: WikiReader wr) {
574: String content = (String) cachedContents.get(virtualWiki + "-"
575: + topic);
576: if (content == null) {
577: try {
578: logger.debug("reloading topic " + topic);
579: content = wr.read(virtualWiki, topic);
580: synchronized (cachedContents) {
581: cachedContents.put(virtualWiki + "-" + topic,
582: content);
583: }
584: } catch (Exception e) {
585: logger.warn("error getting cached page", e);
586: return null;
587: }
588: }
589: return content;
590: }
591:
592: /**
593: * Implements a caching for "fixed" contents.
594: * Caching is particularly important for often-asked topics (like left-side-menu,
595: * top-banners, bottom-banners, etc. that are asked for every request)
596: *
597: * @param virtualWiki the virtual wiki
598: * @param topic the topic name
599: * @return the topic contents
600: */
601: private String getCachedContent(String virtualWiki, String topic) {
602: return getCached(virtualWiki, topic, cookedReader);
603: }
604:
605: /**
606: * Implements a caching for "fixed" contents.
607: * Caching is particularly important for often-asked topics (like left-side-menu,
608: * top-banners, bottom-banners, etc. that are asked for every request)
609: *
610: * @param virtualWiki the virtual wiki
611: * @param topic the topic name
612: * @return the topic contents
613: */
614: private String getCachedRawContent(String virtualWiki, String topic) {
615: return getCached(virtualWiki, topic, rawReader);
616: }
617:
618: /**
619: * Clears the cached content
620: * This method is called when a "edit-save" or "edit-cancel" is invoked.
621: * <p/>
622: * Clearing all cached contents forces to reload.
623: */
624: private void removeCachedContents() {
625: if (logger.isDebugEnabled()) {
626: logger.debug("Removing Cached Contents; "
627: + "cachedContents.size() = "
628: + cachedContents.size());
629: }
630: cachedContents.clear();
631: }
632:
633: /**
634: * POST requests should only come from saves and searches
635: */
636: protected void doPost(HttpServletRequest request,
637: HttpServletResponse response) throws ServletException,
638: IOException {
639: logger.debug("POST");
640: request.setAttribute("lastRequest", request.getRequestURL());
641: RequestDispatcher dispatch;
642: response.setContentType("text/html");
643: String virtualWiki = null;
644: try {
645: virtualWiki = Utilities.extractVirtualWiki(request);
646: } catch (Exception e) {
647: e.printStackTrace();
648: }
649: logger.debug("virtual wiki: " + virtualWiki);
650: // TODO virtual-wiki and virtualWiki request params should be unified.
651: request.setAttribute("virtual-wiki", virtualWiki);
652: request.setAttribute("virtualWiki", virtualWiki);
653: request.setAttribute("env", Environment.getInstance());
654: buildLayout(request, virtualWiki);
655: // make decision based on action
656: String action = request.getParameter("action");
657: if (action != null) {
658: logger.debug("Wiki action: " + action);
659: String actionRedirect = PseudoTopicHandler.getInstance()
660: .getRedirectURL(action);
661: logger.debug("actionRedirect: " + actionRedirect);
662: // first, convert locale-specific action into a constant. this isn't
663: // terribly important with the current code, but if anything is to
664: // be done with action values in the future it will be helpful.
665: if (checkAction(action, Utilities.resource(
666: "edit.action.save", request.getLocale()))) {
667: action = ACTION_SAVE;
668: } else if (checkAction(action, Utilities.resource(
669: "edit.action.append", request.getLocale()))) {
670: action = ACTION_APPEND;
671: } else if (checkAction(action, Utilities.resource(
672: "edit.action.preview", request.getLocale()))) {
673: action = ACTION_PREVIEW;
674: } else if (checkAction(action, Utilities.resource(
675: "edit.action.savetemplate", request.getLocale()))) {
676: action = ACTION_SAVE_TEMPLATE;
677: } else if (action.equals(Utilities.resource(
678: "edit.action.cancel", request.getLocale()))) {
679: action = ACTION_CANCEL;
680: }
681: if (actionRedirect != null) {
682: // Handle the layout pages in a cache: do not reload the for every
683: // request, just reload when an update is made on any page (SaveTopicServlet)
684: // This is for performance reasons.
685: //
686: // In the previous version the removeCachedContents() call was added in update
687: // methods; in this version, this didn't work due to this new
688: // implementation by PseudoTopicHandler, so the
689: // checkActionAndRemoveCachedContentsIfNeeded method call was added.
690: //
691: // TODO: Simplify this servlet.
692: checkActionAndRemoveCachedContentsIfNeeded(action,
693: request.getLocale());
694: logger
695: .debug("Using redirect from pseudotopics actions: "
696: + actionRedirect);
697: dispatch(actionRedirect, request, response);
698: return;
699: } else if (action.equals(ACTION_SEARCH)) {
700: // a search request has been made
701: dispatch = request
702: .getRequestDispatcher("/SearchServlet");
703: dispatch.forward(request, response);
704: return;
705: } else if (action.equals(ACTION_SAVE)) {
706: // a save request has been made
707: logger.debug("Dispatching save");
708: removeCachedContents();
709: dispatch = request
710: .getRequestDispatcher("/SaveTopicServlet");
711: dispatch.forward(request, response);
712: return;
713: } else if (action.equals(ACTION_APPEND)) {
714: // a append template request has been made
715: logger.debug("Dispatching append template");
716: dispatch = request
717: .getRequestDispatcher("/SaveTopicServlet");
718: dispatch.forward(request, response);
719: return;
720: } else if (action.equals(ACTION_PREVIEW)) {
721: // a save request has been made
722: logger.debug("Dispatching preview");
723: removeCachedContents();
724: request.setAttribute(ACTION_PREVIEW, "true");
725: dispatch = request.getRequestDispatcher("/EditServlet");
726: dispatch.forward(request, response);
727: return;
728: } else if (action.equals(ACTION_ADMIN)) {
729: // request to save admin values
730: logger.debug("Despatching admin servlet");
731: dispatch = request
732: .getRequestDispatcher("/AdministrationServlet");
733: dispatch.forward(request, response);
734: return;
735: } else if (action.equals(ACTION_SAVE_TEMPLATE)) {
736: // save template
737: logger.debug("Despatching save template");
738: removeCachedContents();
739: dispatch = request
740: .getRequestDispatcher("/SaveTemplateServlet");
741: dispatch.forward(request, response);
742: return;
743: } else if (action.equals(ACTION_RSS)) {
744: // save template
745: dispatch = request.getRequestDispatcher("/RSS");
746: dispatch.forward(request, response);
747: return;
748: } else if (action.equals(ACTION_CANCEL)) {
749: // cancellation of edit
750: String topic = request.getParameter("topic");
751: try {
752: WikiBase.getInstance().unlockTopic(virtualWiki,
753: topic);
754: } catch (Exception err) {
755: error(request, response, new WikiServletException(
756: err.getMessage()));
757: return;
758: }
759: String next = "Wiki?" + topic;
760: removeCachedContents();
761: response.sendRedirect(response.encodeRedirectURL(next));
762: return;
763: } else if (action.equals(ACTION_SAVE_USER)) {
764: String username = request.getParameter("username");
765: if (username == null || username.trim().length() == 0) {
766: // FIXME: this is a fix for VQW-54, but it could be handled more elegantly
767: ResourceBundle messages = getMessages(request
768: .getLocale());
769: error(
770: request,
771: response,
772: new WikiServletException(messages
773: .getString("exception.badusername")));
774: return;
775: }
776: Cookie c = Utilities.createUsernameCookie(username);
777: logger.debug("Delivering cookie: " + c.getName() + " "
778: + c.getValue());
779: try {
780: response.addCookie(c);
781: } catch (Exception e) {
782: logger.warn(e.getMessage(), e);
783: ResourceBundle messages = getMessages(request
784: .getLocale());
785: error(
786: request,
787: response,
788: new WikiServletException(messages
789: .getString("exception.badusername")));
790: return;
791: }
792: String topic = request.getParameter("topic");
793: request.setAttribute("title", "SetUsername");
794: if (topic == null || "".equals(topic)) {
795: try {
796: request.setAttribute("userList", WikiBase
797: .getInstance().getUsergroupInstance()
798: .getListOfAllUsers());
799: } catch (Exception e) {
800: }
801: dispatch = request
802: .getRequestDispatcher(PseudoTopicHandler
803: .getInstance().getRedirectURL(
804: "SetUsername"));
805: dispatch.forward(request, response);
806: return;
807: } else {
808: request.setAttribute("topic", topic);
809: dispatch = request
810: .getRequestDispatcher("/EditServlet");
811: dispatch.forward(request, response);
812: return;
813: }
814: } else if (action.equals(ACTION_NOTIFY)) {
815: dispatch = request
816: .getRequestDispatcher("/NotifyServlet");
817: dispatch.forward(request, response);
818: return;
819: } else if (action.equals(ACTION_MEMBER)) {
820: dispatch = request
821: .getRequestDispatcher("/MemberServlet");
822: dispatch.forward(request, response);
823: return;
824: }
825: // in case, no action can be dispatched, go to a normal wiki page
826: }
827: dispatch = request.getRequestDispatcher("/jsp/wiki.jsp");
828: dispatch.forward(request, response);
829: }
830:
831: /**
832: * if the action is Save, SaveTemplate or CancelFromEdit, clears the cache
833: * and force the wiki to reload layout page elements
834: * (topArea, bottomArea, leftMenu, etc.)
835: */
836: private void checkActionAndRemoveCachedContentsIfNeeded(
837: String action, Locale locale) {
838: if (action.equals(ACTION_SAVE)
839: || action.equals(ACTION_SAVE_TEMPLATE)
840: || action.equals(ACTION_CANCEL)) {
841: removeCachedContents();
842: }
843: }
844:
845: /**
846: *
847: */
848: private boolean checkAction(String original, String test) {
849: if (original.equals(test)) {
850: return true;
851: }
852: // find in test the first character, which is not alpabetic
853: int count;
854: String test2 = test.toLowerCase();
855: for (count = 0; count < test.length(); count++) {
856: if (!(test2.charAt(count) >= 'a' && test2.charAt(count) <= 'z')) {
857: break;
858: }
859: }
860: count--;
861: if (count < 0) {
862: return false;
863: }
864: // fix by pcs_org
865: if (original.length() < count) {
866: return false;
867: }
868: if (original.substring(0, count).equals(
869: test.substring(0, count))) {
870: return true;
871: } else {
872: return false;
873: }
874: }
875:
876: /**
877: * Mark all needles in a haystack, so that they can be replaced later. Take special care on HTML,
878: * so that no needle is replaced inside a HTML tag.
879: *
880: * @param haystack The haystack to go through.
881: * @param needle The needle to search.
882: * @return The haystack with all needles (outside HTML) marked with the char \u0000
883: */
884: public static String markToReplaceOutsideHTML(String haystack,
885: String needle) {
886: if (needle.length() == 0) {
887: return haystack;
888: }
889: StringBuffer sb = new StringBuffer();
890: boolean inHTMLmode = false;
891: int l = haystack.length();
892: for (int j = 0; j < l; j++) {
893: char c = haystack.charAt(j);
894: switch (c) {
895: case '<':
896: if (((j + 1) < l) && (haystack.charAt(j + 1) != ' ')) {
897: inHTMLmode = true;
898: }
899: break;
900: case '>':
901: if (inHTMLmode) {
902: inHTMLmode = false;
903: }
904: break;
905: }
906: if ((c == needle.charAt(0) || Math
907: .abs(c - needle.charAt(0)) == 32)
908: && !inHTMLmode) {
909: boolean ok = true;
910: if ((j + needle.length()) > l
911: || !haystack.substring(j, j + needle.length())
912: .equalsIgnoreCase(needle)) {
913: ok = false;
914: }
915: if (ok) {
916: sb.append('\u0000');
917: for (int k = 0; k < needle.length(); k++) {
918: sb.append(haystack.charAt(j + k));
919: }
920: j = j + needle.length() - 1;
921: } else {
922: sb.append(c);
923: }
924: } else {
925: sb.append(c);
926: }
927: }
928: return sb.toString();
929: }
930:
931: /**
932: * Replace all needles inside the text with their replacements.
933: *
934: * @param text The text or haystack, where all needles are already marked with the unicode character \u0000
935: * @param needle The needle to search
936: * @param replacement The text, which replaces the needle
937: * @return String containing the text with the needle replaced by the replacement.
938: */
939: public static String replaceMarked(String text, String needle,
940: String replacement) {
941: needle = '\u0000' + needle;
942: text = Utilities.replaceString(text, needle, replacement);
943: return text;
944: }
945: }
|