blob: 836e10dc5011d8bf532cb5be1c928ff4508ea0ca [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.wiki;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.wiki.api.engine.AdminBeanManager;
import org.apache.wiki.api.engine.FilterManager;
import org.apache.wiki.api.engine.PluginManager;
import org.apache.wiki.api.exceptions.FilterException;
import org.apache.wiki.api.exceptions.ProviderException;
import org.apache.wiki.api.exceptions.WikiException;
import org.apache.wiki.attachment.Attachment;
import org.apache.wiki.attachment.AttachmentManager;
import org.apache.wiki.auth.AuthenticationManager;
import org.apache.wiki.auth.AuthorizationManager;
import org.apache.wiki.auth.UserManager;
import org.apache.wiki.auth.acl.AclManager;
import org.apache.wiki.auth.authorize.GroupManager;
import org.apache.wiki.content.PageRenamer;
import org.apache.wiki.diff.DifferenceManager;
import org.apache.wiki.event.WikiEngineEvent;
import org.apache.wiki.event.WikiEventListener;
import org.apache.wiki.event.WikiEventManager;
import org.apache.wiki.event.WikiPageEvent;
import org.apache.wiki.i18n.InternationalizationManager;
import org.apache.wiki.pages.PageManager;
import org.apache.wiki.pages.PageTimeComparator;
import org.apache.wiki.parser.MarkupParser;
import org.apache.wiki.parser.WikiDocument;
import org.apache.wiki.providers.WikiPageProvider;
import org.apache.wiki.references.ReferenceManager;
import org.apache.wiki.render.RenderingManager;
import org.apache.wiki.rss.RSSGenerator;
import org.apache.wiki.rss.RSSThread;
import org.apache.wiki.search.SearchManager;
import org.apache.wiki.tasks.TasksManager;
import org.apache.wiki.ui.Command;
import org.apache.wiki.ui.CommandResolver;
import org.apache.wiki.ui.EditorManager;
import org.apache.wiki.ui.TemplateManager;
import org.apache.wiki.ui.progress.ProgressManager;
import org.apache.wiki.url.URLConstructor;
import org.apache.wiki.util.ClassUtil;
import org.apache.wiki.util.PropertyReader;
import org.apache.wiki.util.TextUtil;
import org.apache.wiki.variables.VariableManager;
import org.apache.wiki.workflow.Decision;
import org.apache.wiki.workflow.DecisionRequiredException;
import org.apache.wiki.workflow.Fact;
import org.apache.wiki.workflow.Step;
import org.apache.wiki.workflow.Workflow;
import org.apache.wiki.workflow.WorkflowBuilder;
import org.apache.wiki.workflow.WorkflowManager;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
/**
* 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.
*/
public class WikiEngine {
private static final String ATTR_WIKIENGINE = "org.apache.wiki.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 default inlining pattern. Currently "*.png" */
public static final String DEFAULT_INLINEPATTERN = "*.png";
/** The name used for the default template. The value is {@value}. */
public static final String DEFAULT_TEMPLATE_NAME = "default";
/** Property for application name */
public static final String PROP_APPNAME = "jspwiki.applicationName";
/** This property defines the inline image pattern. It's current value is {@value} */
public static final String PROP_INLINEIMAGEPTRN = "jspwiki.translatorReader.inlinePattern";
/** 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";
/** Do not use encoding in WikiJSPFilter, default is false for most servers.
Double negative, cause for most servers you don't need the property */
public static final String PROP_NO_FILTER_ENCODING = "jspwiki.nofilterencoding";
/** The name for the property which allows you to set the current reference style. The value is {@value}. */
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";
/** If this property is set to false, all filters are disabled when translating. */
public static final String PROP_RUNFILTERS = "jspwiki.runFilters";
/** Does the work in renaming pages. */
private PageRenamer m_pageRenamer = null;
/** The name of the property containing the ACLManager implementing class. The value is {@value}. */
public static final String PROP_ACL_MANAGER_IMPL = "jspwiki.aclManager";
/** If this property is set to false, we don't allow the creation of empty pages */
public static final String PROP_ALLOW_CREATION_OF_EMPTY_PAGES = "jspwiki.allowCreationOfEmptyPages";
/** 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;
/** 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;
/** Resolves wiki actions, JSPs and special pages. */
private CommandResolver m_commandResolver = 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;
/** Facade for managing users */
private UserManager m_userManager = null;
/** Facade for managing users */
private GroupManager m_groupManager = null;
private RenderingManager m_renderingManager;
private EditorManager m_editorManager;
private InternationalizationManager m_internationalizationManager;
private ProgressManager m_progressManager;
private TasksManager m_tasksManager;
/** Constructs URLs */
private URLConstructor m_urlConstructor;
/** Generates RSS feed when requested. */
private RSSGenerator m_rssGenerator;
/** The RSS file to generate. */
private String m_rssFile;
/** 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.
/** Each engine has its own workflow manager. */
private WorkflowManager m_workflowMgr = null;
private AdminBeanManager m_adminBeanManager;
/** Stores wikiengine attributes. */
private Map<String,Object> m_attributes = new ConcurrentHashMap<>();
/**
* 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).
*
* @return One well-behaving WikiEngine instance.
*/
public static synchronized WikiEngine getInstance( ServletConfig config,
Properties props )
{
return getInstance( config.getServletContext(), props );
}
/**
* 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).
*
* @return One fully functional, properly behaving WikiEngine.
* @throws InternalWikiException If the WikiEngine instantiation fails.
*/
// 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
{
WikiEngine engine = (WikiEngine) context.getAttribute( ATTR_WIKIENGINE );
if( engine == null )
{
String appid = Integer.toString(context.hashCode()); //FIXME: Kludge, use real type.
context.log(" Assigning new engine to "+appid);
try
{
if( props == null )
{
props = PropertyReader.loadWebAppProps( context );
}
engine = new WikiEngine( context, appid, props );
context.setAttribute( ATTR_WIKIENGINE, engine );
}
catch( Exception e )
{
context.log( "ERROR: Failed to create a Wiki engine: "+e.getMessage() );
log.error( "ERROR: Failed to create a Wiki engine, stacktrace follows " , e);
throw new InternalWikiException( "No wiki engine, check logs." , e);
}
}
return engine;
}
/**
* Instantiate the WikiEngine using a given set of properties.
* Use this constructor for testing purposes only.
*
* @param properties A set of properties to use to initialize this WikiEngine.
* @throws WikiException If the initialization fails.
*/
public WikiEngine( Properties properties )
throws WikiException
{
initialize( properties );
}
/**
* 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.
*
* @param context A ServletContext.
* @param appid An Application ID. This application is an unique random string which
* is used to recognize this WikiEngine.
* @param props The WikiEngine configuration.
* @throws WikiException If the WikiEngine construction fails.
*/
protected WikiEngine( ServletContext context, String appid, Properties props )
throws WikiException
{
super();
m_servletContext = context;
m_appid = appid;
// Stash the WikiEngine in the servlet context
if ( context != null )
{
context.setAttribute( ATTR_WIKIENGINE, this );
m_rootPath = context.getRealPath("/");
}
try
{
//
// Note: May be null, if JSPWiki has been deployed in a WAR file.
//
initialize( props );
log.info("Root path for this Wiki is: '"+m_rootPath+"'");
}
catch( Exception e )
{
String msg = Release.APPNAME+": Unable to load and setup properties from jspwiki.properties. "+e.getMessage();
if ( context != null )
{
context.log( msg );
}
throw new WikiException( msg, e );
}
}
/**
* Does all the real initialization.
*/
private void initialize( Properties props )
throws WikiException
{
m_startTime = new Date();
m_properties = props;
//
// Initialize log4j. However, make sure that we don't initialize it multiple times.
// By default we load the log4j config statements from jspwiki.properties, unless
// the property jspwiki.use.external.logconfig=true, in that case we let log4j figure out the
// logging configuration.
//
if( !c_configured )
{
String useExternalLogConfig = TextUtil.getStringProperty(props,"jspwiki.use.external.logconfig","false");
if( useExternalLogConfig == null || useExternalLogConfig.equals("false"))
{
PropertyConfigurator.configure( props );
}
c_configured = true;
}
log.info("*******************************************");
log.info(Release.APPNAME+" "+Release.getVersionString()+" starting. Whee!");
fireEvent( WikiEngineEvent.INITIALIZING ); // begin initialization
log.debug("Java version: "+System.getProperty("java.runtime.version"));
log.debug("Java vendor: "+System.getProperty("java.vm.vendor"));
log.debug("OS: "+System.getProperty("os.name")+" "+System.getProperty("os.version")+" "+System.getProperty("os.arch"));
log.debug("Default server locale: "+Locale.getDefault());
log.debug("Default server timezone: "+TimeZone.getDefault().getDisplayName(true, TimeZone.LONG));
if( m_servletContext != null )
{
log.info("Servlet container: "+m_servletContext.getServerInfo() );
if( m_servletContext.getMajorVersion() < 2 ||
(m_servletContext.getMajorVersion() == 2 && m_servletContext.getMinorVersion() < 4) )
{
throw new InternalWikiException("I require a container which supports at least version 2.4 of Servlet specification");
}
}
log.debug("Configuring WikiEngine...");
// Initializes the CommandResolver
m_commandResolver = new CommandResolver( this, props );
//
// 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, e );
}
log.info("JSPWiki working directory is '"+m_workDir+"'");
m_saveUserInfo = TextUtil.getBooleanProperty( props, PROP_STOREUSERNAME, m_saveUserInfo );
m_useUTF8 = StandardCharsets.UTF_8.name().equals( TextUtil.getStringProperty( props, PROP_ENCODING, StandardCharsets.ISO_8859_1.name() ) );
m_beautifyTitle = TextUtil.getBooleanProperty( props, PROP_BEAUTIFYTITLE, m_beautifyTitle );
m_templateDir = TextUtil.getStringProperty( props, PROP_TEMPLATEDIR, "default" );
enforceValidTemplateDirectory();
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.
//
// FIXME: This part of the code is getting unwieldy. We must think
// of a better way to do the startup-sequence.
try
{
Class< ? > urlclass = ClassUtil.findClass( "org.apache.wiki.url",
TextUtil.getStringProperty( props, PROP_URLCONSTRUCTOR, "DefaultURLConstructor" ) );
m_urlConstructor = (URLConstructor) urlclass.getDeclaredConstructor().newInstance();
m_urlConstructor.initialize( this, props );
m_pageManager = ClassUtil.getMappedObject( PageManager.class.getName(), this, props );
m_pluginManager = ClassUtil.getMappedObject( PluginManager.class.getName(), this, props );
m_differenceManager = ClassUtil.getMappedObject( DifferenceManager.class.getName(), this, props );
m_attachmentManager = ClassUtil.getMappedObject( AttachmentManager.class.getName(), this, props );
m_variableManager = ClassUtil.getMappedObject( VariableManager.class.getName(), props );
m_renderingManager = ClassUtil.getMappedObject( RenderingManager.class.getName() );
m_searchManager = ClassUtil.getMappedObject( SearchManager.class.getName(), this, props );
m_authenticationManager = ClassUtil.getMappedObject( AuthenticationManager.class.getName() );
m_authorizationManager = ClassUtil.getMappedObject( AuthorizationManager.class.getName() );
m_userManager = ClassUtil.getMappedObject( UserManager.class.getName() );
m_groupManager = ClassUtil.getMappedObject( GroupManager.class.getName() );
m_editorManager = ClassUtil.getMappedObject( EditorManager.class.getName(), this );
m_editorManager.initialize( props );
m_progressManager = new ProgressManager();
// 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.initialize( this, props );
m_aclManager = getAclManager();
// Start the Workflow manager
m_workflowMgr = ClassUtil.getMappedObject(WorkflowManager.class.getName());
m_workflowMgr.initialize(this, props);
m_tasksManager = ClassUtil.getMappedObject(TasksManager.class.getName());
m_internationalizationManager = ClassUtil.getMappedObject(InternationalizationManager.class.getName(),this);
m_templateManager = ClassUtil.getMappedObject(TemplateManager.class.getName(), this, props );
// Since we want to use a page filters initilize() method
// as a engine startup listener where we can initialize global event listeners,
// it must be called lastly, so that all object references in the engine
// are availabe to the initialize() method
m_filterManager = ClassUtil.getMappedObject(FilterManager.class.getName(), this, props );
m_adminBeanManager = ClassUtil.getMappedObject(AdminBeanManager.class.getName(),this);
// RenderingManager depends on FilterManager events.
m_renderingManager.initialize( this, props );
//
// ReferenceManager has the side effect of loading all
// pages. Therefore after this point, all page attributes
// are available.
//
// initReferenceManager is indirectly using m_filterManager, therefore
// it has to be called after it was initialized.
//
initReferenceManager();
//
// Hook the different manager routines into the system.
//
m_filterManager.addPageFilter(m_referenceManager, -1001 );
m_filterManager.addPageFilter(m_searchManager, -1002 );
}
catch( RuntimeException 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(), e );
}
catch (ClassNotFoundException e)
{
log.fatal( "JSPWiki could not start, URLConstructor was not found: " + e.getMessage(), e );
throw new WikiException(e.getMessage(), e );
}
catch (InstantiationException e)
{
log.fatal( "JSPWiki could not start, URLConstructor could not be instantiated: " + e.getMessage(), e );
throw new WikiException(e.getMessage(), e );
}
catch (IllegalAccessException e)
{
log.fatal( "JSPWiki could not start, URLConstructor cannot be accessed: " + e.getMessage(), e );
throw new WikiException(e.getMessage(), e );
}
catch( Exception e )
{
// Final catch-all for everything
log.fatal( "JSPWiki could not start, due to an unknown exception when starting.",e );
throw new WikiException( "Failed to start. Caused by: " + e.getMessage() +
"; please check log files for better information.", e );
}
//
// Initialize the good-to-have-but-not-fatal modules.
//
try {
if( TextUtil.getBooleanProperty( props, RSSGenerator.PROP_GENERATE_RSS,false ) ) {
m_rssGenerator = ClassUtil.getMappedObject( RSSGenerator.class.getName(), this, props );
}
m_pageRenamer = ClassUtil.getMappedObject( PageRenamer.class.getName(), this, props );
} catch( final Exception e ) {
log.error( "Unable to start RSS generator - JSPWiki will still work, but there will be no RSS feed.", e );
}
// Start the RSS generator & generator thread
if( m_rssGenerator != null )
{
m_rssFile = TextUtil.getStringProperty( props,
RSSGenerator.PROP_RSSFILE, "rss.rdf" );
File rssFile=null;
if (m_rssFile.startsWith(File.separator))
{
// honor absolute pathnames:
rssFile = new File(m_rssFile );
}
else
{
// relative path names are anchored from the webapp root path:
rssFile = new File( getRootPath(), m_rssFile );
}
int rssInterval = TextUtil.getIntegerProperty( props,
RSSGenerator.PROP_INTERVAL, 3600 );
RSSThread rssThread = new RSSThread( this, rssFile, rssInterval );
rssThread.start();
}
fireEvent( WikiEngineEvent.INITIALIZED ); // initialization complete
log.info("WikiEngine configured.");
m_isConfigured = true;
}
/**
* Checks if the template directory specified in the wiki's properties actually exists. If it doesn't, then {@code m_templateDir} is
* set to {@link #DEFAULT_TEMPLATE_NAME}.
* <p>
* This checks the existence of the <tt>ViewTemplate.jsp</tt> file, which exists in every template using {@code m_servletContext.getRealPath("/")}.
* <p>
* {@code m_servletContext.getRealPath("/")} can return {@code null} on certain servers/conditions (f.ex, packed wars), an extra check
* against {@code m_servletContext.getResource} is made.
*/
void enforceValidTemplateDirectory() {
if( m_servletContext != null ) {
final String viewTemplate = "templates" + File.separator + getTemplateDir() + File.separator + "ViewTemplate.jsp";
boolean exists = new File( m_servletContext.getRealPath("/") + viewTemplate ).exists();
if( !exists ) {
try {
URL url = m_servletContext.getResource( viewTemplate );
exists = url != null && StringUtils.isNotEmpty( url.getFile() );
} catch( MalformedURLException e ) {
exists = false;
}
}
if( !exists ) {
log.warn( getTemplateDir() + " template not found, updating WikiEngine's default template to " + DEFAULT_TEMPLATE_NAME );
m_templateDir = DEFAULT_TEMPLATE_NAME;
}
}
}
/**
* Initializes the reference manager. Scans all existing WikiPages for
* internal links and adds them to the ReferenceManager object.
*
* @throws WikiException If the reference manager initialization fails.
*/
public void initReferenceManager() throws WikiException {
try {
ArrayList<WikiPage> 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 = ClassUtil.getMappedObject(ReferenceManager.class.getName(), this );
m_referenceManager.initialize( pages );
}
} catch( ProviderException e ) {
log.fatal("PageProvider is unable to list pages: ", e);
} catch( ReflectiveOperationException | IllegalArgumentException e ) {
throw new WikiException( "Could not instantiate ReferenceManager: " + e.getMessage(), e );
}
}
/**
* Returns the set of properties that the WikiEngine was initialized
* with. Note that this method returns a direct reference, so it's possible
* to manipulate the properties. However, this is not advised unless you
* really know what you're doing.
*
* @return The wiki properties
*/
public Properties getWikiProperties()
{
return m_properties;
}
/**
* Returns the JSPWiki working directory set with "jspwiki.workDir".
*
* @since 2.1.100
* @return The working directory.
*/
public String getWorkDir()
{
return m_workDir;
}
/**
* Returns the current template directory.
*
* @since 1.9.20
* @return The template directory as initialized by the engine.
*/
public String getTemplateDir()
{
return m_templateDir;
}
/**
* Returns the current TemplateManager.
*
* @return A TemplateManager instance.
*/
public TemplateManager getTemplateManager()
{
return m_templateManager;
}
/**
* Returns the base URL, telling where this Wiki actually lives.
*
* @since 1.6.1
* @return The Base URL.
*/
public String getBaseURL() {
return m_servletContext.getContextPath();
}
/**
* Returns the moment when this engine was started.
*
* @since 2.0.15.
* @return The start time of this wiki.
*/
public Date getStartTime()
{
return (Date)m_startTime.clone();
}
/**
* <p>
* Returns the basic absolute URL to a page, without any modifications. You
* may add any parameters to this.
* </p>
* <p>
* Since 2.3.90 it is safe to call this method with <code>null</code>
* pageName, in which case it will default to the front page.
* </p>
* @since 2.0.3
* @param pageName The name of the page. May be null, in which case defaults to the front page.
* @return An absolute URL to the page.
*/
public String getViewURL( String pageName ) {
if( pageName == null ) {
pageName = getFrontPage();
}
return getURLConstructor().makeURL( WikiContext.VIEW, pageName, "absolute".equals( PROP_REFSTYLE ), 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.
* @return An URL (absolute or relative).
*/
public String getURL( final String context, String pageName, final String params, final boolean absolute ) {
if( pageName == null ) {
pageName = getFrontPage();
}
return m_urlConstructor.makeURL( context, pageName, absolute, params );
}
/**
* Returns the default front page, if no page is used.
*
* @return The front page name.
*/
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;
}
/**
* Returns an URL to some other Wiki that we know.
*
* @param wikiName The name of the other wiki.
* @return null, if no such reference was found.
*/
public String getInterWikiURL( final String wikiName )
{
return TextUtil.getStringProperty(m_properties,PROP_INTERWIKIREF+wikiName,null);
}
/**
* Returns a collection of all supported InterWiki links.
*
* @return A Collection of Strings.
*/
public Collection< String > getAllInterWikiLinks()
{
ArrayList< String > list = new ArrayList< >();
for( Enumeration< ? > i = m_properties.propertyNames(); i.hasMoreElements(); )
{
String prop = ( String )i.nextElement();
if( prop.startsWith( PROP_INTERWIKIREF ) )
{
list.add( prop.substring( prop.lastIndexOf( "." ) + 1 ) );
}
}
return list;
}
/**
* Returns a collection of all image types that get inlined.
*
* @return A Collection of Strings with a regexp pattern.
*/
public Collection< String > getAllInlinedImagePatterns()
{
Properties props = getWikiProperties();
ArrayList<String> ptrnlist = new ArrayList<>();
for( Enumeration< ? > e = props.propertyNames(); e.hasMoreElements(); )
{
String name = ( String )e.nextElement();
if( name.startsWith( PROP_INLINEIMAGEPTRN ) )
{
String ptrn = TextUtil.getStringProperty( props, name, null );
ptrnlist.add( ptrn );
}
}
if( ptrnlist.size() == 0 )
{
ptrnlist.add( DEFAULT_INLINEPATTERN );
}
return ptrnlist;
}
/**
* <p>If the page is a special page, then returns a direct URL
* to that page. Otherwise returns <code>null</code>.
* This method delegates requests to
* {@link org.apache.wiki.ui.CommandResolver#getSpecialPageReference(String)}.
* </p>
* <p>
* Special pages are defined in jspwiki.properties using the jspwiki.specialPage
* setting. They're typically used to give Wiki page names to e.g. custom JSP
* pages.
* </p>
*
* @param original The page to check
* @return A reference to the page, or null, if there's no special page.
*/
public String getSpecialPageReference( String original )
{
return m_commandResolver.getSpecialPageReference( original );
}
/**
* Returns the name of the application.
*
* @return A string describing the name of this 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 MarkupParser.cleanLink( 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 only beautified by
* the name.
*
* @param title The title to beautify
* @return A beautified title (or, if beautification is off,
* returns the title without modification)
* @since 1.7.11
*/
public String beautifyTitle( String title )
{
if( m_beautifyTitle )
{
try
{
Attachment att = m_attachmentManager.getAttachmentInfo(title);
if(att == null)
{
return TextUtil.beautifyString( title );
}
String parent = TextUtil.beautifyString( att.getParentName() );
return parent + "/" + att.getFileName();
}
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 &amp;nbsp; -character.
*
* @param title The title to beautify
* @return A beautified title.
* @since 2.1.127
*/
public String beautifyTitleNoBreak( String title )
{
if( m_beautifyTitle )
{
return TextUtil.beautifyString( title, "&nbsp;" );
}
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.
* @return true, if page (or attachment) exists.
*/
public boolean pageExists( String page )
{
Attachment att = null;
try
{
if( m_commandResolver.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
* @param version Page version
* @return True, if page (or alias, or attachment) exists
* @throws ProviderException If the provider fails.
*/
public boolean pageExists( String page, int version )
throws ProviderException
{
if( m_commandResolver.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.
*
* @param page A WikiPage object describing the name and version.
* @return true, if the page (or alias, or attachment) exists.
* @throws ProviderException If something goes badly wrong.
* @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. This
* method simply delegates to
* {@link org.apache.wiki.ui.CommandResolver#getFinalPageName(String)}.
* @since 2.0
* @param page Page name.
* @return The rewritten page name, or null, if the page does not exist.
* @throws ProviderException If something goes wrong in the backend.
*/
public String getFinalPageName( String page )
throws ProviderException
{
return m_commandResolver.getFinalPageName( page );
}
/**
* Turns a WikiName into something that can be
* called through using an URL.
*
* @since 1.4.1
* @param pagename A name. Can be actually any string.
* @return A properly encoded name.
* @see #decodeName(String)
*/
public String encodeName( String pagename )
{
try
{
return URLEncoder.encode( pagename, m_useUTF8 ? "UTF-8" : "ISO-8859-1" );
}
catch( UnsupportedEncodingException e )
{
throw new InternalWikiException( "ISO-8859-1 not a supported encoding!?! Your platform is borked." , e);
}
}
/**
* Decodes a URL-encoded request back to regular life. This properly heeds
* the encoding as defined in the settings file.
*
* @param pagerequest The URL-encoded string to decode
* @return A decoded string.
* @see #encodeName(String)
*/
public String decodeName( final String pagerequest ) {
try {
return URLDecoder.decode( 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.", e);
}
}
/**
* Returns the IANA name of the character set encoding we're
* supposed to be using right now.
*
* @since 1.5.3
* @return The content encoding (either UTF-8 or ISO-8859-1).
*/
public Charset getContentEncoding() {
if( m_useUTF8 ) {
return StandardCharsets.UTF_8;
}
return StandardCharsets.ISO_8859_1;
}
/**
* Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this
* WikiEngine. If the WIkiEngine has not been initialized, this method will return
* <code>null</code>.
* @return the task queue
*/
public WorkflowManager getWorkflowManager()
{
return m_workflowMgr;
}
/**
* Returns the un-HTMLized text of the latest version of a page.
* This method also replaces the &lt; and &amp; -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 &lt; and &amp; -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 &quot; etc.
//
/*
result = TextUtil.replaceString( result, "&", "&amp;" );
*/
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 &lt; and &amp; -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.
* @param context The WikiContext
* @param page A page reference (not an attachment)
* @return The page content as HTMLized String.
* @see #getPureText(WikiPage)
*/
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( final WikiPage page )
{
return getPureText( page.getName(), page.getVersion() );
}
/**
* Returns the converted HTML of the page using a different
* context than the default context.
*
* @param context A WikiContext in which you wish to render this page in.
* @param page WikiPage reference.
* @return HTML-rendered version of the page.
*/
public String getHTML( final WikiContext context, final WikiPage page ) {
final String pagedata = getPureText( page.getName(), page.getVersion() );
return textToHTML( context, pagedata );
}
/**
* Returns the converted HTML of the page.
*
* @param page WikiName of the page to convert.
* @return HTML-rendered version of the page.
*/
public String getHTML( final 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
* @return HTML-rendered page text.
*/
public String getHTML( final String pagename, final int version ) {
final WikiPage page = getPage( pagename, version );
final WikiContext context = new WikiContext( this, page );
context.setRequestContext( WikiContext.NONE );
return getHTML( context, page );
}
/**
* Converts raw page data to HTML.
*
* @param pagedata Raw page data to convert to HTML
* @param context The WikiContext in which the page is to be rendered
* @return Rendered page text
*/
public String textToHTML( final WikiContext context, String pagedata ) {
String result = "";
final boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true"));
final 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( final FilterException e ) {
log.error( "page filter threw exception: ", 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;
}
/**
* Protected method that signals that the WikiEngine will be shut down by the servlet container. It is called by
* {@link WikiServlet#destroy()}. When this method is called, it fires a "shutdown" WikiEngineEvent to all registered listeners.
*/
protected void shutdown() {
fireEvent( WikiEngineEvent.SHUTDOWN );
m_filterManager.destroy();
}
/**
* Just convert WikiText to HTML.
*
* @param context The WikiContext in which to do the conversion
* @param pagedata The data to render
* @param localLinkHook Is called whenever a wiki link is found
* @param extLinkHook Is called whenever an external link is found
*
* @return HTML-rendered page text.
*/
public String textToHTML( final WikiContext context,
final String pagedata,
final StringTransmutator localLinkHook,
final StringTransmutator extLinkHook ) {
return textToHTML( context, pagedata, localLinkHook, extLinkHook, null, true, false );
}
/**
* Just convert WikiText to HTML.
*
* @param context The WikiContext in which to do the conversion
* @param pagedata The data to render
* @param localLinkHook Is called whenever a wiki link is found
* @param extLinkHook Is called whenever an external link is found
* @param attLinkHook Is called whenever an attachment link is found
* @return HTML-rendered page text.
*/
public String textToHTML( final WikiContext context,
final String pagedata,
final StringTransmutator localLinkHook,
final StringTransmutator extLinkHook,
final StringTransmutator attLinkHook ) {
return textToHTML( context, pagedata, localLinkHook, extLinkHook, attLinkHook, true, false );
}
/**
* Helper method for doing the HTML translation.
*
* @param context The WikiContext in which to do the conversion
* @param pagedata The data to render
* @param localLinkHook Is called whenever a wiki link is found
* @param extLinkHook Is called whenever an external link is found
* @param parseAccessRules Parse the access rules if we encounter them
* @param justParse Just parses the pagedata, does not actually render. In this case, this methods an empty string.
* @return HTML-rendered page text.
*/
public String textToHTML( final WikiContext context,
String pagedata,
final StringTransmutator localLinkHook,
final StringTransmutator extLinkHook,
final StringTransmutator attLinkHook,
final boolean parseAccessRules,
final boolean justParse ) {
String result = "";
if( pagedata == null ) {
log.error("NULL pagedata to textToHTML()");
return null;
}
final boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true"));
try {
final StopWatch sw = new StopWatch();
sw.start();
if( runFilters && m_filterManager != null ) {
pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata );
}
final MarkupParser mp = m_renderingManager.getParser( context, pagedata );
mp.addLocalLinkHook( localLinkHook );
mp.addExternalLinkHook( extLinkHook );
mp.addAttachmentLinkHook( attLinkHook );
if( !parseAccessRules ) {
mp.disableAccessRules();
}
final WikiDocument doc = mp.parse();
// In some cases it's better just to parse, not to render
if( !justParse ) {
result = m_renderingManager.getHTML( context, doc );
if( runFilters && m_filterManager != null ) {
result = m_filterManager.doPostTranslateFiltering( context, result );
}
}
sw.stop();
if( log.isDebugEnabled() ) {
log.debug( "Page " + context.getRealPage().getName() + " rendered, took " + sw );
}
} catch( final IOException e ) {
log.error( "Failed to scan page data: ", e );
} catch( final FilterException e ) {
log.error( "page filter threw exception: ", e );
// FIXME: Don't yet know what to do
}
return result;
}
/**
* Writes the WikiText of a page into the page repository. If the <code>jspwiki.properties</code> file contains
* the property <code>jspwiki.approver.workflow.saveWikiPage</code> and its value resolves to a valid user,
* {@link org.apache.wiki.auth.authorize.Group} or {@link org.apache.wiki.auth.authorize.Role}, this method will
* place a {@link org.apache.wiki.workflow.Decision} in the approver's workflow inbox and throw a
* {@link org.apache.wiki.workflow.DecisionRequiredException}. If the submitting user is authenticated and the
* page save is rejected, a notification will be placed in the user's decision queue.
*
* @since 2.1.28
* @param context The current WikiContext
* @param text The Wiki markup for the page.
* @throws WikiException if the save operation encounters an error during the save operation. If the page-save
* operation requires approval, the exception will be of type {@link org.apache.wiki.workflow.DecisionRequiredException}.
* Individual PageFilters, such as the {@link org.apache.wiki.filters.SpamFilter} may also throw a
* {@link org.apache.wiki.api.exceptions.RedirectException}.
*/
public void saveText( WikiContext context, String text ) throws WikiException {
// Check if page data actually changed; bail if not
WikiPage page = context.getPage();
String oldText = getPureText( page );
String proposedText = TextUtil.normalizePostData( text );
if ( oldText != null && oldText.equals( proposedText ) ) {
return;
}
// Check if creation of empty pages is allowed; bail if not
boolean allowEmpty = TextUtil.getBooleanProperty( m_properties, PROP_ALLOW_CREATION_OF_EMPTY_PAGES, false );
if ( !allowEmpty && !pageExists( page ) && text.trim().equals( "" ) ) {
return;
}
// Create approval workflow for page save; add the diffed, proposed and old text versions as
// Facts for the approver (if approval is required). If submitter is authenticated, any reject
// messages will appear in his/her workflow inbox.
WorkflowBuilder builder = WorkflowBuilder.getBuilder( this );
Principal submitter = context.getCurrentUser();
Step prepTask = m_tasksManager.buildPreSaveWikiPageTask( context, proposedText );
Step completionTask = m_tasksManager.buildSaveWikiPageTask();
String diffText = m_differenceManager.makeDiff( context, oldText, proposedText );
boolean isAuthenticated = context.getWikiSession().isAuthenticated();
Fact[] facts = new Fact[ 5 ];
facts[ 0 ] = new Fact( WorkflowManager.WF_WP_SAVE_FACT_PAGE_NAME, page.getName() );
facts[ 1 ] = new Fact( WorkflowManager.WF_WP_SAVE_FACT_DIFF_TEXT, diffText );
facts[ 2 ] = new Fact( WorkflowManager.WF_WP_SAVE_FACT_PROPOSED_TEXT, proposedText );
facts[ 3 ] = new Fact( WorkflowManager.WF_WP_SAVE_FACT_CURRENT_TEXT, oldText);
facts[ 4 ] = new Fact( WorkflowManager.WF_WP_SAVE_FACT_IS_AUTHENTICATED, Boolean.valueOf( isAuthenticated ) );
String rejectKey = isAuthenticated ? WorkflowManager.WF_WP_SAVE_REJECT_MESSAGE_KEY : null;
Workflow workflow = builder.buildApprovalWorkflow( submitter,
WorkflowManager.WF_WP_SAVE_APPROVER,
prepTask,
WorkflowManager.WF_WP_SAVE_DECISION_MESSAGE_KEY,
facts,
completionTask,
rejectKey );
m_workflowMgr.start( workflow );
// Let callers know if the page-save requires approval
if ( workflow.getCurrentStep() instanceof Decision ) {
throw new DecisionRequiredException( "The page contents must be approved before they become active." );
}
}
/**
* Returns the number of pages in this Wiki
* @return The total number of pages.
*/
public int getPageCount()
{
return m_pageManager.getTotalPageCount();
}
/**
* Returns a Collection of WikiPages, sorted in time
* order of last change (i.e. first object is the most
* recently changed). This method also includes attachments.
*
* @return Set of WikiPage objects.
*/
public Set< WikiPage > getRecentChanges() {
try {
final Collection< WikiPage > pages = m_pageManager.getAllPages();
final Collection< Attachment > atts = m_attachmentManager.getAllAttachments();
final TreeSet< WikiPage > sortedPages = new TreeSet<>( new PageTimeComparator() );
sortedPages.addAll( pages );
sortedPages.addAll( atts );
return sortedPages;
} catch( final ProviderException e ) {
log.error( "Unable to fetch all pages: ",e);
return null;
}
}
/**
* Finds the corresponding WikiPage object based on the page name. It always finds
* the latest version of a page.
*
* @param pagereq The name of the page to look for.
* @return A WikiPage object, or null, if the page by the name could not be found.
*/
public WikiPage getPage( String pagereq )
{
return getPage( pagereq, WikiProvider.LATEST_VERSION );
}
/**
* Finds the corresponding WikiPage object base on the page name and version.
*
* @param pagereq The name of the page to look for.
* @param version The version number to look for. May be WikiProvider.LATEST_VERSION,
* in which case it will look for the latest version (and this method then becomes
* the equivalent of getPage(String).
*
* @return A WikiPage object, or null, if the page could not be found; or if there
* is no such version of the 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.
*
* @param page Name of the page to look for
* @return an ordered List of WikiPages, each corresponding to a different revision of the page.
*/
public List< ? extends WikiPage > getVersionHistory( String page ) {
List< ? extends WikiPage > c = null;
try {
c = m_pageManager.getVersionHistory( page );
if( c == null ) {
c = m_attachmentManager.getVersionHistory( page );
}
} catch( ProviderException e ) {
log.error( "FIXME", e );
}
return c;
}
/**
* Returns this object's ReferenceManager.
* @return The current ReferenceManager instance.
*
* @since 1.6.1
*/
public ReferenceManager getReferenceManager()
{
return m_referenceManager;
}
/**
* Returns the current 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.
*
* In 2.10 the PluginManager will be returned instead of the generic
*
* @since 1.6.1
* @return The current PluginManager instance
*/
@SuppressWarnings("unchecked")
public < T extends PluginManager > T getPluginManager()
{
return (T)m_pluginManager;
}
/**
* Returns the current variable manager.
* @return The current VariableManager.
*/
public VariableManager getVariableManager()
{
return m_variableManager;
}
/**
* Returns the current PageManager which is responsible for storing
* and managing WikiPages.
*
* @return The current PageManager instance.
*/
public PageManager getPageManager()
{
return m_pageManager;
}
/**
* Returns the CommandResolver for this wiki engine.
* @return the resolver
*/
public CommandResolver getCommandResolver()
{
return m_commandResolver;
}
/**
* Returns the current AttachmentManager, which is responsible for
* storing and managing attachments.
*
* @since 1.9.31.
* @return The current AttachmentManager instance
*/
public AttachmentManager getAttachmentManager()
{
return m_attachmentManager;
}
/**
* Returns the currently used authorization manager.
*
* @return The current AuthorizationManager instance
*/
public AuthorizationManager getAuthorizationManager()
{
return m_authorizationManager;
}
/**
* Returns the currently used authentication manager.
*
* @return The current AuthenticationManager instance.
*/
public AuthenticationManager getAuthenticationManager()
{
return m_authenticationManager;
}
/**
* Returns the manager responsible for the filters.
* @since 2.1.88
* @return The current FilterManager instance
*/
@SuppressWarnings("unchecked")
public < T extends FilterManager > T getFilterManager()
{
return (T)m_filterManager;
}
/**
* Returns the manager responsible for searching the Wiki.
* @since 2.2.21
* @return The current SearchManager instance
*/
public SearchManager getSearchManager()
{
return m_searchManager;
}
/**
* Returns the progress manager we're using
* @return A ProgressManager
* @since 2.6
*/
public ProgressManager getProgressManager()
{
return m_progressManager;
}
/**
* Figure out to which page we are really going to. Considers
* special page names from the jspwiki.properties, and possible aliases.
* This method delgates requests to
* {@link org.apache.wiki.WikiContext#getRedirectURL()}.
* @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( final WikiContext context )
{
return context.getRedirectURL();
}
/**
* Shortcut to create a WikiContext from a supplied HTTP request,
* using a default wiki context.
* @param request the HTTP request
* @param requestContext the default context to use
* @return a new WikiContext object.
*
* @see org.apache.wiki.ui.CommandResolver
* @see org.apache.wiki.ui.Command
* @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( final HttpServletRequest request, final String requestContext ) {
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." );
}
// Build the wiki context
final Command command = m_commandResolver.findCommand( request, requestContext );
return new WikiContext( this, request, command );
}
/**
* Returns the URL of the global RSS file. May be null, if the
* RSS file generation is not operational.
* @since 1.7.10
* @return The global RSS url
*/
public String getGlobalRSSURL()
{
if( m_rssGenerator != null && m_rssGenerator.isEnabled() )
{
return getBaseURL()+ "/" + m_rssFile;
}
return null;
}
/**
* Returns the root path. The root path is where the WikiEngine is
* located in the file system.
*
* @since 2.2
* @return A path to where the Wiki is installed in the local filesystem.
*/
public String getRootPath()
{
return m_rootPath;
}
/**
* @since 2.2.6
* @return the URL constructor
*/
public URLConstructor getURLConstructor()
{
return m_urlConstructor;
}
/**
* Returns the RSSGenerator. If the property <code>jspwiki.rss.generate</code>
* has not been set to <code>true</code>, this method will return <code>null</code>,
* <em>and callers should check for this value.</em>
* @since 2.1.165
* @return the RSS generator
*/
public RSSGenerator getRSSGenerator()
{
return m_rssGenerator;
}
/**
* Returns the PageRenamer employed by this WikiEngine.
* @since 2.5.141
* @return The current PageRenamer instance.
*/
public PageRenamer getPageRenamer()
{
return m_pageRenamer;
}
/**
* Returns the UserManager employed by this WikiEngine.
* @since 2.3
* @return The current UserManager instance.
*/
public UserManager getUserManager()
{
return m_userManager;
}
/**
* Returns the TasksManager employed by this WikiEngine.
* @return The current TasksManager instance.
*/
public TasksManager getTasksManager()
{
return m_tasksManager;
}
/**
* Returns the GroupManager employed by this WikiEngine.
* @since 2.3
* @return The current GroupManager instance
*/
public GroupManager getGroupManager()
{
return m_groupManager;
}
/**
* Returns the current {@link AdminBeanManager}.
*
* @return The current {@link AdminBeanManager}.
* @since 2.6
*/
public AdminBeanManager getAdminBeanManager() {
return m_adminBeanManager;
}
/**
* Returns the AclManager employed by this WikiEngine.
* The AclManager is lazily initialized.
* <p>
* The AclManager implementing class may be set by the
* System property {@link #PROP_ACL_MANAGER_IMPL}.
* </p>
*
* @since 2.3
* @return The current AclManager.
*/
public AclManager getAclManager()
{
if( m_aclManager == null )
{
try
{
String s = m_properties.getProperty( PROP_ACL_MANAGER_IMPL, ClassUtil.getMappedClass( AclManager.class.getName() ).getName() );
m_aclManager = ClassUtil.getMappedObject(s); // TODO: I am not sure whether this is the right call
m_aclManager.initialize( this, m_properties );
}
catch ( ReflectiveOperationException | IllegalArgumentException e )
{
log.fatal( "unable to instantiate class for AclManager: " + e.getMessage() );
throw new InternalWikiException( "Cannot instantiate AclManager, please check logs.", e );
}
}
return m_aclManager;
}
/**
* Returns the DifferenceManager so that texts can be compared.
* @return the difference manager
*/
public DifferenceManager getDifferenceManager()
{
return m_differenceManager;
}
/**
* Returns the current EditorManager instance.
*
* @return The current EditorManager.
*/
public EditorManager getEditorManager()
{
return m_editorManager;
}
/**
* Returns the current i18n manager.
*
* @return The current Intertan... Interante... Internatatializ... Whatever.
*/
public InternationalizationManager getInternationalizationManager()
{
return m_internationalizationManager;
}
/**
* Registers a WikiEventListener with this instance.
* @param listener the event listener
*/
public final synchronized void addWikiEventListener( final WikiEventListener listener )
{
WikiEventManager.addWikiEventListener( this, listener );
}
/**
* Un-registers a WikiEventListener with this instance.
* @param listener the event listener
*/
public final synchronized void removeWikiEventListener( final WikiEventListener listener )
{
WikiEventManager.removeWikiEventListener( this, listener );
}
/**
* Fires a WikiEngineEvent to all registered listeners.
* @param type the event type
*/
protected final void fireEvent( final int type ) {
if( WikiEventManager.isListening(this ) ) {
WikiEventManager.fireEvent( this, new WikiEngineEvent(this, type ) );
}
}
/**
* Fires a WikiPageEvent to all registered listeners.
* @param type the event type
*/
protected final void firePageEvent( final int type, final String pageName ) {
if( WikiEventManager.isListening(this ) ) {
WikiEventManager.fireEvent(this,new WikiPageEvent(this, type, pageName ) );
}
}
/**
* Adds an attribute to the engine for the duration of this engine. The
* value is not persisted.
*
* @since 2.4.91
* @param key the attribute name
* @param value the value
*/
public void setAttribute( final String key, final Object value )
{
m_attributes.put( key, value );
}
/**
* Gets an attribute from the engine.
*
* @param key the attribute name
* @return the value
*/
public Object getAttribute( final String key )
{
return m_attributes.get( key );
}
/**
* Removes an attribute.
*
* @param key The key of the attribute to remove.
* @return The previous attribute, if it existed.
*/
public Object removeAttribute( final String key )
{
return m_attributes.remove( key );
}
/**
* Returns a WatchDog for current thread.
*
* @return The current thread WatchDog.
* @since 2.4.92
*/
public WatchDog getCurrentWatchDog()
{
return WatchDog.getCurrentWatchDog(this);
}
}