| /* |
| JSPWiki - a JSP-based WikiWiki clone. |
| |
| Copyright (C) 2001-2005 Janne Jalkanen (Janne.Jalkanen@iki.fi) |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2.1 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| package com.ecyrd.jspwiki; |
| |
| import java.io.*; |
| import java.security.Principal; |
| import java.util.*; |
| |
| import javax.servlet.ServletConfig; |
| import javax.servlet.ServletContext; |
| import javax.servlet.ServletRequest; |
| import javax.servlet.http.HttpServletRequest; |
| |
| import org.apache.commons.lang.time.StopWatch; |
| import org.apache.log4j.Logger; |
| import org.apache.log4j.PropertyConfigurator; |
| |
| import com.ecyrd.jspwiki.attachment.Attachment; |
| import com.ecyrd.jspwiki.attachment.AttachmentManager; |
| import com.ecyrd.jspwiki.auth.AuthenticationManager; |
| import com.ecyrd.jspwiki.auth.AuthorizationManager; |
| import com.ecyrd.jspwiki.auth.UserManager; |
| import com.ecyrd.jspwiki.auth.acl.AclManager; |
| import com.ecyrd.jspwiki.auth.acl.DefaultAclManager; |
| import com.ecyrd.jspwiki.auth.authorize.GroupManager; |
| import com.ecyrd.jspwiki.auth.user.UserDatabase; |
| import com.ecyrd.jspwiki.diff.DifferenceManager; |
| import com.ecyrd.jspwiki.filters.FilterException; |
| import com.ecyrd.jspwiki.filters.FilterManager; |
| import com.ecyrd.jspwiki.parser.JSPWikiMarkupParser; |
| import com.ecyrd.jspwiki.parser.MarkupParser; |
| import com.ecyrd.jspwiki.plugin.PluginManager; |
| import com.ecyrd.jspwiki.providers.ProviderException; |
| import com.ecyrd.jspwiki.providers.WikiPageProvider; |
| import com.ecyrd.jspwiki.render.RenderingManager; |
| import com.ecyrd.jspwiki.rss.RSSGenerator; |
| import com.ecyrd.jspwiki.search.SearchManager; |
| import com.ecyrd.jspwiki.ui.EditorManager; |
| import com.ecyrd.jspwiki.ui.TemplateManager; |
| import com.ecyrd.jspwiki.url.URLConstructor; |
| import com.ecyrd.jspwiki.util.ClassUtil; |
| |
| /** |
| * Provides Wiki services to the JSP page. |
| * |
| * <P> |
| * This is the main interface through which everything should go. |
| * |
| * <P> |
| * Using this class: Always get yourself an instance from JSP page |
| * by using the WikiEngine.getInstance() method. Never create a new |
| * WikiEngine() from scratch, unless you're writing tests. |
| * <p> |
| * There's basically only a single WikiEngine for each web application, and |
| * you should always get it using the WikiEngine.getInstance() method. |
| * |
| * @author Janne Jalkanen |
| */ |
| public class WikiEngine |
| { |
| private static final Logger log = Logger.getLogger(WikiEngine.class); |
| |
| /** True, if log4j has been configured. */ |
| // FIXME: If you run multiple applications, the first application |
| // to run defines where the log goes. Not what we want. |
| private static boolean c_configured = false; |
| |
| /** Stores properties. */ |
| private Properties m_properties; |
| |
| /** The web.xml parameter that defines where the config file is to be found. |
| * If it is not defined, uses the default as defined by DEFAULT_PROPERTYFILE. |
| * {@value jspwiki.propertyfile} |
| */ |
| |
| public static final String PARAM_PROPERTYFILE = "jspwiki.propertyfile"; |
| |
| /** Property for application name */ |
| public static final String PROP_APPNAME = "jspwiki.applicationName"; |
| |
| /** Property start for any interwiki reference. */ |
| public static final String PROP_INTERWIKIREF = "jspwiki.interWikiRef."; |
| |
| /** If true, then the user name will be stored with the page data.*/ |
| public static final String PROP_STOREUSERNAME= "jspwiki.storeUserName"; |
| |
| /** Define the used encoding. Currently supported are ISO-8859-1 and UTF-8 */ |
| public static final String PROP_ENCODING = "jspwiki.encoding"; |
| |
| /** The name for the base URL to use in all references. */ |
| public static final String PROP_BASEURL = "jspwiki.baseURL"; |
| |
| public static final String PROP_REFSTYLE = "jspwiki.referenceStyle"; |
| |
| /** Property name for the "spaces in titles" -hack. */ |
| public static final String PROP_BEAUTIFYTITLE = "jspwiki.breakTitleWithSpaces"; |
| |
| /** Property name for where the jspwiki work directory should be. |
| If not specified, reverts to ${java.tmpdir}. */ |
| public static final String PROP_WORKDIR = "jspwiki.workDir"; |
| |
| /** The name of the cookie that gets stored to the user browser. */ |
| public static final String PREFS_COOKIE_NAME = "JSPWikiUserProfile"; |
| |
| /** Property name for the "match english plurals" -hack. */ |
| public static final String PROP_MATCHPLURALS = "jspwiki.translatorReader.matchEnglishPlurals"; |
| /** Property name for the template that is used. */ |
| public static final String PROP_TEMPLATEDIR = "jspwiki.templateDir"; |
| |
| /** Property name for the default front page. */ |
| public static final String PROP_FRONTPAGE = "jspwiki.frontPage"; |
| |
| /** Property name for setting the url generator instance */ |
| |
| public static final String PROP_URLCONSTRUCTOR = "jspwiki.urlConstructor"; |
| |
| private static final String PROP_SPECIALPAGE = "jspwiki.specialPage."; |
| |
| /** If this property is set to false, all filters are disabled when translating. */ |
| public static final String PROP_RUNFILTERS = "jspwiki.runFilters"; |
| |
| /** Path to the default property file. |
| * {@value /WEB_INF/jspwiki.properties} |
| */ |
| public static final String DEFAULT_PROPERTYFILE = "/WEB-INF/jspwiki.properties"; |
| |
| /** Does the work in renaming pages. */ |
| private PageRenamer m_pageRenamer = null; |
| |
| /** |
| * Contains the default properties for JSPWiki. |
| */ |
| private static final String[] DEFAULT_PROPERTIES = |
| { "jspwiki.specialPage.Login", "Login.jsp", |
| "jspwiki.specialPage.Logout", "Logout.jsp", |
| "jspwiki.specialPage.CreateGroup", "NewGroup.jsp", |
| "jspwiki.specialPage.CreateProfile", "Register.jsp", |
| "jspwiki.specialPage.EditProfile", "UserPreferences.jsp", |
| "jspwiki.specialPage.Preferences", "UserPreferences.jsp", |
| "jspwiki.specialPage.Search", "Search.jsp", |
| "jspwiki.specialPage.FindPage", "FindPage.jsp"}; |
| |
| /** Stores an internal list of engines per each ServletContext */ |
| private static Hashtable c_engines = new Hashtable(); |
| |
| /** Should the user info be saved with the page data as well? */ |
| private boolean m_saveUserInfo = true; |
| |
| /** If true, uses UTF8 encoding for all data */ |
| private boolean m_useUTF8 = true; |
| |
| /** If true, we'll also consider english plurals (+s) a match. */ |
| private boolean m_matchEnglishPlurals = true; |
| |
| /** Stores the base URL. */ |
| private String m_baseURL; |
| |
| /** Store the file path to the basic URL. When we're not running as |
| a servlet, it defaults to the user's current directory. */ |
| private String m_rootPath = System.getProperty("user.dir"); |
| |
| /** Stores references between wikipages. */ |
| private ReferenceManager m_referenceManager = null; |
| |
| /** Stores the Plugin manager */ |
| private PluginManager m_pluginManager; |
| |
| /** Stores the Variable manager */ |
| private VariableManager m_variableManager; |
| |
| /** Stores the Attachment manager */ |
| private AttachmentManager m_attachmentManager = null; |
| |
| /** Stores the Page manager */ |
| private PageManager m_pageManager = null; |
| |
| /** Stores the authorization manager */ |
| private AuthorizationManager m_authorizationManager = null; |
| |
| /** Stores the authentication manager.*/ |
| private AuthenticationManager m_authenticationManager = null; |
| |
| /** Stores the ACL manager. */ |
| private AclManager m_aclManager = null; |
| |
| private TemplateManager m_templateManager = null; |
| |
| /** Does all our diffs for us. */ |
| private DifferenceManager m_differenceManager; |
| |
| /** Handlers page filters. */ |
| private FilterManager m_filterManager; |
| |
| /** Stores the Search manager */ |
| private SearchManager m_searchManager = null; |
| |
| private UserManager m_userManager; |
| |
| private RenderingManager m_renderingManager; |
| |
| private EditorManager m_editorManager; |
| |
| /** Constructs URLs */ |
| private URLConstructor m_urlConstructor; |
| |
| /** Generates RSS feed when requested. */ |
| private RSSGenerator m_rssGenerator; |
| |
| /** Stores the relative URL to the global RSS feed. */ |
| private String m_rssURL; |
| |
| /** Store the ServletContext that we're in. This may be null if WikiEngine |
| is not running inside a servlet container (i.e. when testing). */ |
| private ServletContext m_servletContext = null; |
| |
| /** If true, all titles will be cleaned. */ |
| private boolean m_beautifyTitle = false; |
| |
| /** Stores the template path. This is relative to "templates". */ |
| private String m_templateDir; |
| |
| /** The default front page name. Defaults to "Main". */ |
| private String m_frontPage; |
| |
| /** The time when this engine was started. */ |
| private Date m_startTime; |
| |
| /** The location where the work directory is. */ |
| private String m_workDir; |
| |
| /** Each engine has their own application id. */ |
| private String m_appid = ""; |
| |
| private boolean m_isConfigured = false; // Flag. |
| |
| /** |
| * Gets a WikiEngine related to this servlet. Since this method |
| * is only called from JSP pages (and JspInit()) to be specific, |
| * we throw a RuntimeException if things don't work. |
| * |
| * @param config The ServletConfig object for this servlet. |
| * |
| * @return A WikiEngine instance. |
| * @throws InternalWikiException in case something fails. This |
| * is a RuntimeException, so be prepared for it. |
| */ |
| |
| // FIXME: It seems that this does not work too well, jspInit() |
| // does not react to RuntimeExceptions, or something... |
| |
| public static synchronized WikiEngine getInstance( ServletConfig config ) |
| throws InternalWikiException |
| { |
| return( getInstance( config.getServletContext(), null ) ); |
| } |
| |
| /** |
| * Gets a WikiEngine related to the servlet. Works like getInstance(ServletConfig), |
| * but does not force the Properties object. This method is just an optional way |
| * of initializing a WikiEngine for embedded JSPWiki applications; normally, you |
| * should use getInstance(ServletConfig). |
| * |
| * @param config The ServletConfig of the webapp servlet/JSP calling this method. |
| * @param props A set of properties, or null, if we are to load JSPWiki's default |
| * jspwiki.properties (this is the usual case). |
| */ |
| public static synchronized WikiEngine getInstance( ServletConfig config, |
| Properties props ) |
| { |
| return( getInstance( config.getServletContext(), null ) ); |
| } |
| |
| /** |
| * Gets a WikiEngine related to the servlet. Works just like getInstance( ServletConfig ) |
| * |
| * @param context The ServletContext of the webapp servlet/JSP calling this method. |
| * @param props A set of properties, or null, if we are to load JSPWiki's default |
| * jspwiki.properties (this is the usual case). |
| */ |
| |
| // FIXME: Potential make-things-easier thingy here: no need to fetch the wikiengine anymore |
| // Wiki.jsp.jspInit() [really old code]; it's probably even faster to fetch it |
| // using this method every time than go to pageContext.getAttribute(). |
| |
| public static synchronized WikiEngine getInstance( ServletContext context, |
| Properties props ) |
| throws InternalWikiException |
| { |
| String appid = Integer.toString(context.hashCode()); //FIXME: Kludge, use real type. |
| |
| context.log( "Application "+appid+" requests WikiEngine."); |
| |
| WikiEngine engine = (WikiEngine) c_engines.get( appid ); |
| |
| if( engine == null ) |
| { |
| context.log(" Assigning new log to "+appid); |
| try |
| { |
| if( props == null ) |
| props = loadWebAppProps( context ); |
| engine = new WikiEngine( context, appid, props ); |
| } |
| catch( Exception e ) |
| { |
| context.log( "ERROR: Failed to create a Wiki engine: "+e.getMessage() ); |
| throw new InternalWikiException( "No wiki engine, check logs." ); |
| } |
| |
| c_engines.put( appid, engine ); |
| } |
| |
| return engine; |
| } |
| |
| |
| /** |
| * Instantiate the WikiEngine using a given set of properties. |
| * Use this constructor for testing purposes only. |
| */ |
| public WikiEngine( Properties properties ) |
| throws WikiException |
| { |
| initialize( properties ); |
| } |
| |
| /** |
| * Loads the webapp properties based on servlet context information. |
| * Returns a Properties object containing the settings, or null if unable |
| * to load it. (The default file is WEB-INF/jspwiki.properties, and can |
| * be overridden by setting PARAM_PROPERTYFILE in the server or webapp |
| * configuration.) |
| */ |
| private static Properties loadWebAppProps( ServletContext context ) |
| { |
| String propertyFile = context.getInitParameter(PARAM_PROPERTYFILE); |
| InputStream propertyStream = null; |
| |
| try |
| { |
| // |
| // Figure out where our properties lie. |
| // |
| if( propertyFile == null ) |
| { |
| context.log("No "+PARAM_PROPERTYFILE+" defined for this context, using default from "+DEFAULT_PROPERTYFILE); |
| // Use the default property file. |
| propertyStream = context.getResourceAsStream(DEFAULT_PROPERTYFILE); |
| } |
| else |
| { |
| context.log("Reading properties from "+propertyFile+" instead of default."); |
| propertyStream = new FileInputStream( new File(propertyFile) ); |
| } |
| |
| if( propertyStream == null ) |
| { |
| throw new WikiException("Property file cannot be found!"+propertyFile); |
| } |
| |
| Properties props = new Properties( TextUtil.createProperties( DEFAULT_PROPERTIES ) ); |
| props.load( propertyStream ); |
| return( props ); |
| } |
| catch( Exception e ) |
| { |
| context.log( Release.APPNAME+": Unable to load and setup properties from jspwiki.properties. "+e.getMessage() ); |
| } |
| finally |
| { |
| try |
| { |
| propertyStream.close(); |
| } |
| catch( IOException e ) |
| { |
| context.log("Unable to close property stream - something must be seriously wrong."); |
| } |
| } |
| |
| return( null ); |
| } |
| |
| |
| /** |
| * Instantiate using this method when you're running as a servlet and |
| * WikiEngine will figure out where to look for the property |
| * file. |
| * Do not use this method - use WikiEngine.getInstance() instead. |
| */ |
| protected WikiEngine( ServletContext context, String appid, Properties props ) |
| throws WikiException |
| { |
| m_servletContext = context; |
| m_appid = appid; |
| |
| try |
| { |
| // |
| // Note: May be null, if JSPWiki has been deployed in a WAR file. |
| // |
| m_rootPath = context.getRealPath("/"); |
| initialize( props ); |
| log.info("Root path for this Wiki is: '"+m_rootPath+"'"); |
| } |
| catch( Exception e ) |
| { |
| context.log( Release.APPNAME+": Unable to load and setup properties from jspwiki.properties. "+e.getMessage() ); |
| } |
| } |
| |
| /** |
| * Does all the real initialization. |
| */ |
| private void initialize( Properties props ) |
| throws WikiException |
| { |
| m_startTime = new Date(); |
| m_properties = props; |
| |
| // |
| // Initialized log4j. However, make sure that |
| // we don't initialize it multiple times. Also, if |
| // all of the log4j statements have been removed from |
| // the property file, we do not do any property setting |
| // either.q |
| // |
| if( !c_configured ) |
| { |
| if( props.getProperty("log4j.rootCategory") != null ) |
| { |
| PropertyConfigurator.configure( props ); |
| } |
| c_configured = true; |
| } |
| |
| log.info("*******************************************"); |
| log.info("JSPWiki "+Release.VERSTR+" starting. Whee!"); |
| |
| log.debug("Configuring WikiEngine..."); |
| |
| // |
| // Create and find the default working directory. |
| // |
| m_workDir = TextUtil.getStringProperty( props, PROP_WORKDIR, null ); |
| |
| if( m_workDir == null ) |
| { |
| m_workDir = System.getProperty("java.io.tmpdir", "."); |
| m_workDir += File.separator+Release.APPNAME+"-"+m_appid; |
| } |
| |
| try |
| { |
| File f = new File( m_workDir ); |
| f.mkdirs(); |
| |
| // |
| // A bunch of sanity checks |
| // |
| if( !f.exists() ) throw new WikiException("Work directory does not exist: "+m_workDir); |
| if( !f.canRead() ) throw new WikiException("No permission to read work directory: "+m_workDir); |
| if( !f.canWrite() ) throw new WikiException("No permission to write to work directory: "+m_workDir); |
| if( !f.isDirectory() ) throw new WikiException("jspwiki.workDir does not point to a directory: "+m_workDir); |
| } |
| catch( SecurityException e ) |
| { |
| log.fatal("Unable to find or create the working directory: "+m_workDir,e); |
| throw new IllegalArgumentException("Unable to find or create the working dir: "+m_workDir); |
| } |
| |
| log.info("JSPWiki working directory is '"+m_workDir+"'"); |
| |
| m_saveUserInfo = TextUtil.getBooleanProperty( props, |
| PROP_STOREUSERNAME, |
| m_saveUserInfo ); |
| |
| m_useUTF8 = "UTF-8".equals( TextUtil.getStringProperty( props, PROP_ENCODING, "ISO-8859-1" ) ); |
| m_baseURL = TextUtil.getStringProperty( props, PROP_BASEURL, "" ); |
| |
| |
| m_beautifyTitle = TextUtil.getBooleanProperty( props, |
| PROP_BEAUTIFYTITLE, |
| m_beautifyTitle ); |
| |
| m_matchEnglishPlurals = TextUtil.getBooleanProperty( props, |
| PROP_MATCHPLURALS, |
| m_matchEnglishPlurals ); |
| |
| m_templateDir = TextUtil.getStringProperty( props, PROP_TEMPLATEDIR, "default" ); |
| m_frontPage = TextUtil.getStringProperty( props, PROP_FRONTPAGE, "Main" ); |
| |
| // |
| // Initialize the important modules. Any exception thrown by the |
| // managers means that we will not start up. |
| // |
| try |
| { |
| Class urlclass = ClassUtil.findClass( "com.ecyrd.jspwiki.url", |
| TextUtil.getStringProperty( props, PROP_URLCONSTRUCTOR, "DefaultURLConstructor" ) ); |
| m_urlConstructor = (URLConstructor) urlclass.newInstance(); |
| m_urlConstructor.initialize( this, props ); |
| |
| m_pageManager = new PageManager( this, props ); |
| m_pluginManager = new PluginManager( props ); |
| m_differenceManager = new DifferenceManager( this, props ); |
| m_attachmentManager = new AttachmentManager( this, props ); |
| m_variableManager = new VariableManager( props ); |
| m_filterManager = new FilterManager( this, props ); |
| m_renderingManager = new RenderingManager(); |
| m_renderingManager.initialize( this, props ); |
| |
| m_searchManager = new SearchManager( this, props ); |
| |
| m_authenticationManager = new AuthenticationManager(); |
| m_authorizationManager = new AuthorizationManager(); |
| m_userManager = new UserManager(); |
| |
| m_editorManager = new EditorManager(); |
| m_editorManager.initialize( this, props ); |
| |
| // Initialize the authentication, authorization, user and acl managers |
| m_authenticationManager.initialize( this, props ); |
| m_authorizationManager.initialize( this, props ); |
| m_userManager.initialize( this, props ); |
| |
| // m_groupManager = getGroupManager(); |
| m_aclManager = getAclManager(); |
| |
| // |
| // ReferenceManager has the side effect of loading all |
| // pages. Therefore after this point, all page attributes |
| // are available. |
| // |
| initReferenceManager(); |
| |
| m_templateManager = new TemplateManager( this, props ); |
| |
| // |
| // Hook the different manager routines into the system. |
| // |
| getFilterManager().addPageFilter(m_referenceManager, -1000 ); |
| getFilterManager().addPageFilter(m_searchManager, -1001 ); |
| |
| } |
| catch( Exception e ) |
| { |
| // RuntimeExceptions may occur here, even if they shouldn't. |
| log.fatal( "Failed to start managers.", e ); |
| throw new WikiException( "Failed to start managers: "+e.getMessage() ); |
| } |
| |
| // |
| // Initialize the good-to-have-but-not-fatal modules. |
| // |
| try |
| { |
| if( TextUtil.getBooleanProperty( props, |
| RSSGenerator.PROP_GENERATE_RSS, |
| false ) ) |
| { |
| m_rssGenerator = new RSSGenerator( this, props ); |
| } |
| |
| m_pageRenamer = new PageRenamer( this, props ); |
| } |
| catch( Exception e ) |
| { |
| log.error( "Unable to start RSS generator - JSPWiki will still work, "+ |
| "but there will be no RSS feed.", e ); |
| } |
| |
| // FIXME: I wonder if this should be somewhere else. |
| if( m_rssGenerator != null ) |
| { |
| new RSSThread().start(); |
| } |
| |
| log.info("WikiEngine configured."); |
| m_isConfigured = true; |
| } |
| |
| /** |
| * Initializes the reference manager. Scans all existing WikiPages for |
| * internal links and adds them to the ReferenceManager object. |
| */ |
| public void initReferenceManager() |
| { |
| m_pluginManager.setInitStage( true ); |
| |
| try |
| { |
| ArrayList pages = new ArrayList(); |
| pages.addAll( m_pageManager.getAllPages() ); |
| pages.addAll( m_attachmentManager.getAllAttachments() ); |
| |
| // Build a new manager with default key lists. |
| if( m_referenceManager == null ) |
| { |
| m_referenceManager = new ReferenceManager( this ); |
| m_referenceManager.initialize( pages ); |
| } |
| |
| } |
| catch( ProviderException e ) |
| { |
| log.fatal("PageProvider is unable to list pages: ", e); |
| } |
| |
| m_pluginManager.setInitStage( false ); |
| } |
| |
| |
| /** |
| * Throws an exception if a property is not found. |
| * |
| * @param props A set of properties to search the key in. |
| * @param key The key to look for. |
| * @return The required property |
| * |
| * @throws NoRequiredPropertyException If the search key is not |
| * in the property set. |
| */ |
| |
| // FIXME: Should really be in some util file. |
| public static String getRequiredProperty( Properties props, String key ) |
| throws NoRequiredPropertyException |
| { |
| String value = TextUtil.getStringProperty( props, key, null ); |
| |
| if( value == null ) |
| { |
| throw new NoRequiredPropertyException( "Required property not found", |
| key ); |
| } |
| |
| return value; |
| } |
| |
| /** |
| * Internal method for getting a property. This is used by the |
| * TranslatorReader for example. |
| */ |
| |
| public Properties getWikiProperties() |
| { |
| return m_properties; |
| } |
| |
| /** |
| * Returns the JSPWiki working directory. |
| * @since 2.1.100 |
| */ |
| public String getWorkDir() |
| { |
| return m_workDir; |
| } |
| |
| /** |
| * Don't use. |
| * @since 1.8.0 |
| * @deprecated |
| */ |
| public String getPluginSearchPath() |
| { |
| // FIXME: This method should not be here, probably. |
| return TextUtil.getStringProperty( m_properties, PluginManager.PROP_SEARCHPATH, null ); |
| } |
| |
| /** |
| * Returns the current template directory. |
| * |
| * @since 1.9.20 |
| */ |
| public String getTemplateDir() |
| { |
| return m_templateDir; |
| } |
| |
| public TemplateManager getTemplateManager() |
| { |
| return m_templateManager; |
| } |
| |
| /** |
| * Returns the base URL. Always prepend this to any reference |
| * you make. |
| * |
| * @since 1.6.1 |
| */ |
| |
| public String getBaseURL() |
| { |
| return m_baseURL; |
| } |
| |
| /** |
| * Returns the moment when this engine was started. |
| * |
| * @since 2.0.15. |
| */ |
| |
| public Date getStartTime() |
| { |
| return m_startTime; |
| } |
| |
| /** |
| * Returns the basic absolute URL to a page, without any modifications. |
| * You may add any parameters to this. This is a convinience method. |
| * |
| * @since 2.0.3 |
| */ |
| public String getViewURL( String pageName ) |
| { |
| return m_urlConstructor.makeURL( WikiContext.VIEW, pageName, true, null ); |
| } |
| |
| /** |
| * Returns the basic URL to an editor. |
| * @deprecated |
| * |
| * @since 2.0.3 |
| */ |
| public String getEditURL( String pageName ) |
| { |
| return m_urlConstructor.makeURL( WikiContext.EDIT, pageName, false, null ); |
| } |
| |
| /** |
| * Returns the basic attachment URL. |
| * @since 2.0.42. |
| * @deprecated |
| */ |
| public String getAttachmentURL( String attName ) |
| { |
| return m_urlConstructor.makeURL( WikiContext.ATTACH, attName, false, null ); |
| } |
| |
| /** |
| * Returns an URL if a WikiContext is not available. |
| * @param context The WikiContext (VIEW, EDIT, etc...) |
| * @param pageName Name of the page, as usual |
| * @param params List of parameters. May be null, if no parameters. |
| * @param absolute If true, will generate an absolute URL regardless of properties setting. |
| */ |
| public String getURL( String context, String pageName, String params, boolean absolute ) |
| { |
| return m_urlConstructor.makeURL( context, pageName, absolute, params ); |
| } |
| /** |
| * Returns the default front page, if no page is used. |
| */ |
| |
| public String getFrontPage() |
| { |
| return m_frontPage; |
| } |
| |
| /** |
| * Returns the ServletContext that this particular WikiEngine was |
| * initialized with. <B>It may return null</B>, if the WikiEngine is not |
| * running inside a servlet container! |
| * |
| * @since 1.7.10 |
| * @return ServletContext of the WikiEngine, or null. |
| */ |
| |
| public ServletContext getServletContext() |
| { |
| return m_servletContext; |
| } |
| |
| /** |
| * This is a safe version of the Servlet.Request.getParameter() routine. |
| * Unfortunately, the default version always assumes that the incoming |
| * character set is ISO-8859-1, even though it was something else. |
| * This means that we need to make a new string using the correct |
| * encoding. |
| * <P> |
| * For more information, see: |
| * <A HREF="http://www.jguru.com/faq/view.jsp?EID=137049">JGuru FAQ</A>. |
| * <P> |
| * Incidentally, this is almost the same as encodeName(), below. |
| * I am not yet entirely sure if it's safe to merge the code. |
| * |
| * @since 1.5.3 |
| * @deprecated JSPWiki now requires servlet API 2.3, which has a better |
| * way of dealing with this stuff. This will be removed in |
| * the near future. |
| */ |
| |
| public String safeGetParameter( ServletRequest request, String name ) |
| { |
| try |
| { |
| String res = request.getParameter( name ); |
| if( res != null ) |
| { |
| res = new String(res.getBytes("ISO-8859-1"), |
| getContentEncoding() ); |
| } |
| |
| return res; |
| } |
| catch( UnsupportedEncodingException e ) |
| { |
| log.fatal( "Unsupported encoding", e ); |
| return ""; |
| } |
| |
| } |
| |
| /** |
| * Returns the query string (the portion after the question mark). |
| * |
| * @return The query string. If the query string is null, |
| * returns an empty string. |
| * |
| * @since 2.1.3 |
| */ |
| public String safeGetQueryString( HttpServletRequest request ) |
| { |
| if (request == null) |
| { |
| return ""; |
| } |
| |
| try |
| { |
| String res = request.getQueryString(); |
| if( res != null ) |
| { |
| res = new String(res.getBytes("ISO-8859-1"), |
| getContentEncoding() ); |
| |
| // |
| // Ensure that the 'page=xyz' attribute is removed |
| // FIXME: Is it really the mandate of this routine to |
| // do that? |
| // |
| int pos1 = res.indexOf("page="); |
| if (pos1 >= 0) |
| { |
| String tmpRes = res.substring(0, pos1); |
| int pos2 = res.indexOf("&",pos1) + 1; |
| if ( (pos2 > 0) && (pos2 < res.length()) ) |
| { |
| tmpRes = tmpRes + res.substring(pos2); |
| } |
| res = tmpRes; |
| } |
| } |
| |
| return res; |
| } |
| catch( UnsupportedEncodingException e ) |
| { |
| log.fatal( "Unsupported encoding", e ); |
| return ""; |
| } |
| } |
| |
| /** |
| * Returns an URL to some other Wiki that we know. |
| * |
| * @return null, if no such reference was found. |
| */ |
| public String getInterWikiURL( String wikiName ) |
| { |
| return TextUtil.getStringProperty(m_properties,PROP_INTERWIKIREF+wikiName,null); |
| } |
| |
| /** |
| * Returns a collection of all supported InterWiki links. |
| */ |
| public Collection getAllInterWikiLinks() |
| { |
| Vector v = new Vector(); |
| |
| for( Enumeration i = m_properties.propertyNames(); i.hasMoreElements(); ) |
| { |
| String prop = (String) i.nextElement(); |
| |
| if( prop.startsWith( PROP_INTERWIKIREF ) ) |
| { |
| v.add( prop.substring( prop.lastIndexOf(".")+1 ) ); |
| } |
| } |
| |
| return v; |
| } |
| |
| /** |
| * Returns a collection of all image types that get inlined. |
| */ |
| |
| public Collection getAllInlinedImagePatterns() |
| { |
| return JSPWikiMarkupParser.getImagePatterns( this ); |
| } |
| |
| /** |
| * If the page is a special page, then returns a direct URL |
| * to that page. Otherwise returns null. |
| * <P> |
| * Special pages are non-existant references to other pages. |
| * For example, you could define a special page reference |
| * "RecentChanges" which would always be redirected to "RecentChanges.jsp" |
| * instead of trying to find a Wiki page called "RecentChanges". |
| */ |
| public String getSpecialPageReference( String original ) |
| { |
| String propname = PROP_SPECIALPAGE+original; |
| String specialpage = TextUtil.getStringProperty( m_properties, propname, null ); |
| |
| if( specialpage != null ) |
| specialpage = getURL( WikiContext.NONE, specialpage, null, true ); |
| |
| return specialpage; |
| } |
| |
| /** |
| * Returns the name of the application. |
| */ |
| |
| // FIXME: Should use servlet context as a default instead of a constant. |
| public String getApplicationName() |
| { |
| String appName = TextUtil.getStringProperty(m_properties,PROP_APPNAME,Release.APPNAME); |
| |
| return appName; |
| } |
| |
| /** |
| * Beautifies the title of the page by appending spaces in suitable |
| * places, if the user has so decreed in the properties when constructing |
| * this WikiEngine. However, attachment names are not beautified, no |
| * matter what. |
| * |
| * @since 1.7.11 |
| */ |
| public String beautifyTitle( String title ) |
| { |
| if( m_beautifyTitle ) |
| { |
| try |
| { |
| if(m_attachmentManager.getAttachmentInfo(title) == null) |
| { |
| return TextUtil.beautifyString( title ); |
| } |
| } |
| catch( ProviderException e ) |
| { |
| return title; |
| } |
| } |
| |
| return title; |
| } |
| |
| /** |
| * Beautifies the title of the page by appending non-breaking spaces |
| * in suitable places. This is really suitable only for HTML output, |
| * as it uses the &nbsp; -character. |
| * |
| * @since 2.1.127 |
| */ |
| public String beautifyTitleNoBreak( String title ) |
| { |
| if( m_beautifyTitle ) |
| { |
| return TextUtil.beautifyString( title, " " ); |
| } |
| |
| return title; |
| } |
| |
| /** |
| * Returns true, if the requested page (or an alias) exists. Will consider |
| * any version as existing. Will also consider attachments. |
| * |
| * @param page WikiName of the page. |
| */ |
| public boolean pageExists( String page ) |
| { |
| |
| Attachment att = null; |
| |
| try |
| { |
| if( getSpecialPageReference(page) != null ) return true; |
| |
| if( getFinalPageName( page ) != null ) |
| { |
| return true; |
| } |
| |
| att = getAttachmentManager().getAttachmentInfo( (WikiContext)null, page ); |
| } |
| catch( ProviderException e ) |
| { |
| log.debug("pageExists() failed to find attachments",e); |
| } |
| |
| return att != null; |
| } |
| |
| /** |
| * Returns true, if the requested page (or an alias) exists with the |
| * requested version. |
| * |
| * @param page Page name |
| */ |
| public boolean pageExists( String page, int version ) |
| throws ProviderException |
| { |
| if( getSpecialPageReference(page) != null ) return true; |
| |
| String finalName = getFinalPageName( page ); |
| |
| boolean isThere = false; |
| |
| if( finalName != null ) |
| { |
| // |
| // Go and check if this particular version of this page |
| // exists. |
| // |
| isThere = m_pageManager.pageExists( finalName, version ); |
| } |
| |
| if( isThere == false ) |
| { |
| // |
| // Go check if such an attachment exists. |
| // |
| try |
| { |
| isThere = getAttachmentManager().getAttachmentInfo( (WikiContext)null, page, version ) != null; |
| } |
| catch( ProviderException e ) |
| { |
| log.debug("pageExists() failed to find attachments",e); |
| } |
| } |
| |
| return isThere; |
| } |
| |
| /** |
| * Returns true, if the requested page (or an alias) exists, with the |
| * specified version in the WikiPage. |
| * |
| * @since 2.0 |
| */ |
| public boolean pageExists( WikiPage page ) |
| throws ProviderException |
| { |
| if( page != null ) |
| { |
| return pageExists( page.getName(), page.getVersion() ); |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the correct page name, or null, if no such |
| * page can be found. Aliases are considered. |
| * <P> |
| * In some cases, page names can refer to other pages. For example, |
| * when you have matchEnglishPlurals set, then a page name "Foobars" |
| * will be transformed into "Foobar", should a page "Foobars" not exist, |
| * but the page "Foobar" would. This method gives you the correct |
| * page name to refer to. |
| * <P> |
| * This facility can also be used to rewrite any page name, for example, |
| * by using aliases. It can also be used to check the existence of any |
| * page. |
| * |
| * @since 2.0 |
| * @param page Page name. |
| * @return The rewritten page name, or null, if the page does not exist. |
| */ |
| |
| public String getFinalPageName( String page ) |
| throws ProviderException |
| { |
| boolean isThere = simplePageExists( page ); |
| |
| if( !isThere && m_matchEnglishPlurals ) |
| { |
| if( page.endsWith("s") ) |
| { |
| page = page.substring( 0, page.length()-1 ); |
| } |
| else |
| { |
| page += "s"; |
| } |
| |
| isThere = simplePageExists( page ); |
| } |
| |
| return isThere ? page : null ; |
| } |
| |
| /** |
| * Just queries the existing pages directly from the page manager. |
| * We also check overridden pages from jspwiki.properties |
| */ |
| private boolean simplePageExists( String page ) |
| throws ProviderException |
| { |
| if( getSpecialPageReference(page) != null ) return true; |
| |
| return m_pageManager.pageExists( page ); |
| } |
| |
| /** |
| * Turns a WikiName into something that can be |
| * called through using an URL. |
| * |
| * @since 1.4.1 |
| */ |
| public String encodeName( String pagename ) |
| { |
| return TextUtil.urlEncode( pagename, (m_useUTF8 ? "UTF-8" : "ISO-8859-1")); |
| } |
| |
| public String decodeName( String pagerequest ) |
| { |
| try |
| { |
| return TextUtil.urlDecode( pagerequest, (m_useUTF8 ? "UTF-8" : "ISO-8859-1") ); |
| } |
| catch( UnsupportedEncodingException e ) |
| { |
| throw new InternalWikiException("ISO-8859-1 not a supported encoding!?! Your platform is borked."); |
| } |
| } |
| |
| /** |
| * Returns the IANA name of the character set encoding we're |
| * supposed to be using right now. |
| * |
| * @since 1.5.3 |
| */ |
| public String getContentEncoding() |
| { |
| if( m_useUTF8 ) |
| return "UTF-8"; |
| |
| return "ISO-8859-1"; |
| } |
| |
| /** |
| * Returns the un-HTMLized text of the latest version of a page. |
| * This method also replaces the < and & -characters with |
| * their respective HTML entities, thus making it suitable |
| * for inclusion on an HTML page. If you want to have the |
| * page text without any conversions, use getPureText(). |
| * |
| * @param page WikiName of the page to fetch. |
| * @return WikiText. |
| */ |
| public String getText( String page ) |
| { |
| return getText( page, WikiPageProvider.LATEST_VERSION ); |
| } |
| |
| /** |
| * Returns the un-HTMLized text of the given version of a page. |
| * This method also replaces the < and & -characters with |
| * their respective HTML entities, thus making it suitable |
| * for inclusion on an HTML page. If you want to have the |
| * page text without any conversions, use getPureText(). |
| * |
| * |
| * @param page WikiName of the page to fetch |
| * @param version Version of the page to fetch |
| * @return WikiText. |
| */ |
| public String getText( String page, int version ) |
| { |
| String result = getPureText( page, version ); |
| |
| // |
| // Replace ampersand first, or else all quotes and stuff |
| // get replaced as well with " etc. |
| // |
| /* |
| result = TextUtil.replaceString( result, "&", "&" ); |
| */ |
| |
| result = TextUtil.replaceEntities( result ); |
| |
| return result; |
| } |
| |
| /** |
| * Returns the un-HTMLized text of the given version of a page in |
| * the given context. USE THIS METHOD if you don't know what |
| * doing. |
| * <p> |
| * This method also replaces the < and & -characters with |
| * their respective HTML entities, thus making it suitable |
| * for inclusion on an HTML page. If you want to have the |
| * page text without any conversions, use getPureText(). |
| * |
| * @since 1.9.15. |
| */ |
| public String getText( WikiContext context, WikiPage page ) |
| { |
| return getText( page.getName(), page.getVersion() ); |
| } |
| |
| |
| /** |
| * Returns the pure text of a page, no conversions. Use this |
| * if you are writing something that depends on the parsing |
| * of the page. Note that you should always check for page |
| * existence through pageExists() before attempting to fetch |
| * the page contents. |
| * |
| * @param page The name of the page to fetch. |
| * @param version If WikiPageProvider.LATEST_VERSION, then uses the |
| * latest version. |
| * @return The page contents. If the page does not exist, |
| * returns an empty string. |
| */ |
| // FIXME: Should throw an exception on unknown page/version? |
| public String getPureText( String page, int version ) |
| { |
| String result = null; |
| |
| try |
| { |
| result = m_pageManager.getPageText( page, version ); |
| } |
| catch( ProviderException e ) |
| { |
| // FIXME |
| } |
| finally |
| { |
| if( result == null ) |
| result = ""; |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Returns the pure text of a page, no conversions. Use this |
| * if you are writing something that depends on the parsing |
| * the page. Note that you should always check for page |
| * existence through pageExists() before attempting to fetch |
| * the page contents. |
| * |
| * @param page A handle to the WikiPage |
| * @return String of WikiText. |
| * @since 2.1.13. |
| */ |
| public String getPureText( WikiPage page ) |
| { |
| return getPureText( page.getName(), page.getVersion() ); |
| } |
| |
| /** |
| * Returns the converted HTML of the page using a different |
| * context than the default context. |
| */ |
| |
| public String getHTML( WikiContext context, WikiPage page ) |
| { |
| String pagedata = null; |
| |
| pagedata = getPureText( page.getName(), page.getVersion() ); |
| |
| String res = textToHTML( context, pagedata ); |
| |
| return res; |
| } |
| |
| /** |
| * Returns the converted HTML of the page. |
| * |
| * @param page WikiName of the page to convert. |
| */ |
| public String getHTML( String page ) |
| { |
| return getHTML( page, WikiPageProvider.LATEST_VERSION ); |
| } |
| |
| /** |
| * Returns the converted HTML of the page's specific version. |
| * The version must be a positive integer, otherwise the current |
| * version is returned. |
| * |
| * @param pagename WikiName of the page to convert. |
| * @param version Version number to fetch |
| */ |
| public String getHTML( String pagename, int version ) |
| { |
| WikiPage page = getPage( pagename, version ); |
| |
| WikiContext context = new WikiContext( this, |
| page ); |
| context.setRequestContext( WikiContext.NONE ); |
| |
| String res = getHTML( context, page ); |
| |
| return res; |
| } |
| |
| /** |
| * Converts raw page data to HTML. |
| * |
| * @param pagedata Raw page data to convert to HTML |
| */ |
| public String textToHTML( WikiContext context, String pagedata ) |
| { |
| String result = ""; |
| |
| boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true")); |
| |
| StopWatch sw = new StopWatch(); |
| sw.start(); |
| try |
| { |
| if( runFilters ) |
| pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata ); |
| |
| result = m_renderingManager.getHTML( context, pagedata ); |
| |
| if( runFilters ) |
| result = m_filterManager.doPostTranslateFiltering( context, result ); |
| } |
| catch( FilterException e ) |
| { |
| // FIXME: Don't yet know what to do |
| } |
| sw.stop(); |
| if( log.isDebugEnabled() ) |
| log.debug("Page "+context.getRealPage().getName()+" rendered, took "+sw ); |
| |
| return( result ); |
| } |
| |
| /** |
| * Reads a WikiPageful of data from a String and returns all links |
| * internal to this Wiki in a Collection. |
| */ |
| protected Collection scanWikiLinks( WikiPage page, String pagedata ) |
| { |
| LinkCollector localCollector = new LinkCollector(); |
| |
| textToHTML( new WikiContext(this,page), |
| pagedata, |
| localCollector, |
| null, |
| localCollector, |
| false ); |
| |
| return localCollector.getLinks(); |
| } |
| |
| /** |
| * Just convert WikiText to HTML. |
| */ |
| |
| public String textToHTML( WikiContext context, |
| String pagedata, |
| StringTransmutator localLinkHook, |
| StringTransmutator extLinkHook ) |
| { |
| return textToHTML( context, pagedata, localLinkHook, extLinkHook, null, true ); |
| } |
| |
| /** |
| * Just convert WikiText to HTML. |
| */ |
| |
| public String textToHTML( WikiContext context, |
| String pagedata, |
| StringTransmutator localLinkHook, |
| StringTransmutator extLinkHook, |
| StringTransmutator attLinkHook ) |
| { |
| return textToHTML( context, pagedata, localLinkHook, extLinkHook, attLinkHook, true ); |
| } |
| |
| /** |
| * Helper method for doing the HTML translation. |
| */ |
| private String textToHTML( WikiContext context, |
| String pagedata, |
| StringTransmutator localLinkHook, |
| StringTransmutator extLinkHook, |
| StringTransmutator attLinkHook, |
| boolean parseAccessRules ) |
| { |
| String result = ""; |
| |
| if( pagedata == null ) |
| { |
| log.error("NULL pagedata to textToHTML()"); |
| return null; |
| } |
| |
| boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true")); |
| |
| try |
| { |
| StopWatch sw = new StopWatch(); |
| sw.start(); |
| |
| if( runFilters ) |
| pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata ); |
| |
| MarkupParser mp = m_renderingManager.getParser( context, pagedata ); |
| mp.addLocalLinkHook( localLinkHook ); |
| mp.addExternalLinkHook( extLinkHook ); |
| mp.addAttachmentLinkHook( attLinkHook ); |
| |
| if( !parseAccessRules ) mp.disableAccessRules(); |
| |
| result = m_renderingManager.getHTML( context, mp.parse() ); |
| |
| if( runFilters ) |
| result = m_filterManager.doPostTranslateFiltering( context, result ); |
| |
| sw.stop(); |
| |
| if( log.isDebugEnabled() ) |
| log.debug("Page "+context.getRealPage().getName()+" rendered, took "+sw ); |
| } |
| catch( IOException e ) |
| { |
| log.error("Failed to scan page data: ", e); |
| } |
| catch( FilterException e ) |
| { |
| // FIXME: Don't yet know what to do |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Updates all references for the given page. |
| */ |
| |
| public void updateReferences( WikiPage page ) |
| { |
| String pageData = getPureText( page.getName(), WikiProvider.LATEST_VERSION ); |
| |
| m_referenceManager.updateReferences( page.getName(), |
| scanWikiLinks( page, pageData ) ); |
| } |
| |
| |
| /** |
| * Writes the WikiText of a page into the |
| * page repository. |
| * |
| * @since 2.1.28 |
| * @param context The current WikiContext |
| * @param text The Wiki markup for the page. |
| */ |
| public void saveText( WikiContext context, String text ) |
| throws WikiException |
| { |
| WikiPage page = context.getPage(); |
| |
| if( page.getAuthor() == null ) |
| { |
| Principal wup = context.getCurrentUser(); |
| |
| if( wup != null ) page.setAuthor( wup.getName() ); |
| } |
| |
| text = TextUtil.normalizePostData(text); |
| |
| text = m_filterManager.doPreSaveFiltering( context, text ); |
| |
| // Hook into cross reference collection. |
| |
| m_pageManager.putPageText( page, text ); |
| |
| // ARJ HACK: reload the page so we parse ACLs, among other things |
| /* |
| page = getPage( page.getName() ); |
| context.setPage( page ); |
| textToHTML( context, text ); |
| */ |
| m_filterManager.doPostSaveFiltering( context, text ); |
| } |
| |
| /** |
| * Returns the number of pages in this Wiki |
| */ |
| public int getPageCount() |
| { |
| return m_pageManager.getTotalPageCount(); |
| } |
| |
| /** |
| * Returns the provider name |
| */ |
| |
| public String getCurrentProvider() |
| { |
| return m_pageManager.getProvider().getClass().getName(); |
| } |
| |
| /** |
| * return information about current provider. |
| * @since 1.6.4 |
| */ |
| public String getCurrentProviderInfo() |
| { |
| return m_pageManager.getProviderDescription(); |
| } |
| |
| /** |
| * Returns a Collection of WikiPages, sorted in time |
| * order of last change. |
| */ |
| |
| // FIXME: Should really get a Date object and do proper comparisons. |
| // This is terribly wasteful. |
| public Collection getRecentChanges() |
| { |
| try |
| { |
| Collection pages = m_pageManager.getAllPages(); |
| Collection atts = m_attachmentManager.getAllAttachments(); |
| |
| TreeSet sortedPages = new TreeSet( new PageTimeComparator() ); |
| |
| sortedPages.addAll( pages ); |
| sortedPages.addAll( atts ); |
| |
| return sortedPages; |
| } |
| catch( ProviderException e ) |
| { |
| log.error( "Unable to fetch all pages: ",e); |
| return null; |
| } |
| } |
| |
| /** |
| * Parses an incoming search request, then |
| * does a search. |
| * <P> |
| * The query is dependent on the actual chosen search provider - each one of them has |
| * a language of its own. |
| */ |
| |
| // |
| // FIXME: Should also have attributes attached. |
| // |
| public Collection findPages( String query ) |
| throws ProviderException, IOException |
| { |
| Collection results = m_searchManager.findPages( query ); |
| |
| return results; |
| } |
| |
| /** |
| * Return a bunch of information from the web page. |
| */ |
| |
| public WikiPage getPage( String pagereq ) |
| { |
| return getPage( pagereq, WikiProvider.LATEST_VERSION ); |
| } |
| |
| /** |
| * Returns specific information about a Wiki page. |
| * @since 1.6.7. |
| */ |
| |
| public WikiPage getPage( String pagereq, int version ) |
| { |
| try |
| { |
| WikiPage p = m_pageManager.getPageInfo( pagereq, version ); |
| |
| if( p == null ) |
| { |
| p = m_attachmentManager.getAttachmentInfo( (WikiContext)null, pagereq ); |
| } |
| |
| return p; |
| } |
| catch( ProviderException e ) |
| { |
| log.error( "Unable to fetch page info",e); |
| return null; |
| } |
| } |
| |
| |
| /** |
| * Returns a Collection of WikiPages containing the |
| * version history of a page. |
| */ |
| |
| public List getVersionHistory( String page ) |
| { |
| List c = null; |
| |
| try |
| { |
| c = m_pageManager.getVersionHistory( page ); |
| |
| if( c == null ) |
| { |
| c = m_attachmentManager.getVersionHistory( page ); |
| } |
| } |
| catch( ProviderException e ) |
| { |
| log.error("FIXME"); |
| } |
| |
| return c; |
| } |
| |
| /** |
| * Returns a diff of two versions of a page. |
| * |
| * @param page Page to return |
| * @param version1 Version number of the old page. If |
| * WikiPageProvider.LATEST_VERSION (-1), then uses current page. |
| * @param version2 Version number of the new page. If |
| * WikiPageProvider.LATEST_VERSION (-1), then uses current page. |
| * |
| * @return A HTML-ized difference between two pages. If there is no difference, |
| * returns an empty string. |
| */ |
| public String getDiff( String page, int version1, int version2 ) |
| { |
| String page1 = getPureText( page, version1 ); |
| String page2 = getPureText( page, version2 ); |
| |
| // Kludge to make diffs for new pages to work this way. |
| |
| if( version1 == WikiPageProvider.LATEST_VERSION ) |
| { |
| page1 = ""; |
| } |
| |
| String diff = m_differenceManager.makeDiff( page1, page2 ); |
| |
| return diff; |
| } |
| |
| /** |
| * Returns this object's ReferenceManager. |
| * @since 1.6.1 |
| */ |
| // (FIXME: We may want to protect this, though...) |
| public ReferenceManager getReferenceManager() |
| { |
| return m_referenceManager; |
| } |
| |
| /** |
| * Returns the rendering manager for this wiki application. |
| * |
| * @since 2.3.27 |
| * @return A RenderingManager object. |
| */ |
| public RenderingManager getRenderingManager() |
| { |
| return m_renderingManager; |
| } |
| |
| /** |
| * Returns the current plugin manager. |
| * @since 1.6.1 |
| */ |
| |
| public PluginManager getPluginManager() |
| { |
| return m_pluginManager; |
| } |
| |
| public VariableManager getVariableManager() |
| { |
| return m_variableManager; |
| } |
| |
| /** |
| * Shortcut to getVariableManager().getValue(). However, this method does not |
| * throw a NoSuchVariableException, but returns null in case the variable does |
| * not exist. |
| * |
| * @since 2.2 |
| */ |
| public String getVariable( WikiContext context, String name ) |
| { |
| try |
| { |
| return m_variableManager.getValue( context, name ); |
| } |
| catch( NoSuchVariableException e ) |
| { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the current PageManager. |
| */ |
| public PageManager getPageManager() |
| { |
| return m_pageManager; |
| } |
| |
| /** |
| * Returns the current AttachmentManager. |
| * @since 1.9.31. |
| */ |
| public AttachmentManager getAttachmentManager() |
| { |
| return m_attachmentManager; |
| } |
| |
| /** |
| * Returns the currently used authorization manager. |
| */ |
| public AuthorizationManager getAuthorizationManager() |
| { |
| return m_authorizationManager; |
| } |
| |
| /** |
| * Returns the currently used authentication manager. |
| */ |
| public AuthenticationManager getAuthenticationManager() |
| { |
| return m_authenticationManager; |
| } |
| |
| /** |
| * Returns the manager responsible for the filters. |
| * @since 2.1.88 |
| */ |
| public FilterManager getFilterManager() |
| { |
| return m_filterManager; |
| } |
| |
| /** |
| * Returns the manager responsible for searching the Wiki. |
| * @since 2.2.21 |
| */ |
| public SearchManager getSearchManager() |
| { |
| return m_searchManager; |
| } |
| |
| /** |
| * Parses the given path and attempts to match it against the list |
| * of specialpages to see if this path exists. It is used to map things |
| * like "UserPreferences.jsp" to page "User Preferences". |
| * |
| * @return WikiName, or null if a match could not be found. |
| */ |
| private String matchSpecialPagePath( String path ) |
| { |
| // |
| // Remove servlet root marker. |
| // |
| if( path.startsWith("/") ) |
| { |
| path = path.substring(1); |
| } |
| |
| for( Iterator i = m_properties.entrySet().iterator(); i.hasNext(); ) |
| { |
| Map.Entry entry = (Map.Entry) i.next(); |
| |
| String key = (String)entry.getKey(); |
| |
| if( key.startsWith( PROP_SPECIALPAGE ) ) |
| { |
| String value = (String)entry.getValue(); |
| |
| if( value.equals( path ) ) |
| { |
| return key.substring( PROP_SPECIALPAGE.length() ); |
| } |
| } |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Figure out to which page we are really going to. Considers |
| * special page names from the jspwiki.properties, and possible aliases. |
| * |
| * @param context The Wiki Context in which the request is being made. |
| * @return A complete URL to the new page to redirect to |
| * @since 2.2 |
| */ |
| |
| public String getRedirectURL( WikiContext context ) |
| { |
| String pagename = context.getPage().getName(); |
| String redirURL = null; |
| |
| redirURL = getSpecialPageReference( pagename ); |
| |
| if( redirURL == null ) |
| { |
| String alias = (String)context.getPage().getAttribute( WikiPage.ALIAS ); |
| |
| if( alias != null ) |
| { |
| redirURL = getViewURL( alias ); |
| } |
| else |
| { |
| redirURL = (String)context.getPage().getAttribute( WikiPage.REDIRECT ); |
| } |
| } |
| |
| return redirURL; |
| } |
| |
| /** |
| * Shortcut to create a WikiContext from the Wiki page. |
| * |
| * @since 2.1.15. |
| */ |
| // FIXME: We need to have a version which takes a fixed page |
| // name as well, or check it elsewhere. |
| public WikiContext createContext( HttpServletRequest request, |
| String requestContext ) |
| { |
| String pagereq; |
| |
| if( !m_isConfigured ) |
| { |
| throw new InternalWikiException("WikiEngine has not been properly started. It is likely that the configuration is faulty. Please check all logs for the possible reason."); |
| } |
| |
| // |
| // First, set the encoding for parameter parsing. |
| // |
| try |
| { |
| request.setCharacterEncoding( getContentEncoding() ); |
| } |
| catch( UnsupportedEncodingException e ) |
| { |
| log.fatal("Someone gave us a encoding we cannot understand!"); |
| throw new InternalWikiException("Unknown encoding "+getContentEncoding()); |
| } |
| |
| try |
| { |
| pagereq = m_urlConstructor.parsePage( requestContext, |
| request, |
| getContentEncoding() ); |
| } |
| catch( IOException e ) |
| { |
| log.error("Unable to create context",e); |
| throw new InternalWikiException("Big internal booboo, please check logs."); |
| } |
| |
| String template = request.getParameter( "skin" ); |
| |
| // |
| // Figure out the page name. |
| // We also check the list of special pages, which incidentally |
| // allows us to localize them, too. |
| // |
| |
| if( pagereq == null || pagereq.length() == 0 ) |
| { |
| String servlet = request.getServletPath(); |
| log.debug("Servlet path is: "+servlet); |
| |
| pagereq = matchSpecialPagePath( servlet ); |
| |
| log.debug("Mapped to "+pagereq); |
| if( pagereq == null ) |
| { |
| pagereq = getFrontPage(); |
| } |
| } |
| |
| int hashMark = pagereq.indexOf('#'); |
| |
| if( hashMark != -1 ) |
| { |
| pagereq = pagereq.substring( 0, hashMark ); |
| } |
| |
| int version = WikiProvider.LATEST_VERSION; |
| String rev = request.getParameter("version"); |
| |
| if( rev != null ) |
| { |
| version = Integer.parseInt( rev ); |
| } |
| |
| // |
| // Find the WikiPage object |
| // |
| String pagename = pagereq; |
| WikiPage wikipage; |
| |
| try |
| { |
| pagename = getFinalPageName( pagereq ); |
| } |
| catch( ProviderException e ) {} // FIXME: Should not ignore! |
| |
| if( pagename != null ) |
| { |
| wikipage = getPage( pagename, version ); |
| } |
| else |
| { |
| wikipage = getPage( pagereq, version ); |
| } |
| |
| if( wikipage == null ) |
| { |
| pagereq = MarkupParser.cleanLink( pagereq ); |
| wikipage = new WikiPage( this, pagereq ); |
| } |
| |
| // |
| // Figure out which template we should be using for this page. |
| // |
| if( template == null ) |
| { |
| template = (String)wikipage.getAttribute( PROP_TEMPLATEDIR ); |
| |
| // FIXME: Most definitely this should be checked for |
| // existence, or else it is possible to create pages that |
| // cannot be shown. |
| |
| if( template == null || template.length() == 0 ) |
| { |
| template = getTemplateDir(); |
| } |
| } |
| |
| WikiContext context = new WikiContext( this, |
| request, |
| wikipage ); |
| context.setRequestContext( requestContext ); |
| context.setTemplate( template ); |
| |
| return context; |
| } |
| |
| /** |
| * Deletes a page or an attachment completely, including all versions. |
| * |
| * @param pageName |
| * @throws ProviderException |
| */ |
| public void deletePage( String pageName ) |
| throws ProviderException |
| { |
| WikiPage p = getPage( pageName ); |
| |
| if( p instanceof Attachment ) |
| { |
| m_attachmentManager.deleteAttachment( (Attachment) p ); |
| } |
| else |
| { |
| if (m_attachmentManager.hasAttachments( p )) |
| { |
| Collection attachments = m_attachmentManager.listAttachments( p ); |
| for( Iterator atti = attachments.iterator(); atti.hasNext(); ) |
| { |
| m_attachmentManager.deleteAttachment( (Attachment)(atti.next()) ); |
| } |
| |
| } |
| m_pageManager.deletePage( p ); |
| } |
| } |
| |
| /** |
| * Deletes a specific version of a page or an attachment. |
| * |
| * @param page |
| * @throws ProviderException |
| */ |
| public void deleteVersion( WikiPage page ) |
| throws ProviderException |
| { |
| if( page instanceof Attachment ) |
| { |
| m_attachmentManager.deleteVersion( (Attachment) page ); |
| } |
| else |
| { |
| m_pageManager.deleteVersion( page ); |
| } |
| } |
| |
| /** |
| * Returns the URL of the global RSS file. May be null, if the |
| * RSS file generation is not operational. |
| * @since 1.7.10 |
| */ |
| public String getGlobalRSSURL() |
| { |
| if( m_rssURL != null ) |
| { |
| return getBaseURL()+m_rssURL; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * @since 2.2 |
| */ |
| public String getRootPath() |
| { |
| return m_rootPath; |
| } |
| |
| /** |
| * @since 2.2.6 |
| * @return the URL constructor |
| */ |
| public URLConstructor getURLConstructor() |
| { |
| return m_urlConstructor; |
| } |
| |
| /** |
| * @since 2.1.165 |
| * @return the RSS generator |
| */ |
| public RSSGenerator getRSSGenerator() |
| { |
| return m_rssGenerator; |
| } |
| |
| /** |
| * Runs the RSS generation thread. |
| * FIXME: MUST be somewhere else, this is not a good place. |
| */ |
| private class RSSThread extends Thread |
| { |
| public void run() |
| { |
| setName("JSPWiki Global RSS generator thread"); |
| try |
| { |
| String fileName = TextUtil.getStringProperty( m_properties, |
| RSSGenerator.PROP_RSSFILE, |
| "rss.rdf" ); |
| int rssInterval = TextUtil.getIntegerProperty( m_properties, |
| RSSGenerator.PROP_INTERVAL, |
| 3600 ); |
| |
| log.debug("RSS file will be at "+fileName); |
| log.debug("RSS refresh interval (seconds): "+rssInterval); |
| |
| while(true) |
| { |
| Writer out = null; |
| Reader in = null; |
| |
| try |
| { |
| // |
| // Generate RSS file, output it to |
| // default "rss.rdf". |
| // |
| log.debug("Regenerating RSS feed to "+fileName); |
| |
| String feed = m_rssGenerator.generate(); |
| |
| File file = new File( m_rootPath, fileName ); |
| |
| in = new StringReader(feed); |
| out = new BufferedWriter( new OutputStreamWriter( new FileOutputStream(file), "UTF-8") ); |
| |
| FileUtil.copyContents( in, out ); |
| |
| m_rssURL = fileName; |
| } |
| catch( IOException e ) |
| { |
| log.error("Cannot generate RSS feed to "+fileName, e ); |
| m_rssURL = null; |
| } |
| finally |
| { |
| try |
| { |
| if( in != null ) in.close(); |
| if( out != null ) out.close(); |
| } |
| catch( IOException e ) |
| { |
| log.fatal("Could not close I/O for RSS", e ); |
| break; |
| } |
| } |
| |
| Thread.sleep(rssInterval*1000L); |
| } // while |
| |
| } |
| catch(InterruptedException e) |
| { |
| log.error("RSS thread interrupted, no more RSS feeds", e); |
| } |
| |
| // |
| // Signal: no more RSS feeds. |
| // |
| m_rssURL = null; |
| } |
| } |
| |
| /** |
| * Renames, or moves, a wiki page. Can also alter referring wiki |
| * links to point to the renamed page. |
| * |
| * @param renameFrom Name of the source page. |
| * @param renameTo Name of the destination page. |
| * @param changeReferrers If true, then changes any referring links |
| * to point to the renamed page. |
| * |
| * @return The name of the page that the source was renamed to. |
| * |
| * @throws WikiException In the case of an error, such as the destination |
| * page already existing. |
| */ |
| public String renamePage( String renameFrom, |
| String renameTo, |
| boolean changeReferrers) |
| throws WikiException |
| { |
| return m_pageRenamer.renamePage(renameFrom, renameTo, changeReferrers); |
| } |
| |
| /** |
| * Returns the UserDatabase employed by this WikiEngine. |
| * The UserDatabase is lazily initialized. |
| * @since 2.3 |
| */ |
| |
| /** |
| * Returns the UserManager employed by this WikiEngine. |
| * @since 2.3 |
| */ |
| public UserManager getUserManager() |
| { |
| return m_userManager; |
| } |
| |
| // FIXME: Must not throw RuntimeException, but something else. |
| public UserDatabase getUserDatabase() |
| { |
| return m_userManager.getUserDatabase(); |
| } |
| |
| /** |
| * Returns the GroupManager employed by this WikiEngine. |
| * The GroupManager is lazily initialized. |
| * @since 2.3 |
| */ |
| public GroupManager getGroupManager() |
| { |
| return m_userManager.getGroupManager(); |
| } |
| |
| /** |
| * Returns the AclManager employed by this WikiEngine. |
| * The AclManager is lazily initialized. |
| * @since 2.3 |
| */ |
| public AclManager getAclManager() |
| { |
| if (m_aclManager == null) { |
| // TODO: make this pluginizable |
| m_aclManager = new DefaultAclManager(); |
| m_aclManager.initialize( this, m_properties ); |
| } |
| return m_aclManager; |
| } |
| |
| public EditorManager getEditorManager() |
| { |
| return m_editorManager; |
| } |
| } |