0001: /*
0002: JSPWiki - a JSP-based WikiWiki clone.
0003:
0004: Copyright (C) 2001-2005 Janne Jalkanen (Janne.Jalkanen@iki.fi)
0005:
0006: This program is free software; you can redistribute it and/or modify
0007: it under the terms of the GNU Lesser General Public License as published by
0008: the Free Software Foundation; either version 2.1 of the License, or
0009: (at your option) any later version.
0010:
0011: This program is distributed in the hope that it will be useful,
0012: but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: GNU Lesser General Public License for more details.
0015:
0016: You should have received a copy of the GNU Lesser General Public License
0017: along with this program; if not, write to the Free Software
0018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0019: */
0020: package com.ecyrd.jspwiki;
0021:
0022: import java.io.*;
0023: import java.util.*;
0024: import org.apache.log4j.*;
0025: import javax.servlet.*;
0026: import javax.servlet.http.HttpServletRequest;
0027: import javax.servlet.http.HttpServletResponse;
0028: import com.ecyrd.jspwiki.plugin.PluginManager;
0029: import com.ecyrd.jspwiki.rss.RSSGenerator;
0030: import com.ecyrd.jspwiki.search.SearchManager;
0031: import com.ecyrd.jspwiki.providers.WikiPageProvider;
0032: import com.ecyrd.jspwiki.providers.ProviderException;
0033: import com.ecyrd.jspwiki.attachment.AttachmentManager;
0034: import com.ecyrd.jspwiki.attachment.Attachment;
0035: import com.ecyrd.jspwiki.auth.AuthorizationManager;
0036: import com.ecyrd.jspwiki.auth.UserManager;
0037: import com.ecyrd.jspwiki.auth.UserProfile;
0038:
0039: import com.ecyrd.jspwiki.filters.FilterException;
0040: import com.ecyrd.jspwiki.filters.FilterManager;
0041:
0042: import com.ecyrd.jspwiki.url.URLConstructor;
0043: import com.ecyrd.jspwiki.util.ClassUtil;
0044: import com.ecyrd.jspwiki.diff.DifferenceManager;
0045: import com.ecyrd.jspwiki.util.HttpUtil;
0046:
0047: import com.sun.portal.app.wiki.WikiPortletContext;
0048: import com.sun.jspwiki.community.CommunityContext;
0049:
0050: /**
0051: * Provides Wiki services to the JSP page.
0052: *
0053: * <P>
0054: * This is the main interface through which everything should go.
0055: *
0056: * <P>
0057: * Using this class: Always get yourself an instance from JSP page
0058: * by using the WikiEngine.getInstance() method. Never create a new
0059: * WikiEngine() from scratch, unless you're writing tests.
0060: * <p>
0061: * There's basically only a single WikiEngine for each web application, and
0062: * you should always get it using the WikiEngine.getInstance() method.
0063: *
0064: * @author Janne Jalkanen
0065: */
0066: public class WikiEngine {
0067: private static final Logger log = Logger
0068: .getLogger(WikiEngine.class);
0069:
0070: /** True, if log4j has been configured. */
0071: // FIXME: If you run multiple applications, the first application
0072: // to run defines where the log goes. Not what we want.
0073: private static boolean c_configured = false;
0074:
0075: /** Stores properties. */
0076: private Properties m_properties;
0077:
0078: /** The web.xml parameter that defines where the config file is to be found.
0079: * If it is not defined, uses the default as defined by DEFAULT_PROPERTYFILE.
0080: * @value jspwiki.propertyfile
0081: */
0082:
0083: public static final String PARAM_PROPERTYFILE = "jspwiki.propertyfile";
0084:
0085: /** Property for application name */
0086: public static final String PROP_APPNAME = "jspwiki.applicationName";
0087:
0088: /** Property start for any interwiki reference. */
0089: public static final String PROP_INTERWIKIREF = "jspwiki.interWikiRef.";
0090:
0091: /** If true, then the user name will be stored with the page data.*/
0092: public static final String PROP_STOREUSERNAME = "jspwiki.storeUserName";
0093:
0094: /** Define the used encoding. Currently supported are ISO-8859-1 and UTF-8 */
0095: public static final String PROP_ENCODING = "jspwiki.encoding";
0096:
0097: /** The name for the base URL to use in all references. */
0098: public static final String PROP_BASEURL = "jspwiki.baseURL";
0099:
0100: public static final String PROP_REFSTYLE = "jspwiki.referenceStyle";
0101:
0102: /** Property name for the "spaces in titles" -hack. */
0103: public static final String PROP_BEAUTIFYTITLE = "jspwiki.breakTitleWithSpaces";
0104:
0105: /** Property name for where the jspwiki work directory should be.
0106: If not specified, reverts to ${java.tmpdir}. */
0107: public static final String PROP_WORKDIR = "jspwiki.workDir";
0108:
0109: /** The name of the cookie that gets stored to the user browser. */
0110: public static final String PREFS_COOKIE_NAME = "JSPWikiUserProfile";
0111:
0112: /** Property name for the "match english plurals" -hack. */
0113: public static final String PROP_MATCHPLURALS = "jspwiki.translatorReader.matchEnglishPlurals";
0114: /** Property name for the template that is used. */
0115: public static final String PROP_TEMPLATEDIR = "jspwiki.templateDir";
0116:
0117: /** Property name for the default front page. */
0118: public static final String PROP_FRONTPAGE = "jspwiki.frontPage";
0119:
0120: /** Property name for setting the url generator instance */
0121:
0122: public static final String PROP_URLCONSTRUCTOR = "jspwiki.urlConstructor";
0123:
0124: private static final String PROP_SPECIALPAGE = "jspwiki.specialPage.";
0125:
0126: /** If this property is set to false, all filters are disabled when translating. */
0127: public static final String PROP_RUNFILTERS = "jspwiki.runFilters";
0128:
0129: /** repository template location (nb: main wiki is already initialised by page provider) */
0130: public static final String PROP_PAGETEMPLATESCONFIGDIR = "jspwiki.pageTemplatesConfigDir";
0131:
0132: /** Path to the default property file.
0133: * @value /WEB_INF/jspwiki.properties
0134: */
0135: public static final String DEFAULT_PROPERTYFILE = "/WEB-INF/jspwiki.properties";
0136:
0137: /**
0138: * Contains the default properties for JSPWiki.
0139: */
0140: private static final String[] DEFAULT_PROPERTIES = {
0141: "jspwiki.specialPage.Login", "Login.jsp",
0142: "jspwiki.specialPage.UserPreferences",
0143: "UserPreferences.jsp", "jspwiki.specialPage.Search",
0144: "Search.jsp", "jspwiki.specialPage.FindPage",
0145: "FindPage.jsp" };
0146:
0147: /** Stores an internal list of engines per each ServletContext */
0148: private static Hashtable c_engines = new Hashtable();
0149:
0150: /** Should the user info be saved with the page data as well? */
0151: private boolean m_saveUserInfo = true;
0152:
0153: /** If true, uses UTF8 encoding for all data */
0154: private boolean m_useUTF8 = true;
0155:
0156: /** If true, we'll also consider english plurals (+s) a match. */
0157: private boolean m_matchEnglishPlurals = true;
0158:
0159: /** Stores the base URL. */
0160: private String m_baseURL;
0161:
0162: /** Store the file path to the basic URL. When we're not running as
0163: a servlet, it defaults to the user's current directory. */
0164: private String m_rootPath = System.getProperty("user.dir");
0165:
0166: /** Stores references between wikipages. */
0167: private ReferenceManager m_referenceManager = null;
0168:
0169: /** Stores the Plugin manager */
0170: private PluginManager m_pluginManager;
0171:
0172: /** Stores the Variable manager */
0173: private VariableManager m_variableManager;
0174:
0175: /** Stores the Attachment manager */
0176: private AttachmentManager m_attachmentManager = null;
0177:
0178: /** Stores the Page manager */
0179: private PageManager m_pageManager = null;
0180:
0181: /** Stores the authorization manager */
0182: private AuthorizationManager m_authorizationManager = null;
0183:
0184: /** Stores the user manager.*/
0185: private UserManager m_userManager = null;
0186:
0187: private TemplateManager m_templateManager = null;
0188:
0189: /** Does all our diffs for us. */
0190: private DifferenceManager m_differenceManager;
0191:
0192: /** Handlers page filters. */
0193: private FilterManager m_filterManager;
0194:
0195: /** Stores the Search manager */
0196: private SearchManager m_searchManager = null;
0197:
0198: /** Constructs URLs */
0199: private URLConstructor m_urlConstructor;
0200:
0201: /** Generates RSS feed when requested. */
0202: private RSSGenerator m_rssGenerator;
0203:
0204: /** Stores the relative URL to the global RSS feed. */
0205: private String m_rssURL;
0206:
0207: /** Store the ServletContext that we're in. This may be null if WikiEngine
0208: is not running inside a servlet container (i.e. when testing). */
0209: private ServletContext m_servletContext = null;
0210:
0211: /** If true, all titles will be cleaned. */
0212: private boolean m_beautifyTitle = false;
0213:
0214: /** Stores the template path. This is relative to "templates". */
0215: private String m_templateDir;
0216:
0217: /** The default front page name. Defaults to "Main". */
0218: private String m_frontPage;
0219:
0220: /** The time when this engine was started. */
0221: private Date m_startTime;
0222:
0223: /** The location where the work directory is. */
0224: private String m_workDir;
0225:
0226: /** Each engine has their own application id. */
0227: private String m_appid = "";
0228:
0229: private boolean m_isConfigured = false; // Flag.
0230:
0231: /** Location of the initial page repository template for subwikis (main/default wiki is handled by the page provider itself) */
0232: private String m_pageTemplatesConfigDir;
0233:
0234: private ThreadLocal m_communityContextTL = new ThreadLocal();
0235:
0236: /**
0237: * Gets a WikiEngine related to this servlet. Since this method
0238: * is only called from JSP pages (and JspInit()) to be specific,
0239: * we throw a RuntimeException if things don't work.
0240: *
0241: * @param config The ServletConfig object for this servlet.
0242: *
0243: * @return A WikiEngine instance.
0244: * @throws InternalWikiException in case something fails. This
0245: * is a RuntimeException, so be prepared for it.
0246: */
0247:
0248: // FIXME: It seems that this does not work too well, jspInit()
0249: // does not react to RuntimeExceptions, or something...
0250: public static synchronized WikiEngine getInstance(
0251: ServletConfig config) throws InternalWikiException {
0252: return (getInstance(config.getServletContext(), null));
0253: }
0254:
0255: /**
0256: * Gets a WikiEngine related to the servlet. Works like getInstance(ServletConfig),
0257: * but does not force the Properties object. This method is just an optional way
0258: * of initializing a WikiEngine for embedded JSPWiki applications; normally, you
0259: * should use getInstance(ServletConfig).
0260: *
0261: * @param config The ServletConfig of the webapp servlet/JSP calling this method.
0262: * @param props A set of properties, or null, if we are to load JSPWiki's default
0263: * jspwiki.properties (this is the usual case).
0264: */
0265: public static synchronized WikiEngine getInstance(
0266: ServletConfig config, Properties props) {
0267: return (getInstance(config.getServletContext(), null));
0268: }
0269:
0270: /**
0271: * Gets a WikiEngine related to the servlet. Works just like getInstance( ServletConfig )
0272: *
0273: * @param config The ServletContext of the webapp servlet/JSP calling this method.
0274: * @param props A set of properties, or null, if we are to load JSPWiki's default
0275: * jspwiki.properties (this is the usual case).
0276: */
0277:
0278: // FIXME: Potential make-things-easier thingy here: no need to fetch the wikiengine anymore
0279: // Wiki.jsp.jspInit() [really old code]; it's probably even faster to fetch it
0280: // using this method every time than go to pageContext.getAttribute().
0281: public static synchronized WikiEngine getInstance(
0282: ServletContext context, Properties props)
0283: throws InternalWikiException {
0284: String appid = Integer.toString(context.hashCode()); //FIXME: Kludge, use real type.
0285:
0286: context.log("Application " + appid + " requests WikiEngine.");
0287:
0288: WikiEngine engine = (WikiEngine) c_engines.get(appid);
0289:
0290: if (engine == null) {
0291: context.log(" Assigning new log to " + appid);
0292: try {
0293: if (props == null)
0294: props = loadWebAppProps(context);
0295: engine = new WikiEngine(context, appid, props);
0296: } catch (Exception e) {
0297: context.log("ERROR: Failed to create a Wiki engine: "
0298: + e.getMessage());
0299: throw new InternalWikiException(
0300: "No wiki engine, check logs.");
0301: }
0302:
0303: c_engines.put(appid, engine);
0304: }
0305:
0306: return engine;
0307: }
0308:
0309: /**
0310: * Instantiate the WikiEngine using a given set of properties.
0311: * Use this constructor for testing purposes only.
0312: */
0313: public WikiEngine(Properties properties) throws WikiException {
0314: initialize(properties);
0315: }
0316:
0317: /**
0318: * Loads the webapp properties based on servlet context information.
0319: * Returns a Properties object containing the settings, or null if unable
0320: * to load it. (The default file is WEB-INF/jspwiki.properties, and can
0321: * be overridden by setting PARAM_PROPERTYFILE in the server or webapp
0322: * configuration.)
0323: */
0324: private static Properties loadWebAppProps(ServletContext context) {
0325: String propertyFile = context
0326: .getInitParameter(PARAM_PROPERTYFILE);
0327: InputStream propertyStream = null;
0328:
0329: try {
0330: //
0331: // Figure out where our properties lie.
0332: //
0333: if (propertyFile == null) {
0334: context
0335: .log("No "
0336: + PARAM_PROPERTYFILE
0337: + " defined for this context, using default from "
0338: + DEFAULT_PROPERTYFILE);
0339: // Use the default property file.
0340: propertyStream = context
0341: .getResourceAsStream(DEFAULT_PROPERTYFILE);
0342: } else {
0343: context.log("Reading properties from " + propertyFile
0344: + " instead of default.");
0345: propertyStream = new FileInputStream(new File(
0346: propertyFile));
0347: }
0348:
0349: if (propertyStream == null) {
0350: throw new WikiException(
0351: "Property file cannot be found!" + propertyFile);
0352: }
0353:
0354: Properties props = new Properties(TextUtil
0355: .createProperties(DEFAULT_PROPERTIES));
0356: // XXX his is a no-op?? should remove...
0357: if (WikiPortletContext.isActive())
0358: props.putAll(WikiPortletContext.getProperties());
0359: props.load(propertyStream);
0360: return (props);
0361: } catch (Exception e) {
0362: context
0363: .log(Release.APPNAME
0364: + ": Unable to load and setup properties from jspwiki.properties. "
0365: + e.getMessage());
0366: } finally {
0367: try {
0368: propertyStream.close();
0369: } catch (IOException e) {
0370: context
0371: .log("Unable to close property stream - something must be seriously wrong.");
0372: }
0373: }
0374:
0375: return (null);
0376: }
0377:
0378: /**
0379: * Instantiate using this method when you're running as a servlet and
0380: * WikiEngine will figure out where to look for the property
0381: * file.
0382: * Do not use this method - use WikiEngine.getInstance() instead.
0383: */
0384: protected WikiEngine(ServletContext context, String appid,
0385: Properties props) throws WikiException {
0386: InputStream propertyStream = null;
0387: String propertyFile = context
0388: .getInitParameter(PARAM_PROPERTYFILE);
0389:
0390: m_servletContext = context;
0391: m_appid = appid;
0392:
0393: try {
0394: //
0395: // Note: May be null, if JSPWiki has been deployed in a WAR file.
0396: //
0397: m_rootPath = context.getRealPath("/");
0398: initialize(props);
0399: log
0400: .info("Root path for this Wiki is: '" + m_rootPath
0401: + "'");
0402: } catch (Exception e) {
0403: context
0404: .log(Release.APPNAME
0405: + ": Unable to load and setup properties from jspwiki.properties. "
0406: + e.getMessage());
0407: }
0408: }
0409:
0410: /**
0411: * Does all the real initialization.
0412: */
0413: private void initialize(Properties props) throws WikiException {
0414: m_startTime = new Date();
0415: m_properties = props;
0416:
0417: //
0418: // Initialized log4j. However, make sure that
0419: // we don't initialize it multiple times. Also, if
0420: // all of the log4j statements have been removed from
0421: // the property file, we do not do any property setting
0422: // either.q
0423: //
0424: if (!c_configured) {
0425: if (props.getProperty("log4j.rootCategory") != null) {
0426: PropertyConfigurator.configure(props);
0427: }
0428: c_configured = true;
0429: }
0430:
0431: log.info("*******************************************");
0432: log.info("JSPWiki " + Release.VERSTR + " starting. Whee!");
0433:
0434: log.debug("Configuring WikiEngine...");
0435:
0436: //
0437: // Create and find the default working directory.
0438: //
0439: m_workDir = props.getProperty(PROP_WORKDIR);
0440:
0441: if (m_workDir == null) {
0442: m_workDir = System.getProperty("java.io.tmpdir", ".");
0443: m_workDir += File.separator + Release.APPNAME + "-"
0444: + m_appid;
0445: }
0446:
0447: try {
0448: File f = new File(m_workDir);
0449: f.mkdirs();
0450:
0451: //
0452: // A bunch of sanity checks
0453: //
0454: if (!f.exists())
0455: throw new WikiException(
0456: "Work directory does not exist: " + m_workDir);
0457: if (!f.canRead())
0458: throw new WikiException(
0459: "No permission to read work directory: "
0460: + m_workDir);
0461: if (!f.canWrite())
0462: throw new WikiException(
0463: "No permission to write to work directory: "
0464: + m_workDir);
0465: if (!f.isDirectory())
0466: throw new WikiException(
0467: "jspwiki.workDir does not point to a directory: "
0468: + m_workDir);
0469: } catch (SecurityException e) {
0470: log.fatal(
0471: "Unable to find or create the working directory: "
0472: + m_workDir, e);
0473: throw new IllegalArgumentException(
0474: "Unable to find or create the working dir: "
0475: + m_workDir);
0476: }
0477:
0478: log.info("JSPWiki working directory is '" + m_workDir + "'");
0479:
0480: m_saveUserInfo = TextUtil.getBooleanProperty(props,
0481: PROP_STOREUSERNAME, m_saveUserInfo);
0482:
0483: m_useUTF8 = "UTF-8".equals(props.getProperty(PROP_ENCODING,
0484: "ISO-8859-1"));
0485: m_baseURL = props.getProperty(PROP_BASEURL, "");
0486:
0487: m_beautifyTitle = TextUtil.getBooleanProperty(props,
0488: PROP_BEAUTIFYTITLE, m_beautifyTitle);
0489:
0490: m_matchEnglishPlurals = TextUtil.getBooleanProperty(props,
0491: PROP_MATCHPLURALS, m_matchEnglishPlurals);
0492:
0493: m_templateDir = props.getProperty(PROP_TEMPLATEDIR, "default");
0494: m_frontPage = props.getProperty(PROP_FRONTPAGE, "Main");
0495:
0496: m_pageTemplatesConfigDir = props
0497: .getProperty(PROP_PAGETEMPLATESCONFIGDIR);
0498:
0499: //
0500: // Initialize the important modules. Any exception thrown by the
0501: // managers means that we will not start up.
0502: //
0503: try {
0504: Class urlclass = ClassUtil.findClass(
0505: "com.ecyrd.jspwiki.url", props.getProperty(
0506: PROP_URLCONSTRUCTOR,
0507: "DefaultURLConstructor"));
0508: m_urlConstructor = (URLConstructor) urlclass.newInstance();
0509: m_urlConstructor.initialize(this , props);
0510:
0511: m_pageManager = new PageManager(this , props);
0512: m_pluginManager = new PluginManager(props);
0513: m_differenceManager = new DifferenceManager(this , props);
0514: m_attachmentManager = new AttachmentManager(this , props);
0515: m_variableManager = new VariableManager(props);
0516: m_filterManager = new FilterManager(this , props);
0517:
0518: //
0519: // ReferenceManager has the side effect of loading all
0520: // pages. Therefore after this point, all page attributes
0521: // are available.
0522: //
0523: initReferenceManager();
0524:
0525: m_templateManager = new TemplateManager(this , props);
0526: m_userManager = new UserManager(this , props);
0527: m_authorizationManager = new AuthorizationManager(this ,
0528: props);
0529:
0530: // needs user manager to be set up first
0531: m_searchManager = new SearchManager(this , props);
0532:
0533: } catch (Exception e) {
0534: // RuntimeExceptions may occur here, even if they shouldn't.
0535: log.fatal("Failed to start managers.", e);
0536: throw new WikiException("Failed to start managers: "
0537: + e.getMessage());
0538: }
0539:
0540: //
0541: // Initialize the good-to-have-but-not-fatal modules.
0542: //
0543: try {
0544: if (TextUtil.getBooleanProperty(props,
0545: RSSGenerator.PROP_GENERATE_RSS, false)) {
0546: m_rssGenerator = new RSSGenerator(this , props);
0547: }
0548: } catch (Exception e) {
0549: log.error(
0550: "Unable to start RSS generator - JSPWiki will still work, "
0551: + "but there will be no RSS feed.", e);
0552: }
0553:
0554: // FIXME: I wonder if this should be somewhere else.
0555: if (m_rssGenerator != null) {
0556: new RSSThread().start();
0557: }
0558:
0559: log.info("WikiEngine configured.");
0560: m_isConfigured = true;
0561: }
0562:
0563: /**
0564: * Initializes the reference manager. Scans all existing WikiPages for
0565: * internal links and adds them to the ReferenceManager object.
0566: */
0567: private void initReferenceManager() {
0568: m_pluginManager.setInitStage(true);
0569:
0570: try {
0571: ArrayList pages = new ArrayList();
0572: pages.addAll(m_pageManager.getAllPages());
0573: pages.addAll(m_attachmentManager.getAllAttachments());
0574:
0575: // Build a new manager with default key lists.
0576: if (m_referenceManager == null) {
0577: m_referenceManager = new ReferenceManager(this );
0578: m_referenceManager.initialize(pages);
0579: }
0580:
0581: } catch (ProviderException e) {
0582: log.fatal("PageProvider is unable to list pages: ", e);
0583: }
0584:
0585: m_pluginManager.setInitStage(false);
0586:
0587: m_filterManager.addPageFilter(m_referenceManager, -1000); // FIXME: Magic number.
0588: }
0589:
0590: /**
0591: * Throws an exception if a property is not found.
0592: *
0593: * @param props A set of properties to search the key in.
0594: * @param key The key to look for.
0595: * @return The required property
0596: *
0597: * @throws NoRequiredPropertyException If the search key is not
0598: * in the property set.
0599: */
0600:
0601: // FIXME: Should really be in some util file.
0602: public static String getRequiredProperty(Properties props,
0603: String key) throws NoRequiredPropertyException {
0604: String value = props.getProperty(key);
0605:
0606: if (value == null) {
0607: throw new NoRequiredPropertyException(
0608: "Required property not found", key);
0609: }
0610:
0611: return value;
0612: }
0613:
0614: /**
0615: * Internal method for getting a property. This is used by the
0616: * TranslatorReader for example.
0617: */
0618:
0619: public Properties getWikiProperties() {
0620: return m_properties;
0621: }
0622:
0623: /**
0624: * Returns the JSPWiki working directory.
0625: * @since 2.1.100
0626: */
0627: public String getWorkDir() {
0628: return m_workDir;
0629: }
0630:
0631: /**
0632: * Don't use.
0633: * @since 1.8.0
0634: */
0635: public String getPluginSearchPath() {
0636: // FIXME: This method should not be here, probably.
0637: return m_properties.getProperty(PluginManager.PROP_SEARCHPATH);
0638: }
0639:
0640: /**
0641: * Returns the current template directory.
0642: *
0643: * @since 1.9.20
0644: */
0645: public String getTemplateDir() {
0646: return m_templateDir;
0647: }
0648:
0649: public TemplateManager getTemplateManager() {
0650: return m_templateManager;
0651: }
0652:
0653: /**
0654: * Returns the base URL. Always prepend this to any reference
0655: * you make.
0656: *
0657: * @since 1.6.1
0658: */
0659:
0660: public String getBaseURL() {
0661: return m_baseURL;
0662: }
0663:
0664: /**
0665: * Returns the moment when this engine was started.
0666: *
0667: * @since 2.0.15.
0668: */
0669:
0670: public Date getStartTime() {
0671: return m_startTime;
0672: }
0673:
0674: /**
0675: * Returns the basic URL to a page, without any modifications.
0676: * You may add any parameters to this.
0677: * @deprecated
0678: *
0679: * @since 2.0.3
0680: */
0681: public String getViewURL(String pageName) {
0682: return m_urlConstructor.makeURL(WikiContext.VIEW, pageName,
0683: false, null);
0684: }
0685:
0686: /**
0687: * Returns the basic URL to an editor.
0688: * @deprecated
0689: *
0690: * @since 2.0.3
0691: */
0692: public String getEditURL(String pageName) {
0693: return m_urlConstructor.makeURL(WikiContext.EDIT, pageName,
0694: false, null);
0695: }
0696:
0697: /**
0698: * Returns the basic attachment URL.
0699: * @since 2.0.42.
0700: * @deprecated
0701: */
0702: public String getAttachmentURL(String attName) {
0703: return m_urlConstructor.makeURL(WikiContext.ATTACH, attName,
0704: false, null);
0705: }
0706:
0707: /**
0708: * Returns an URL if a WikiContext is not available.
0709: * @param context The WikiContext (VIEW, EDIT, etc...)
0710: * @param pageName Name of the page, as usual
0711: * @param params List of parameters. May be null, if no parameters.
0712: * @param absolute If true, will generate an absolute URL regardless of properties setting.
0713: */
0714: public String getURL(String context, String pageName,
0715: String params, boolean absolute) {
0716: return m_urlConstructor.makeURL(context, pageName, absolute,
0717: params);
0718: }
0719:
0720: /**
0721: * Returns the default front page, if no page is used.
0722: */
0723:
0724: public String getFrontPage() {
0725: return m_frontPage;
0726: }
0727:
0728: /**
0729: * Returns the ServletContext that this particular WikiEngine was
0730: * initialized with. <B>It may return null</B>, if the WikiEngine is not
0731: * running inside a servlet container!
0732: *
0733: * @since 1.7.10
0734: * @return ServletContext of the WikiEngine, or null.
0735: */
0736:
0737: public ServletContext getServletContext() {
0738: return m_servletContext;
0739: }
0740:
0741: /**
0742: * This is a safe version of the Servlet.Request.getParameter() routine.
0743: * Unfortunately, the default version always assumes that the incoming
0744: * character set is ISO-8859-1, even though it was something else.
0745: * This means that we need to make a new string using the correct
0746: * encoding.
0747: * <P>
0748: * For more information, see:
0749: * <A HREF="http://www.jguru.com/faq/view.jsp?EID=137049">JGuru FAQ</A>.
0750: * <P>
0751: * Incidentally, this is almost the same as encodeName(), below.
0752: * I am not yet entirely sure if it's safe to merge the code.
0753: *
0754: * @since 1.5.3
0755: */
0756:
0757: public String safeGetParameter(ServletRequest request, String name) {
0758: try {
0759: String res = request.getParameter(name);
0760: if (res != null && !WikiPortletContext.isActive()) {
0761: // portletrequest.getCharacterEncoding() is returning null, but it is
0762: // in fact UTF-8 - so only assume ISO-8859-1 if there is no portlet context
0763: if (!WikiPortletContext.isActive())
0764: res = new String(res.getBytes("ISO-8859-1"),
0765: getContentEncoding());
0766: }
0767:
0768: return res;
0769: } catch (UnsupportedEncodingException e) {
0770: log.fatal("Unsupported encoding", e);
0771: return "";
0772: }
0773:
0774: }
0775:
0776: /**
0777: * Returns the query string (the portion after the question mark).
0778: *
0779: * @return The query string. If the query string is null,
0780: * returns an empty string.
0781: *
0782: * @since 2.1.3
0783: */
0784: public String safeGetQueryString(HttpServletRequest request) {
0785: if (request == null) {
0786: return "";
0787: }
0788:
0789: try {
0790: String res = request.getQueryString();
0791: if (res != null) {
0792: res = new String(res.getBytes("ISO-8859-1"),
0793: getContentEncoding());
0794:
0795: //
0796: // Ensure that the 'page=xyz' attribute is removed
0797: // FIXME: Is it really the mandate of this routine to
0798: // do that?
0799: //
0800: int pos1 = res.indexOf("page=");
0801: if (pos1 >= 0) {
0802: String tmpRes = res.substring(0, pos1);
0803: int pos2 = res.indexOf("&", pos1) + 1;
0804: if ((pos2 > 0) && (pos2 < res.length())) {
0805: tmpRes = tmpRes + res.substring(pos2);
0806: }
0807: res = tmpRes;
0808: }
0809: }
0810:
0811: return res;
0812: } catch (UnsupportedEncodingException e) {
0813: log.fatal("Unsupported encoding", e);
0814: return "";
0815: }
0816: }
0817:
0818: /**
0819: * Returns an URL to some other Wiki that we know.
0820: *
0821: * @return null, if no such reference was found.
0822: */
0823: public String getInterWikiURL(String wikiName) {
0824: return m_properties.getProperty(PROP_INTERWIKIREF + wikiName);
0825: }
0826:
0827: /**
0828: * Returns a collection of all supported InterWiki links.
0829: */
0830: public Collection getAllInterWikiLinks() {
0831: Vector v = new Vector();
0832:
0833: for (Enumeration i = m_properties.propertyNames(); i
0834: .hasMoreElements();) {
0835: String prop = (String) i.nextElement();
0836:
0837: if (prop.startsWith(PROP_INTERWIKIREF)) {
0838: v.add(prop.substring(prop.lastIndexOf(".") + 1));
0839: }
0840: }
0841:
0842: return v;
0843: }
0844:
0845: /**
0846: * Returns a collection of all image types that get inlined.
0847: */
0848:
0849: public Collection getAllInlinedImagePatterns() {
0850: return TranslatorReader.getImagePatterns(this );
0851: }
0852:
0853: /**
0854: * If the page is a special page, then returns a direct URL
0855: * to that page. Otherwise returns null.
0856: * <P>
0857: * Special pages are non-existant references to other pages.
0858: * For example, you could define a special page reference
0859: * "RecentChanges" which would always be redirected to "RecentChanges.jsp"
0860: * instead of trying to find a Wiki page called "RecentChanges".
0861: */
0862: public String getSpecialPageReference(String original) {
0863: original = getRelativePageName(original);
0864: String propname = PROP_SPECIALPAGE + original;
0865: String specialpage = m_properties.getProperty(propname);
0866:
0867: if (specialpage != null)
0868: specialpage = getURL(WikiContext.NONE, specialpage, null,
0869: true);
0870:
0871: return specialpage;
0872: }
0873:
0874: /**
0875: * Returns the name of the application.
0876: */
0877:
0878: // FIXME: Should use servlet context as a default instead of a constant.
0879: public String getApplicationName() {
0880: String appName = m_properties.getProperty(PROP_APPNAME);
0881:
0882: if (appName == null)
0883: return Release.APPNAME;
0884:
0885: return appName;
0886: }
0887:
0888: /**
0889: * Beautifies the title of the page by appending spaces in suitable
0890: * places, if the user has so decreed in the properties when constructing
0891: * this WikiEngine. However, attachment names are not beautified, no
0892: * matter what.
0893: *
0894: * @since 1.7.11
0895: */
0896: public String beautifyTitle(String title) {
0897: if (m_beautifyTitle) {
0898: try {
0899: if (m_attachmentManager.getAttachmentInfo(title) == null) {
0900: return TextUtil.beautifyString(title);
0901: }
0902: } catch (ProviderException e) {
0903: return title;
0904: }
0905: }
0906:
0907: return title;
0908: }
0909:
0910: /**
0911: * Beautifies the title of the page by appending non-breaking spaces
0912: * in suitable places. This is really suitable only for HTML output,
0913: * as it uses the &nbsp; -character.
0914: *
0915: * @since 2.1.127
0916: */
0917: public String beautifyTitleNoBreak(String title) {
0918: if (m_beautifyTitle) {
0919: return TextUtil.beautifyString(title, " ");
0920: }
0921:
0922: return title;
0923: }
0924:
0925: /**
0926: * Returns true, if the requested page (or an alias) exists. Will consider
0927: * any version as existing. Will also consider attachments.
0928: *
0929: * @param page WikiName of the page.
0930: */
0931: public boolean pageExists(String page) {
0932:
0933: Attachment att = null;
0934:
0935: try {
0936: if (getSpecialPageReference(page) != null)
0937: return true;
0938:
0939: if (getFinalPageName(page) != null) {
0940: return true;
0941: }
0942:
0943: att = getAttachmentManager().getAttachmentInfo(
0944: (WikiContext) null, page);
0945: } catch (ProviderException e) {
0946: log.debug("pageExists() failed to find attachments", e);
0947: }
0948:
0949: return att != null;
0950: }
0951:
0952: /**
0953: * Returns true, if the requested page (or an alias) exists with the
0954: * requested version.
0955: *
0956: * @param page Page name
0957: */
0958: public boolean pageExists(String page, int version)
0959: throws ProviderException {
0960: if (getSpecialPageReference(page) != null)
0961: return true;
0962:
0963: String finalName = getFinalPageName(page);
0964: WikiPage p = null;
0965:
0966: if (finalName != null) {
0967: //
0968: // Go and check if this particular version of this page
0969: // exists.
0970: //
0971: p = m_pageManager.getPageInfo(finalName, version);
0972: }
0973:
0974: if (p == null) {
0975: try {
0976: p = getAttachmentManager().getAttachmentInfo(
0977: (WikiContext) null, page, version);
0978: } catch (ProviderException e) {
0979: log.debug("pageExists() failed to find attachments", e);
0980: }
0981: }
0982:
0983: return (p != null);
0984: }
0985:
0986: /**
0987: * Returns true, if the requested page (or an alias) exists, with the
0988: * specified version in the WikiPage.
0989: *
0990: * @since 2.0
0991: */
0992: public boolean pageExists(WikiPage page) throws ProviderException {
0993: if (page != null) {
0994: return pageExists(page.getName(), page.getVersion());
0995: }
0996: return false;
0997: }
0998:
0999: /**
1000: * Returns the correct page name, or null, if no such
1001: * page can be found. Aliases are considered.
1002: * <P>
1003: * In some cases, page names can refer to other pages. For example,
1004: * when you have matchEnglishPlurals set, then a page name "Foobars"
1005: * will be transformed into "Foobar", should a page "Foobars" not exist,
1006: * but the page "Foobar" would. This method gives you the correct
1007: * page name to refer to.
1008: * <P>
1009: * This facility can also be used to rewrite any page name, for example,
1010: * by using aliases. It can also be used to check the existence of any
1011: * page.
1012: *
1013: * @since 2.0
1014: * @param page Page name.
1015: * @return The rewritten page name, or null, if the page does not exist.
1016: */
1017:
1018: public String getFinalPageName(String page)
1019: throws ProviderException {
1020: page = makeAbsolutePageName(page);
1021: boolean isThere = simplePageExists(page);
1022:
1023: if (!isThere && m_matchEnglishPlurals) {
1024: if (page.endsWith("s")) {
1025: page = page.substring(0, page.length() - 1);
1026: } else {
1027: page += "s";
1028: }
1029:
1030: isThere = simplePageExists(page);
1031: }
1032:
1033: return isThere ? page : null;
1034: }
1035:
1036: /**
1037: * Just queries the existing pages directly from the page manager.
1038: * We also check overridden pages from jspwiki.properties
1039: */
1040: private boolean simplePageExists(String page)
1041: throws ProviderException {
1042: if (getSpecialPageReference(page) != null)
1043: return true;
1044:
1045: return m_pageManager.pageExists(makeProviderPageName(page));
1046: }
1047:
1048: /**
1049: * Turns a WikiName into something that can be
1050: * called through using an URL.
1051: *
1052: * @since 1.4.1
1053: */
1054: public String encodeName(String pagename) {
1055: return TextUtil.urlEncode(pagename, (m_useUTF8 ? "UTF-8"
1056: : "ISO-8859-1"));
1057: }
1058:
1059: public String decodeName(String pagerequest) {
1060: try {
1061: return TextUtil.urlDecode(pagerequest, (m_useUTF8 ? "UTF-8"
1062: : "ISO-8859-1"));
1063: } catch (UnsupportedEncodingException e) {
1064: throw new InternalWikiException(
1065: "ISO-8859-1 not a supported encoding!?! Your platform is borked.");
1066: }
1067: }
1068:
1069: /**
1070: * Returns the IANA name of the character set encoding we're
1071: * supposed to be using right now.
1072: *
1073: * @since 1.5.3
1074: */
1075: public String getContentEncoding() {
1076: if (m_useUTF8)
1077: return "UTF-8";
1078:
1079: return "ISO-8859-1";
1080: }
1081:
1082: /**
1083: * Returns the un-HTMLized text of the latest version of a page.
1084: * This method also replaces the < and & -characters with
1085: * their respective HTML entities, thus making it suitable
1086: * for inclusion on an HTML page. If you want to have the
1087: * page text without any conversions, use getPureText().
1088: *
1089: * @param page WikiName of the page to fetch.
1090: * @return WikiText.
1091: */
1092: public String getText(String page) {
1093: return getText(page, WikiPageProvider.LATEST_VERSION);
1094: }
1095:
1096: /**
1097: * Returns the un-HTMLized text of the given version of a page.
1098: * This method also replaces the < and & -characters with
1099: * their respective HTML entities, thus making it suitable
1100: * for inclusion on an HTML page. If you want to have the
1101: * page text without any conversions, use getPureText().
1102: *
1103: *
1104: * @param page WikiName of the page to fetch
1105: * @param version Version of the page to fetch
1106: * @return WikiText.
1107: */
1108: public String getText(String page, int version) {
1109: String result = getPureText(page, version);
1110:
1111: //
1112: // Replace ampersand first, or else all quotes and stuff
1113: // get replaced as well with " etc.
1114: //
1115: /*
1116: result = TextUtil.replaceString( result, "&", "&" );
1117: */
1118:
1119: result = TextUtil.replaceEntities(result);
1120:
1121: return result;
1122: }
1123:
1124: /**
1125: * Returns the un-HTMLized text of the given version of a page in
1126: * the given context. USE THIS METHOD if you don't know what
1127: * doing.
1128: * <p>
1129: * This method also replaces the < and & -characters with
1130: * their respective HTML entities, thus making it suitable
1131: * for inclusion on an HTML page. If you want to have the
1132: * page text without any conversions, use getPureText().
1133: *
1134: * @since 1.9.15.
1135: */
1136: public String getText(WikiContext context, WikiPage page) {
1137: return getText(page.getName(), page.getVersion());
1138: }
1139:
1140: /**
1141: * Returns the pure text of a page, no conversions. Use this
1142: * if you are writing something that depends on the parsing
1143: * of the page. Note that you should always check for page
1144: * existence through pageExists() before attempting to fetch
1145: * the page contents.
1146: *
1147: * @param page The name of the page to fetch.
1148: * @param version If WikiPageProvider.LATEST_VERSION, then uses the
1149: * latest version.
1150: * @return The page contents. If the page does not exist,
1151: * returns an empty string.
1152: */
1153: // FIXME: Should throw an exception on unknown page/version?
1154: public String getPureText(String page, int version) {
1155: String result = null;
1156:
1157: try {
1158: result = m_pageManager.getPageText(page, version);
1159: } catch (ProviderException e) {
1160: // FIXME
1161: } finally {
1162: if (result == null)
1163: result = "";
1164: }
1165:
1166: return result;
1167: }
1168:
1169: /**
1170: * Returns the pure text of a page, no conversions. Use this
1171: * if you are writing something that depends on the parsing
1172: * the page. Note that you should always check for page
1173: * existence through pageExists() before attempting to fetch
1174: * the page contents.
1175: *
1176: * @param page A handle to the WikiPage
1177: * @return String of WikiText.
1178: * @since 2.1.13.
1179: */
1180: public String getPureText(WikiPage page) {
1181: return getPureText(page.getName(), page.getVersion());
1182: }
1183:
1184: /**
1185: * Returns the converted HTML of the page using a different
1186: * context than the default context.
1187: */
1188:
1189: public String getHTML(WikiContext context, WikiPage page) {
1190: String pagedata = null;
1191:
1192: pagedata = getPureText(page.getName(), page.getVersion());
1193:
1194: String res = textToHTML(context, pagedata);
1195:
1196: return res;
1197: }
1198:
1199: /**
1200: * Returns the converted HTML of the page.
1201: *
1202: * @param page WikiName of the page to convert.
1203: */
1204: public String getHTML(String page) {
1205: return getHTML(page, WikiPageProvider.LATEST_VERSION);
1206: }
1207:
1208: /**
1209: * Returns the converted HTML of the page's specific version.
1210: * The version must be a positive integer, otherwise the current
1211: * version is returned.
1212: *
1213: * @param pagename WikiName of the page to convert.
1214: * @param version Version number to fetch
1215: */
1216: public String getHTML(String pagename, int version) {
1217: WikiPage page = getPage(pagename, version);
1218:
1219: WikiContext context = new WikiContext(this , page);
1220: context.setRequestContext(WikiContext.NONE);
1221:
1222: String res = getHTML(context, page);
1223:
1224: return res;
1225: }
1226:
1227: /**
1228: * Converts raw page data to HTML.
1229: *
1230: * @param pagedata Raw page data to convert to HTML
1231: */
1232: public String textToHTML(WikiContext context, String pagedata) {
1233: return textToHTML(context, pagedata, null, null);
1234: }
1235:
1236: /**
1237: * Reads a WikiPageful of data from a String and returns all links
1238: * internal to this Wiki in a Collection.
1239: */
1240: protected Collection scanWikiLinks(WikiPage page, String pagedata) {
1241: LinkCollector localCollector = new LinkCollector();
1242:
1243: textToHTML(new WikiContext(this , page), pagedata,
1244: localCollector, null, localCollector, false);
1245:
1246: return localCollector.getLinks();
1247: }
1248:
1249: /**
1250: * Just convert WikiText to HTML.
1251: */
1252:
1253: public String textToHTML(WikiContext context, String pagedata,
1254: StringTransmutator localLinkHook,
1255: StringTransmutator extLinkHook) {
1256: return textToHTML(context, pagedata, localLinkHook,
1257: extLinkHook, null, true);
1258: }
1259:
1260: /**
1261: * Just convert WikiText to HTML.
1262: */
1263:
1264: public String textToHTML(WikiContext context, String pagedata,
1265: StringTransmutator localLinkHook,
1266: StringTransmutator extLinkHook,
1267: StringTransmutator attLinkHook) {
1268: return textToHTML(context, pagedata, localLinkHook,
1269: extLinkHook, attLinkHook, true);
1270: }
1271:
1272: /**
1273: * Helper method for doing the HTML translation.
1274: */
1275: private String textToHTML(WikiContext context, String pagedata,
1276: StringTransmutator localLinkHook,
1277: StringTransmutator extLinkHook,
1278: StringTransmutator attLinkHook, boolean parseAccessRules) {
1279: String result = "";
1280:
1281: if (pagedata == null) {
1282: log.error("NULL pagedata to textToHTML()");
1283: return null;
1284: }
1285:
1286: TranslatorReader in = null;
1287: Collection links = null;
1288:
1289: boolean runFilters = "true".equals(m_variableManager.getValue(
1290: context, PROP_RUNFILTERS, "true"));
1291:
1292: try {
1293: if (runFilters)
1294: pagedata = m_filterManager.doPreTranslateFiltering(
1295: context, pagedata);
1296:
1297: in = new TranslatorReader(context, new StringReader(
1298: pagedata));
1299:
1300: in.addLocalLinkHook(localLinkHook);
1301: in.addExternalLinkHook(extLinkHook);
1302: in.addAttachmentLinkHook(attLinkHook);
1303:
1304: if (!parseAccessRules)
1305: in.disableAccessRules();
1306: result = FileUtil.readContents(in);
1307:
1308: if (runFilters)
1309: result = m_filterManager.doPostTranslateFiltering(
1310: context, result);
1311: } catch (IOException e) {
1312: log.error("Failed to scan page data: ", e);
1313: } catch (FilterException e) {
1314: // FIXME: Don't yet know what to do
1315: } finally {
1316: try {
1317: if (in != null)
1318: in.close();
1319: } catch (Exception e) {
1320: log.fatal("Closing failed", e);
1321: }
1322: }
1323:
1324: return (result);
1325: }
1326:
1327: /**
1328: * Updates all references for the given page.
1329: */
1330:
1331: public void updateReferences(WikiPage page) {
1332: String pageData = getPureText(page.getName(),
1333: WikiProvider.LATEST_VERSION);
1334:
1335: m_referenceManager.updateReferences(page.getName(),
1336: scanWikiLinks(page, pageData));
1337: }
1338:
1339: /**
1340: * Writes the WikiText of a page into the
1341: * page repository.
1342: *
1343: * @since 2.1.28
1344: * @param context The current WikiContext
1345: * @param text The Wiki markup for the page.
1346: */
1347: public void saveText(WikiContext context, String text)
1348: throws WikiException {
1349: WikiPage page = context.getPage();
1350:
1351: if (page.getAuthor() == null) {
1352: UserProfile wup = context.getCurrentUser();
1353:
1354: if (wup != null)
1355: page.setAuthor(wup.getName());
1356: }
1357:
1358: text = TextUtil.normalizePostData(text);
1359:
1360: text = m_filterManager.doPreSaveFiltering(context, text);
1361:
1362: // Hook into cross reference collection.
1363:
1364: m_pageManager.putPageText(page, text);
1365:
1366: m_filterManager.doPostSaveFiltering(context, text);
1367: }
1368:
1369: /**
1370: * Returns the number of pages in this Wiki
1371: */
1372: public int getPageCount() {
1373: return m_pageManager.getTotalPageCount();
1374: }
1375:
1376: /**
1377: * Returns the provider name
1378: */
1379:
1380: public String getCurrentProvider() {
1381: return m_pageManager.getProvider().getClass().getName();
1382: }
1383:
1384: /**
1385: * return information about current provider.
1386: * @since 1.6.4
1387: */
1388: public String getCurrentProviderInfo() {
1389: return m_pageManager.getProviderDescription();
1390: }
1391:
1392: /**
1393: * Returns a Collection of WikiPages, sorted in time
1394: * order of last change.
1395: */
1396:
1397: // FIXME: Should really get a Date object and do proper comparisons.
1398: // This is terribly wasteful.
1399: public Collection getRecentChanges() {
1400: try {
1401: Collection pages = m_pageManager.getAllPages();
1402: Collection atts = m_attachmentManager.getAllAttachments();
1403:
1404: TreeSet sortedPages = new TreeSet(new PageTimeComparator());
1405:
1406: sortedPages.addAll(pages);
1407: sortedPages.addAll(atts);
1408:
1409: return sortedPages;
1410: } catch (ProviderException e) {
1411: log.error("Unable to fetch all pages: ", e);
1412: return null;
1413: }
1414: }
1415:
1416: /**
1417: * Parses an incoming search request, then
1418: * does a search.
1419: * <P>
1420: * The query is dependent on the actual chosen search provider - each one of them has
1421: * a language of its own.
1422: */
1423:
1424: //
1425: // FIXME: Should also have attributes attached.
1426: //
1427: public Collection findPages(String query) throws ProviderException,
1428: IOException {
1429: Collection results = m_searchManager.findPages(query);
1430:
1431: return results;
1432: }
1433:
1434: /**
1435: * Return a bunch of information from the web page.
1436: */
1437:
1438: public WikiPage getPage(String pagereq) {
1439: return getPage(pagereq, WikiProvider.LATEST_VERSION);
1440: }
1441:
1442: /**
1443: * Returns specific information about a Wiki page.
1444: * @since 1.6.7.
1445: */
1446:
1447: public WikiPage getPage(String pagereq, int version) {
1448: try {
1449: pagereq = makeAbsolutePageName(pagereq);
1450: WikiPage p = m_pageManager.getPageInfo(pagereq, version);
1451:
1452: if (p == null) {
1453: p = m_attachmentManager.getAttachmentInfo(
1454: (WikiContext) null, pagereq);
1455: }
1456:
1457: return p;
1458: } catch (ProviderException e) {
1459: log.error("Unable to fetch page info", e);
1460: return null;
1461: }
1462: }
1463:
1464: /**
1465: * Returns a Collection of WikiPages containing the
1466: * version history of a page.
1467: */
1468:
1469: public List getVersionHistory(String page) {
1470: List c = null;
1471:
1472: try {
1473: c = m_pageManager.getVersionHistory(page);
1474:
1475: if (c == null) {
1476: c = m_attachmentManager.getVersionHistory(page);
1477: }
1478: } catch (ProviderException e) {
1479: log.error("FIXME");
1480: }
1481:
1482: return c;
1483: }
1484:
1485: /**
1486: * Returns a diff of two versions of a page.
1487: *
1488: * @param page Page to return
1489: * @param version1 Version number of the old page. If
1490: * WikiPageProvider.LATEST_VERSION (-1), then uses current page.
1491: * @param version2 Version number of the new page. If
1492: * WikiPageProvider.LATEST_VERSION (-1), then uses current page.
1493: *
1494: * @return A HTML-ized difference between two pages. If there is no difference,
1495: * returns an empty string.
1496: */
1497: public String getDiff(String page, int version1, int version2) {
1498: String page1 = getPureText(page, version1);
1499: String page2 = getPureText(page, version2);
1500:
1501: // Kludge to make diffs for new pages to work this way.
1502:
1503: if (version1 == WikiPageProvider.LATEST_VERSION) {
1504: page1 = "";
1505: }
1506:
1507: String diff = m_differenceManager.makeDiff(page1, page2);
1508:
1509: return diff;
1510: }
1511:
1512: /**
1513: * Returns this object's ReferenceManager.
1514: * @since 1.6.1
1515: */
1516: // (FIXME: We may want to protect this, though...)
1517: public ReferenceManager getReferenceManager() {
1518: return m_referenceManager;
1519: }
1520:
1521: /**
1522: * Returns the current plugin manager.
1523: * @since 1.6.1
1524: */
1525:
1526: public PluginManager getPluginManager() {
1527: return m_pluginManager;
1528: }
1529:
1530: public VariableManager getVariableManager() {
1531: return m_variableManager;
1532: }
1533:
1534: /**
1535: * Shortcut to getVariableManager().getValue(). However, this method does not
1536: * throw a NoSuchVariableException, but returns null in case the variable does
1537: * not exist.
1538: *
1539: * @since 2.2
1540: */
1541: public String getVariable(WikiContext context, String name) {
1542: try {
1543: return m_variableManager.getValue(context, name);
1544: } catch (NoSuchVariableException e) {
1545: return null;
1546: }
1547: }
1548:
1549: /**
1550: * Returns the current PageManager.
1551: */
1552: public PageManager getPageManager() {
1553: return m_pageManager;
1554: }
1555:
1556: /**
1557: * Returns the current AttachmentManager.
1558: * @since 1.9.31.
1559: */
1560: public AttachmentManager getAttachmentManager() {
1561: return m_attachmentManager;
1562: }
1563:
1564: /**
1565: * Returns the currently used authorization manager.
1566: */
1567: public AuthorizationManager getAuthorizationManager() {
1568: return m_authorizationManager;
1569: }
1570:
1571: /**
1572: * Returns the currently used user manager.
1573: */
1574: public UserManager getUserManager() {
1575: return m_userManager;
1576: }
1577:
1578: /**
1579: * Returns the manager responsible for the filters.
1580: * @since 2.1.88
1581: */
1582: public FilterManager getFilterManager() {
1583: return m_filterManager;
1584: }
1585:
1586: /**
1587: * Returns the manager responsible for searching the Wiki.
1588: * @since 2.2.21
1589: */
1590: public SearchManager getSearchManager() {
1591: return m_searchManager;
1592: }
1593:
1594: /**
1595: * Parses the given path and attempts to match it against the list
1596: * of specialpages to see if this path exists. It is used to map things
1597: * like "UserPreferences.jsp" to page "User Preferences".
1598: *
1599: * @return WikiName, or null if a match could not be found.
1600: */
1601: private String matchSpecialPagePath(String path) {
1602: //
1603: // Remove servlet root marker.
1604: //
1605: if (path.startsWith("/")) {
1606: path = path.substring(1);
1607: }
1608:
1609: for (Iterator i = m_properties.entrySet().iterator(); i
1610: .hasNext();) {
1611: Map.Entry entry = (Map.Entry) i.next();
1612:
1613: String key = (String) entry.getKey();
1614:
1615: if (key.startsWith(PROP_SPECIALPAGE)) {
1616: String value = (String) entry.getValue();
1617:
1618: if (value.equals(path)) {
1619: return key.substring(PROP_SPECIALPAGE.length());
1620: }
1621: }
1622: }
1623:
1624: return null;
1625: }
1626:
1627: /**
1628: * Figure out to which page we are really going to. Considers
1629: * special page names from the jspwiki.properties, and possible aliases.
1630: *
1631: * @param context The Wiki Context in which the request is being made.
1632: * @return A complete URL to the new page to redirect to
1633: * @since 2.2
1634: */
1635:
1636: public String getRedirectURL(WikiContext context) {
1637: String pagename = context.getPage().getName();
1638: String redirURL = null;
1639:
1640: redirURL = getSpecialPageReference(pagename);
1641:
1642: if (redirURL == null) {
1643: String alias = (String) context.getPage().getAttribute(
1644: WikiPage.ALIAS);
1645:
1646: if (alias != null) {
1647: //redirURL = getViewURL( alias );
1648: redirURL = getBaseURL() + "Wiki.jsp?page=" + alias;
1649: } else {
1650: redirURL = (String) context.getPage().getAttribute(
1651: WikiPage.REDIRECT);
1652: }
1653: }
1654:
1655: return redirURL;
1656: }
1657:
1658: public WikiContext createContext(HttpServletRequest request,
1659: String requestContext) {
1660: return createContext(request, null, requestContext);
1661: }
1662:
1663: /**
1664: * Shortcut to create a WikiContext from the Wiki page.
1665: *
1666: * @since 2.1.15.
1667: */
1668: // FIXME: We need to have a version which takes a fixed page
1669: // name as well, or check it elsewhere.
1670: public WikiContext createContext(HttpServletRequest request,
1671: HttpServletResponse response, String requestContext) {
1672: String pagereq;
1673:
1674: if (!m_isConfigured) {
1675: throw new InternalWikiException(
1676: "WikiEngine has not been properly started. It is likely that the configuration is faulty. Please check all logs for the possible reason.");
1677: }
1678:
1679: try {
1680: pagereq = m_urlConstructor.parsePage(requestContext,
1681: request, getContentEncoding());
1682: } catch (IOException e) {
1683: log.error("Unable to create context", e);
1684: throw new InternalWikiException(
1685: "Big internal booboo, please check logs.");
1686: }
1687:
1688: String template = safeGetParameter(request, "skin");
1689:
1690: String wikiName = getWikiName(pagereq);
1691: pagereq = getRelativePageName(pagereq);
1692: if (wikiName == null)
1693: wikiName = safeGetParameter(request, "wikiname");
1694: if (wikiName == null)
1695: wikiName = HttpUtil.retrieveCookieValue(request,
1696: "wiki_name");
1697: if (wikiName != null && wikiName.length() == 0)
1698: wikiName = null;
1699: String rawWikiName = wikiName;
1700: //wikiName = TranslatorReader.cleanLink(wikiName);
1701: WikiContext.setWikiName(wikiName);
1702:
1703: //
1704: // Figure out the page name.
1705: // We also check the list of special pages, which incidentally
1706: // allows us to localize them, too.
1707: //
1708:
1709: if (pagereq == null || pagereq.length() == 0) {
1710: String servlet = request.getServletPath();
1711: log.debug("Servlet path is: " + servlet);
1712:
1713: pagereq = matchSpecialPagePath(servlet);
1714:
1715: log.debug("Mapped to " + pagereq);
1716: if (pagereq == null)
1717: pagereq = getFrontPage();
1718: }
1719:
1720: // create the community context for this thread
1721: setCommunityContext(new CommunityContext(request, response));
1722:
1723: // XXX this is provisioning even for non-members, should move this to page manager
1724: if (m_pageTemplatesConfigDir != null
1725: && wikiName != null
1726: && wikiName.length() > 0
1727: && !pageExists(getFrontPage())
1728: && m_authorizationManager.checkPermission(new WikiPage(
1729: wikiName + ":Main"), getUserManager()
1730: .getUserProfile(request), "create")) {
1731: // Main page not found - import the initial pages for this wiki
1732: // this currently only handles sub-wikis - the default wiki is handled by the jdbc provider's migration code
1733:
1734: // wikicommunities are provisioned with the community pagetemplate
1735: String wikitype = "community";
1736: if (WikiPortletContext.isActive()
1737: && "wikiportlet".equals(WikiPortletContext
1738: .get("wikiTemplate"))) {
1739: // wikiportlet within a community uses the communityportlet pagetemplate
1740: // nb: this is not detected when accessing /wiki directly - it will always use the community pagetemplate
1741: wikitype = "communityportlet";
1742: }
1743: String pagetpl = m_pageTemplatesConfigDir + "/" + wikitype
1744: + ".properties";
1745: log.info("Importing initial pages for Wiki: '"
1746: + (wikiName != null ? wikiName : "global")
1747: + "' using " + pagetpl);
1748: try {
1749: Map tags = new HashMap();
1750: tags.put("%WikiName%", wikiName);
1751: getCommunityContext().insertTags(rawWikiName, tags);
1752: m_pageManager.importPages(pagetpl, tags);
1753: } catch (IOException ioe) {
1754: log
1755: .error(
1756: "Failed to import pages using"
1757: + pagetpl, ioe);
1758: }
1759: }
1760:
1761: int hashMark = pagereq.indexOf('#');
1762:
1763: if (hashMark != -1) {
1764: pagereq = pagereq.substring(0, hashMark);
1765: }
1766:
1767: int version = WikiProvider.LATEST_VERSION;
1768: String rev = request.getParameter("version");
1769:
1770: if (rev != null) {
1771: version = Integer.parseInt(rev);
1772: }
1773:
1774: //
1775: // Find the WikiPage object
1776: //
1777: // sanitize the page name (but not any attachment)
1778: pagereq = TranslatorReader.cleanLink(pagereq);
1779: if (wikiName != null && pagereq.indexOf(":") == -1)
1780: pagereq = wikiName + ":" + pagereq;
1781:
1782: String pagename = pagereq;
1783: WikiPage wikipage;
1784:
1785: try {
1786: // checks if page exists and returns its real name (handles plurals, etc)
1787: pagename = getFinalPageName(pagereq);
1788: } catch (ProviderException e) {
1789: } // FIXME: Should not ignore!
1790:
1791: if (pagename != null) {
1792: wikipage = getPage(pagename, version);
1793: } else {
1794: wikipage = getPage(pagereq, version);
1795: }
1796:
1797: if (wikipage == null) {
1798: //pagereq = TranslatorReader.cleanLink( pagereq );
1799: wikipage = new WikiPage(pagereq);
1800: }
1801:
1802: //
1803: // Figure out which template we should be using for this page.
1804: //
1805: if (template == null) {
1806: template = (String) wikipage.getAttribute(PROP_TEMPLATEDIR);
1807:
1808: if (template == null) {
1809: template = (String) WikiPortletContext
1810: .get("wikiTemplate"); // from portlet prefs
1811: }
1812:
1813: // FIXME: Most definitely this should be checked for
1814: // existence, or else it is possible to create pages that
1815: // cannot be shown.
1816:
1817: if (template == null || template.length() == 0) {
1818: template = getTemplateDir();
1819: }
1820: }
1821:
1822: WikiContext context = new WikiContext(this , wikipage);
1823: context.setRequestContext(requestContext);
1824: context.setHttpRequest(request);
1825: context.setHttpResponse(response);
1826: context.setTemplate(template);
1827:
1828: try {
1829: context.setTemplateBundle(ResourceBundle.getBundle(
1830: template, request.getLocale()));
1831: } catch (Exception ignored) {
1832: // ignore missing bundles, locales, etc.
1833: }
1834:
1835: UserProfile user = getUserManager().getUserProfile(request);
1836: context.setCurrentUser(user);
1837:
1838: return context;
1839: }
1840:
1841: /**
1842: * Deletes a page or an attachment completely, including all versions.
1843: *
1844: * @param pageName
1845: * @throws ProviderException
1846: */
1847: public void deletePage(String pageName) throws ProviderException {
1848: WikiPage p = getPage(pageName);
1849:
1850: if (p instanceof Attachment) {
1851: m_attachmentManager.deleteAttachment((Attachment) p);
1852: } else {
1853: if (m_attachmentManager.hasAttachments(p)) {
1854: Collection attachments = m_attachmentManager
1855: .listAttachments(p);
1856: for (Iterator atti = attachments.iterator(); atti
1857: .hasNext();) {
1858: m_attachmentManager
1859: .deleteAttachment((Attachment) (atti.next()));
1860: }
1861:
1862: }
1863: m_pageManager.deletePage(p);
1864: }
1865: }
1866:
1867: /**
1868: * Deletes a specific version of a page or an attachment.
1869: *
1870: * @param page
1871: * @throws ProviderException
1872: */
1873: public void deleteVersion(WikiPage page) throws ProviderException {
1874: if (page instanceof Attachment) {
1875: m_attachmentManager.deleteVersion((Attachment) page);
1876: } else {
1877: m_pageManager.deleteVersion(page);
1878: }
1879: }
1880:
1881: /**
1882: * Returns the URL of the global RSS file. May be null, if the
1883: * RSS file generation is not operational.
1884: * @since 1.7.10
1885: */
1886: public String getGlobalRSSURL() {
1887: if (m_rssURL != null) {
1888: return getBaseURL() + m_rssURL;
1889: }
1890:
1891: return null;
1892: }
1893:
1894: /**
1895: * @since 2.2
1896: */
1897: public String getRootPath() {
1898: return m_rootPath;
1899: }
1900:
1901: /**
1902: * @since 2.2.6
1903: * @return
1904: */
1905: public URLConstructor getURLConstructor() {
1906: return m_urlConstructor;
1907: }
1908:
1909: public static String getRelativePageName(String page) {
1910: int cdx;
1911: if (page == null || (cdx = page.indexOf(":")) == -1)
1912: return page;
1913: else
1914: return page.substring(cdx + 1);
1915: }
1916:
1917: /**
1918: * Return a page name relative to the curent wiki
1919: * eg, if current wiki is blah then blah:Main -> Main, blech:Main -> blech:Main
1920: */
1921: public static String getRelativeToWikiPageName(String page) {
1922: String pageWikiName = getWikiName(page);
1923: if (pageWikiName == null)
1924: return page;
1925: else {
1926: String curWikiName = WikiContext.getWikiName();
1927: if (pageWikiName.equals(curWikiName))
1928: return getRelativePageName(page);
1929: else
1930: return page;
1931: }
1932: }
1933:
1934: public static String getWikiName(String page) {
1935: int cdx;
1936: if (page == null || (cdx = page.indexOf(":")) == -1)
1937: return null;
1938: else
1939: return page.substring(0, cdx);
1940: }
1941:
1942: public static String makeAbsolutePageName(String page) {
1943: if (page.indexOf(":") == -1) {
1944: String wikiName = WikiContext.getWikiName();
1945: if (wikiName != null)
1946: page = wikiName + ":" + page;
1947: }
1948: return page;
1949: }
1950:
1951: public static String makeProviderPageName(String page) {
1952: if (page.indexOf(":") == -1) {
1953: String wikiName = WikiContext.getWikiName();
1954: if (wikiName != null)
1955: page = wikiName + ":" + page;
1956: } else if (page.indexOf(":") == 0)
1957: page = page.substring(1);
1958: return page;
1959: }
1960:
1961: /**
1962: * @since 2.1.165
1963: * @return
1964: */
1965: public RSSGenerator getRSSGenerator() {
1966: return m_rssGenerator;
1967: }
1968:
1969: /**
1970: * Runs the RSS generation thread.
1971: * FIXME: MUST be somewhere else, this is not a good place.
1972: */
1973: private class RSSThread extends Thread {
1974: public void run() {
1975: try {
1976: String fileName = m_properties.getProperty(
1977: RSSGenerator.PROP_RSSFILE, "rss.rdf");
1978: int rssInterval = TextUtil
1979: .parseIntParameter(
1980: m_properties
1981: .getProperty(RSSGenerator.PROP_INTERVAL),
1982: 3600);
1983:
1984: log.debug("RSS file will be at " + fileName);
1985: log.debug("RSS refresh interval (seconds): "
1986: + rssInterval);
1987:
1988: while (true) {
1989: Writer out = null;
1990: Reader in = null;
1991:
1992: try {
1993: //
1994: // Generate RSS file, output it to
1995: // default "rss.rdf".
1996: //
1997: log.debug("Regenerating RSS feed to "
1998: + fileName);
1999:
2000: String feed = m_rssGenerator.generate();
2001:
2002: File file = new File(m_rootPath, fileName);
2003:
2004: in = new StringReader(feed);
2005: out = new BufferedWriter(
2006: new OutputStreamWriter(
2007: new FileOutputStream(file),
2008: "UTF-8"));
2009:
2010: FileUtil.copyContents(in, out);
2011:
2012: m_rssURL = fileName;
2013: } catch (IOException e) {
2014: log.error("Cannot generate RSS feed to "
2015: + fileName, e);
2016: m_rssURL = null;
2017: } finally {
2018: try {
2019: if (in != null)
2020: in.close();
2021: if (out != null)
2022: out.close();
2023: } catch (IOException e) {
2024: log.fatal("Could not close I/O for RSS", e);
2025: break;
2026: }
2027: }
2028:
2029: Thread.sleep(rssInterval * 1000L);
2030: } // while
2031:
2032: } catch (InterruptedException e) {
2033: log.error("RSS thread interrupted, no more RSS feeds",
2034: e);
2035: }
2036:
2037: //
2038: // Signal: no more RSS feeds.
2039: //
2040: m_rssURL = null;
2041: }
2042: }
2043:
2044: public void setCommunityContext(CommunityContext cctx) {
2045: m_communityContextTL.set(cctx);
2046: }
2047:
2048: public CommunityContext getCommunityContext() {
2049: return (CommunityContext) m_communityContextTL.get();
2050: }
2051:
2052: }
|