001 /* 002 Licensed to the Apache Software Foundation (ASF) under one 003 or more contributor license agreements. See the NOTICE file 004 distributed with this work for additional information 005 regarding copyright ownership. The ASF licenses this file 006 to you under the Apache License, Version 2.0 (the 007 "License"); you may not use this file except in compliance 008 with the License. You may obtain a copy of the License at 009 010 http://www.apache.org/licenses/LICENSE-2.0 011 012 Unless required by applicable law or agreed to in writing, 013 software distributed under the License is distributed on an 014 "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 KIND, either express or implied. See the License for the 016 specific language governing permissions and limitations 017 under the License. 018 */ 019 package org.apache.wiki; 020 021 import java.io.File; 022 import java.io.IOException; 023 import java.io.UnsupportedEncodingException; 024 import java.net.URLDecoder; 025 import java.net.URLEncoder; 026 import java.security.Principal; 027 import java.util.ArrayList; 028 import java.util.Collection; 029 import java.util.Collections; 030 import java.util.Date; 031 import java.util.Enumeration; 032 import java.util.HashMap; 033 import java.util.Iterator; 034 import java.util.List; 035 import java.util.Locale; 036 import java.util.Map; 037 import java.util.Properties; 038 import java.util.TimeZone; 039 import java.util.TreeSet; 040 041 import javax.servlet.ServletConfig; 042 import javax.servlet.ServletContext; 043 import javax.servlet.ServletRequest; 044 import javax.servlet.http.HttpServletRequest; 045 046 import org.apache.commons.lang.time.StopWatch; 047 import org.apache.log4j.Logger; 048 import org.apache.log4j.PropertyConfigurator; 049 import org.apache.wiki.api.engine.AdminBeanManager; 050 import org.apache.wiki.api.engine.FilterManager; 051 import org.apache.wiki.api.engine.PluginManager; 052 import org.apache.wiki.api.exceptions.FilterException; 053 import org.apache.wiki.api.exceptions.NoSuchVariableException; 054 import org.apache.wiki.api.exceptions.ProviderException; 055 import org.apache.wiki.api.exceptions.WikiException; 056 import org.apache.wiki.attachment.Attachment; 057 import org.apache.wiki.attachment.AttachmentManager; 058 import org.apache.wiki.auth.AuthenticationManager; 059 import org.apache.wiki.auth.AuthorizationManager; 060 import org.apache.wiki.auth.UserManager; 061 import org.apache.wiki.auth.acl.AclManager; 062 import org.apache.wiki.auth.acl.DefaultAclManager; 063 import org.apache.wiki.auth.authorize.GroupManager; 064 import org.apache.wiki.content.PageRenamer; 065 import org.apache.wiki.diff.DifferenceManager; 066 import org.apache.wiki.event.WikiEngineEvent; 067 import org.apache.wiki.event.WikiEventListener; 068 import org.apache.wiki.event.WikiEventManager; 069 import org.apache.wiki.event.WikiPageEvent; 070 import org.apache.wiki.event.WikiPageRenameEvent; 071 import org.apache.wiki.i18n.InternationalizationManager; 072 import org.apache.wiki.parser.MarkupParser; 073 import org.apache.wiki.parser.WikiDocument; 074 import org.apache.wiki.providers.WikiPageProvider; 075 import org.apache.wiki.render.RenderingManager; 076 import org.apache.wiki.rss.RSSGenerator; 077 import org.apache.wiki.rss.RSSThread; 078 import org.apache.wiki.search.SearchManager; 079 import org.apache.wiki.ui.Command; 080 import org.apache.wiki.ui.CommandResolver; 081 import org.apache.wiki.ui.EditorManager; 082 import org.apache.wiki.ui.TemplateManager; 083 import org.apache.wiki.ui.progress.ProgressManager; 084 import org.apache.wiki.url.URLConstructor; 085 import org.apache.wiki.util.ClassUtil; 086 import org.apache.wiki.util.PropertyReader; 087 import org.apache.wiki.util.TextUtil; 088 import org.apache.wiki.util.comparators.PageTimeComparator; 089 import org.apache.wiki.workflow.Decision; 090 import org.apache.wiki.workflow.DecisionRequiredException; 091 import org.apache.wiki.workflow.Fact; 092 import org.apache.wiki.workflow.Task; 093 import org.apache.wiki.workflow.Workflow; 094 import org.apache.wiki.workflow.WorkflowBuilder; 095 import org.apache.wiki.workflow.WorkflowManager; 096 097 098 /** 099 * Provides Wiki services to the JSP page. 100 * 101 * <P> 102 * This is the main interface through which everything should go. 103 * 104 * <P> 105 * Using this class: Always get yourself an instance from JSP page 106 * by using the WikiEngine.getInstance() method. Never create a new 107 * WikiEngine() from scratch, unless you're writing tests. 108 * <p> 109 * There's basically only a single WikiEngine for each web application, and 110 * you should always get it using the WikiEngine.getInstance() method. 111 */ 112 public class WikiEngine 113 { 114 private static final String ATTR_WIKIENGINE = "org.apache.wiki.WikiEngine"; 115 116 private static final Logger log = Logger.getLogger(WikiEngine.class); 117 118 /** True, if log4j has been configured. */ 119 // FIXME: If you run multiple applications, the first application 120 // to run defines where the log goes. Not what we want. 121 private static boolean c_configured = false; 122 123 /** Stores properties. */ 124 private Properties m_properties; 125 126 /** The default inlining pattern. Currently "*.png" */ 127 public static final String DEFAULT_INLINEPATTERN = "*.png"; 128 129 /** Property for application name */ 130 public static final String PROP_APPNAME = "jspwiki.applicationName"; 131 132 /** This property defines the inline image pattern. It's current value is {@value} */ 133 public static final String PROP_INLINEIMAGEPTRN = "jspwiki.translatorReader.inlinePattern"; 134 135 /** Property start for any interwiki reference. */ 136 public static final String PROP_INTERWIKIREF = "jspwiki.interWikiRef."; 137 138 /** If true, then the user name will be stored with the page data.*/ 139 public static final String PROP_STOREUSERNAME= "jspwiki.storeUserName"; 140 141 /** Define the used encoding. Currently supported are ISO-8859-1 and UTF-8 */ 142 public static final String PROP_ENCODING = "jspwiki.encoding"; 143 144 /** The name for the base URL to use in all references. */ 145 public static final String PROP_BASEURL = "jspwiki.baseURL"; 146 147 /** The name for the property which allows you to set the current reference 148 * style. The value is {@value}. 149 */ 150 public static final String PROP_REFSTYLE = "jspwiki.referenceStyle"; 151 152 /** Property name for the "spaces in titles" -hack. */ 153 public static final String PROP_BEAUTIFYTITLE = "jspwiki.breakTitleWithSpaces"; 154 155 /** Property name for where the jspwiki work directory should be. 156 If not specified, reverts to ${java.tmpdir}. */ 157 public static final String PROP_WORKDIR = "jspwiki.workDir"; 158 159 /** The name of the cookie that gets stored to the user browser. */ 160 public static final String PREFS_COOKIE_NAME = "JSPWikiUserProfile"; 161 162 /** Property name for the "match english plurals" -hack. */ 163 public static final String PROP_MATCHPLURALS = "jspwiki.translatorReader.matchEnglishPlurals"; 164 165 /** Property name for the template that is used. */ 166 public static final String PROP_TEMPLATEDIR = "jspwiki.templateDir"; 167 168 /** Property name for the default front page. */ 169 public static final String PROP_FRONTPAGE = "jspwiki.frontPage"; 170 171 /** Property name for setting the url generator instance */ 172 173 public static final String PROP_URLCONSTRUCTOR = "jspwiki.urlConstructor"; 174 175 /** If this property is set to false, all filters are disabled when translating. */ 176 public static final String PROP_RUNFILTERS = "jspwiki.runFilters"; 177 178 /** Compares pages by name */ 179 private PageSorter m_pageSorter = null; 180 181 /** Does the work in renaming pages. */ 182 private PageRenamer m_pageRenamer = null; 183 184 /** The name of the property containing the ACLManager implementing class. 185 * The value is {@value}. */ 186 public static final String PROP_ACL_MANAGER_IMPL = "jspwiki.aclManager"; 187 188 /** If this property is set to false, we don't allow the creation of empty pages */ 189 public static final String PROP_ALLOW_CREATION_OF_EMPTY_PAGES = "jspwiki.allowCreationOfEmptyPages"; 190 191 /** Should the user info be saved with the page data as well? */ 192 private boolean m_saveUserInfo = true; 193 194 /** If true, uses UTF8 encoding for all data */ 195 private boolean m_useUTF8 = true; 196 197 /** Stores the base URL. */ 198 private String m_baseURL; 199 200 /** Store the file path to the basic URL. When we're not running as 201 a servlet, it defaults to the user's current directory. */ 202 private String m_rootPath = System.getProperty("user.dir"); 203 204 /** Stores references between wikipages. */ 205 private ReferenceManager m_referenceManager = null; 206 207 /** Stores the Plugin manager */ 208 private PluginManager m_pluginManager; 209 210 /** Stores the Variable manager */ 211 private VariableManager m_variableManager; 212 213 /** Stores the Attachment manager */ 214 private AttachmentManager m_attachmentManager = null; 215 216 /** Stores the Page manager */ 217 private PageManager m_pageManager = null; 218 219 /** Stores the authorization manager */ 220 private AuthorizationManager m_authorizationManager = null; 221 222 /** Stores the authentication manager.*/ 223 private AuthenticationManager m_authenticationManager = null; 224 225 /** Stores the ACL manager. */ 226 private AclManager m_aclManager = null; 227 228 /** Resolves wiki actions, JSPs and special pages. */ 229 private CommandResolver m_commandResolver = null; 230 231 private TemplateManager m_templateManager = null; 232 233 /** Does all our diffs for us. */ 234 private DifferenceManager m_differenceManager; 235 236 /** Handlers page filters. */ 237 private FilterManager m_filterManager; 238 239 /** Stores the Search manager */ 240 private SearchManager m_searchManager = null; 241 242 /** Facade for managing users */ 243 private UserManager m_userManager = null; 244 245 /** Facade for managing users */ 246 private GroupManager m_groupManager = null; 247 248 private RenderingManager m_renderingManager; 249 250 private EditorManager m_editorManager; 251 252 private InternationalizationManager m_internationalizationManager; 253 254 private ProgressManager m_progressManager; 255 256 /** Constructs URLs */ 257 private URLConstructor m_urlConstructor; 258 259 /** Generates RSS feed when requested. */ 260 private RSSGenerator m_rssGenerator; 261 262 /** The RSS file to generate. */ 263 private String m_rssFile; 264 265 /** Store the ServletContext that we're in. This may be null if WikiEngine 266 is not running inside a servlet container (i.e. when testing). */ 267 private ServletContext m_servletContext = null; 268 269 /** If true, all titles will be cleaned. */ 270 private boolean m_beautifyTitle = false; 271 272 /** Stores the template path. This is relative to "templates". */ 273 private String m_templateDir; 274 275 /** The default front page name. Defaults to "Main". */ 276 private String m_frontPage; 277 278 /** The time when this engine was started. */ 279 private Date m_startTime; 280 281 /** The location where the work directory is. */ 282 private String m_workDir; 283 284 /** Each engine has their own application id. */ 285 private String m_appid = ""; 286 287 private boolean m_isConfigured = false; // Flag. 288 289 290 /** Each engine has its own workflow manager. */ 291 private WorkflowManager m_workflowMgr = null; 292 293 private AdminBeanManager m_adminBeanManager; 294 295 /** Stores wikiengine attributes. */ 296 private Map<String,Object> m_attributes = Collections.synchronizedMap(new HashMap<String,Object>()); 297 298 /** 299 * Gets a WikiEngine related to this servlet. Since this method 300 * is only called from JSP pages (and JspInit()) to be specific, 301 * we throw a RuntimeException if things don't work. 302 * 303 * @param config The ServletConfig object for this servlet. 304 * 305 * @return A WikiEngine instance. 306 * @throws InternalWikiException in case something fails. This 307 * is a RuntimeException, so be prepared for it. 308 */ 309 310 // FIXME: It seems that this does not work too well, jspInit() 311 // does not react to RuntimeExceptions, or something... 312 313 public static synchronized WikiEngine getInstance( ServletConfig config ) 314 throws InternalWikiException 315 { 316 return getInstance( config.getServletContext(), null ); 317 } 318 319 /** 320 * Gets a WikiEngine related to the servlet. Works like getInstance(ServletConfig), 321 * but does not force the Properties object. This method is just an optional way 322 * of initializing a WikiEngine for embedded JSPWiki applications; normally, you 323 * should use getInstance(ServletConfig). 324 * 325 * @param config The ServletConfig of the webapp servlet/JSP calling this method. 326 * @param props A set of properties, or null, if we are to load JSPWiki's default 327 * jspwiki.properties (this is the usual case). 328 * 329 * @return One well-behaving WikiEngine instance. 330 */ 331 public static synchronized WikiEngine getInstance( ServletConfig config, 332 Properties props ) 333 { 334 return getInstance( config.getServletContext(), props ); 335 } 336 337 /** 338 * Gets a WikiEngine related to the servlet. Works just like getInstance( ServletConfig ) 339 * 340 * @param context The ServletContext of the webapp servlet/JSP calling this method. 341 * @param props A set of properties, or null, if we are to load JSPWiki's default 342 * jspwiki.properties (this is the usual case). 343 * 344 * @return One fully functional, properly behaving WikiEngine. 345 * @throws InternalWikiException If the WikiEngine instantiation fails. 346 */ 347 348 // FIXME: Potential make-things-easier thingy here: no need to fetch the wikiengine anymore 349 // Wiki.jsp.jspInit() [really old code]; it's probably even faster to fetch it 350 // using this method every time than go to pageContext.getAttribute(). 351 352 public static synchronized WikiEngine getInstance( ServletContext context, 353 Properties props ) 354 throws InternalWikiException 355 { 356 WikiEngine engine = (WikiEngine) context.getAttribute( ATTR_WIKIENGINE ); 357 358 if( engine == null ) 359 { 360 String appid = Integer.toString(context.hashCode()); //FIXME: Kludge, use real type. 361 362 context.log(" Assigning new engine to "+appid); 363 try 364 { 365 if( props == null ) 366 { 367 props = PropertyReader.loadWebAppProps( context ); 368 } 369 370 engine = new WikiEngine( context, appid, props ); 371 context.setAttribute( ATTR_WIKIENGINE, engine ); 372 } 373 catch( Exception e ) 374 { 375 context.log( "ERROR: Failed to create a Wiki engine: "+e.getMessage() ); 376 log.error( "ERROR: Failed to create a Wiki engine, stacktrace follows " , e); 377 throw new InternalWikiException( "No wiki engine, check logs." ); 378 } 379 380 } 381 382 return engine; 383 } 384 385 386 /** 387 * Instantiate the WikiEngine using a given set of properties. 388 * Use this constructor for testing purposes only. 389 * 390 * @param properties A set of properties to use to initialize this WikiEngine. 391 * @throws WikiException If the initialization fails. 392 */ 393 public WikiEngine( Properties properties ) 394 throws WikiException 395 { 396 initialize( properties ); 397 } 398 399 /** 400 * Instantiate using this method when you're running as a servlet and 401 * WikiEngine will figure out where to look for the property 402 * file. 403 * Do not use this method - use WikiEngine.getInstance() instead. 404 * 405 * @param context A ServletContext. 406 * @param appid An Application ID. This application is an unique random string which 407 * is used to recognize this WikiEngine. 408 * @param props The WikiEngine configuration. 409 * @throws WikiException If the WikiEngine construction fails. 410 */ 411 protected WikiEngine( ServletContext context, String appid, Properties props ) 412 throws WikiException 413 { 414 super(); 415 m_servletContext = context; 416 m_appid = appid; 417 418 // Stash the WikiEngine in the servlet context 419 if ( context != null ) 420 { 421 context.setAttribute( ATTR_WIKIENGINE, this ); 422 m_rootPath = context.getRealPath("/"); 423 } 424 425 try 426 { 427 // 428 // Note: May be null, if JSPWiki has been deployed in a WAR file. 429 // 430 initialize( props ); 431 log.info("Root path for this Wiki is: '"+m_rootPath+"'"); 432 } 433 catch( Exception e ) 434 { 435 String msg = Release.APPNAME+": Unable to load and setup properties from jspwiki.properties. "+e.getMessage(); 436 if ( context != null ) 437 { 438 context.log( msg ); 439 } 440 throw new WikiException( msg, e ); 441 } 442 } 443 444 /** 445 * Does all the real initialization. 446 */ 447 private void initialize( Properties props ) 448 throws WikiException 449 { 450 m_startTime = new Date(); 451 m_properties = props; 452 453 // 454 // Initialize log4j. However, make sure that we don't initialize it multiple times. 455 // By default we load the log4j config statements from jspwiki.properties, unless 456 // the property jspwiki.use.external.logconfig=true, in that case we let log4j figure out the 457 // logging configuration. 458 // 459 if( !c_configured ) 460 { 461 String useExternalLogConfig = props.getProperty("jspwiki.use.external.logconfig"); 462 if( useExternalLogConfig == null || useExternalLogConfig.equals("false")) 463 { 464 PropertyConfigurator.configure( props ); 465 } 466 c_configured = true; 467 } 468 469 log.info("*******************************************"); 470 log.info(Release.APPNAME+" "+Release.getVersionString()+" starting. Whee!"); 471 472 fireEvent( WikiEngineEvent.INITIALIZING ); // begin initialization 473 474 log.debug("Java version: "+System.getProperty("java.runtime.version")); 475 log.debug("Java vendor: "+System.getProperty("java.vm.vendor")); 476 log.debug("OS: "+System.getProperty("os.name")+" "+System.getProperty("os.version")+" "+System.getProperty("os.arch")); 477 log.debug("Default server locale: "+Locale.getDefault()); 478 log.debug("Default server timezone: "+TimeZone.getDefault().getDisplayName(true, TimeZone.LONG)); 479 480 if( m_servletContext != null ) 481 { 482 log.info("Servlet container: "+m_servletContext.getServerInfo() ); 483 if( m_servletContext.getMajorVersion() < 2 || 484 (m_servletContext.getMajorVersion() == 2 && m_servletContext.getMinorVersion() < 4) ) 485 { 486 throw new InternalWikiException("I require a container which supports at least version 2.4 of Servlet specification"); 487 } 488 } 489 490 log.debug("Configuring WikiEngine..."); 491 492 // Initializes the CommandResolver 493 m_commandResolver = new CommandResolver( this, props ); 494 495 // 496 // Create and find the default working directory. 497 // 498 m_workDir = TextUtil.getStringProperty( props, PROP_WORKDIR, null ); 499 500 if( m_workDir == null ) 501 { 502 m_workDir = System.getProperty("java.io.tmpdir", "."); 503 m_workDir += File.separator+Release.APPNAME+"-"+m_appid; 504 } 505 506 try 507 { 508 File f = new File( m_workDir ); 509 f.mkdirs(); 510 511 // 512 // A bunch of sanity checks 513 // 514 if( !f.exists() ) throw new WikiException("Work directory does not exist: "+m_workDir); 515 if( !f.canRead() ) throw new WikiException("No permission to read work directory: "+m_workDir); 516 if( !f.canWrite() ) throw new WikiException("No permission to write to work directory: "+m_workDir); 517 if( !f.isDirectory() ) throw new WikiException("jspwiki.workDir does not point to a directory: "+m_workDir); 518 } 519 catch( SecurityException e ) 520 { 521 log.fatal( "Unable to find or create the working directory: "+m_workDir, e ); 522 throw new IllegalArgumentException( "Unable to find or create the working dir: " + m_workDir, e ); 523 } 524 525 log.info("JSPWiki working directory is '"+m_workDir+"'"); 526 527 m_saveUserInfo = TextUtil.getBooleanProperty( props, 528 PROP_STOREUSERNAME, 529 m_saveUserInfo ); 530 531 m_useUTF8 = "UTF-8".equals( TextUtil.getStringProperty( props, PROP_ENCODING, "ISO-8859-1" ) ); 532 m_baseURL = TextUtil.getStringProperty(props, PROP_BASEURL, ""); 533 if (!m_baseURL.endsWith("/")) 534 { 535 m_baseURL = m_baseURL + "/"; 536 } 537 538 m_beautifyTitle = TextUtil.getBooleanProperty( props, 539 PROP_BEAUTIFYTITLE, 540 m_beautifyTitle ); 541 542 m_templateDir = TextUtil.getStringProperty( props, PROP_TEMPLATEDIR, "default" ); 543 m_frontPage = TextUtil.getStringProperty( props, PROP_FRONTPAGE, "Main" ); 544 545 // Initialize the page name comparator now as it may be used while 546 // initializing other modules 547 initPageSorter( props ); 548 549 // 550 // Initialize the important modules. Any exception thrown by the 551 // managers means that we will not start up. 552 // 553 554 // FIXME: This part of the code is getting unwieldy. We must think 555 // of a better way to do the startup-sequence. 556 try 557 { 558 Class< ? > urlclass = ClassUtil.findClass( "org.apache.wiki.url", 559 TextUtil.getStringProperty( props, PROP_URLCONSTRUCTOR, "DefaultURLConstructor" ) ); 560 m_urlConstructor = (URLConstructor) urlclass.newInstance(); 561 m_urlConstructor.initialize( this, props ); 562 563 m_pageManager = (PageManager)ClassUtil.getMappedObject(PageManager.class.getName(), this, props ); 564 m_pluginManager = (PluginManager)ClassUtil.getMappedObject(PluginManager.class.getName(), this, props ); 565 m_differenceManager = (DifferenceManager)ClassUtil.getMappedObject(DifferenceManager.class.getName(), this, props ); 566 m_attachmentManager = (AttachmentManager)ClassUtil.getMappedObject(AttachmentManager.class.getName(), this, props ); 567 m_variableManager = (VariableManager)ClassUtil.getMappedObject(VariableManager.class.getName(), props ); 568 // m_filterManager = (FilterManager)ClassUtil.getMappedObject(FilterManager.class.getName(), this, props ); 569 m_renderingManager = (RenderingManager) ClassUtil.getMappedObject(RenderingManager.class.getName()); 570 571 m_searchManager = (SearchManager)ClassUtil.getMappedObject(SearchManager.class.getName(), this, props ); 572 573 m_authenticationManager = (AuthenticationManager) ClassUtil.getMappedObject(AuthenticationManager.class.getName()); 574 m_authorizationManager = (AuthorizationManager) ClassUtil.getMappedObject( AuthorizationManager.class.getName()); 575 m_userManager = (UserManager) ClassUtil.getMappedObject(UserManager.class.getName()); 576 m_groupManager = (GroupManager) ClassUtil.getMappedObject(GroupManager.class.getName()); 577 578 m_editorManager = (EditorManager)ClassUtil.getMappedObject(EditorManager.class.getName(), this ); 579 m_editorManager.initialize( props ); 580 581 m_progressManager = new ProgressManager(); 582 583 // Initialize the authentication, authorization, user and acl managers 584 585 m_authenticationManager.initialize( this, props ); 586 m_authorizationManager.initialize( this, props ); 587 m_userManager.initialize( this, props ); 588 m_groupManager.initialize( this, props ); 589 m_aclManager = getAclManager(); 590 591 // Start the Workflow manager 592 m_workflowMgr = (WorkflowManager)ClassUtil.getMappedObject(WorkflowManager.class.getName()); 593 m_workflowMgr.initialize(this, props); 594 595 m_internationalizationManager = (InternationalizationManager) 596 ClassUtil.getMappedObject(InternationalizationManager.class.getName(),this); 597 598 m_templateManager = (TemplateManager) 599 ClassUtil.getMappedObject(TemplateManager.class.getName(), this, props ); 600 601 m_adminBeanManager = (AdminBeanManager) 602 ClassUtil.getMappedObject(AdminBeanManager.class.getName(),this); 603 604 // Since we want to use a page filters initilize() method 605 // as a engine startup listener where we can initialize global event listeners, 606 // it must be called lastly, so that all object references in the engine 607 // are availabe to the initialize() method 608 m_filterManager = (FilterManager) 609 ClassUtil.getMappedObject(FilterManager.class.getName(), this, props ); 610 611 // RenderingManager depends on FilterManager events. 612 613 m_renderingManager.initialize( this, props ); 614 615 // 616 // ReferenceManager has the side effect of loading all 617 // pages. Therefore after this point, all page attributes 618 // are available. 619 // 620 // initReferenceManager is indirectly using m_filterManager, therefore 621 // it has to be called after it was initialized. 622 // 623 initReferenceManager(); 624 625 // 626 // Hook the different manager routines into the system. 627 // 628 m_filterManager.addPageFilter(m_referenceManager, -1001 ); 629 m_filterManager.addPageFilter(m_searchManager, -1002 ); 630 } 631 632 catch( RuntimeException e ) 633 { 634 // RuntimeExceptions may occur here, even if they shouldn't. 635 log.fatal( "Failed to start managers.", e ); 636 throw new WikiException( "Failed to start managers: "+e.getMessage(), e ); 637 } 638 catch (ClassNotFoundException e) 639 { 640 log.fatal( "JSPWiki could not start, URLConstructor was not found: ",e ); 641 throw new WikiException(e.getMessage(), e ); 642 } 643 catch (InstantiationException e) 644 { 645 log.fatal( "JSPWiki could not start, URLConstructor could not be instantiated: ",e ); 646 throw new WikiException(e.getMessage(), e ); 647 } 648 catch (IllegalAccessException e) 649 { 650 log.fatal( "JSPWiki could not start, URLConstructor cannot be accessed: ",e ); 651 throw new WikiException(e.getMessage(), e ); 652 } 653 catch( Exception e ) 654 { 655 // Final catch-all for everything 656 log.fatal( "JSPWiki could not start, due to an unknown exception when starting.",e ); 657 throw new WikiException("Failed to start; please check log files for better information.", e ); 658 } 659 660 // 661 // Initialize the good-to-have-but-not-fatal modules. 662 // 663 try 664 { 665 if( TextUtil.getBooleanProperty( props, 666 RSSGenerator.PROP_GENERATE_RSS, 667 false ) ) 668 { 669 m_rssGenerator = (RSSGenerator)ClassUtil.getMappedObject(RSSGenerator.class.getName(), this, props ); 670 } 671 672 m_pageRenamer = (PageRenamer)ClassUtil.getMappedObject(PageRenamer.class.getName(), this, props ); 673 } 674 catch( Exception e ) 675 { 676 log.error( "Unable to start RSS generator - JSPWiki will still work, "+ 677 "but there will be no RSS feed.", e ); 678 } 679 680 // Start the RSS generator & generator thread 681 if( m_rssGenerator != null ) 682 { 683 m_rssFile = TextUtil.getStringProperty( props, 684 RSSGenerator.PROP_RSSFILE, "rss.rdf" ); 685 File rssFile=null; 686 if (m_rssFile.startsWith(File.separator)) 687 { 688 // honor absolute pathnames: 689 rssFile = new File(m_rssFile ); 690 } 691 else 692 { 693 // relative path names are anchored from the webapp root path: 694 rssFile = new File( getRootPath(), m_rssFile ); 695 } 696 int rssInterval = TextUtil.getIntegerProperty( props, 697 RSSGenerator.PROP_INTERVAL, 3600 ); 698 RSSThread rssThread = new RSSThread( this, rssFile, rssInterval ); 699 rssThread.start(); 700 } 701 702 fireEvent( WikiEngineEvent.INITIALIZED ); // initialization complete 703 704 log.info("WikiEngine configured."); 705 m_isConfigured = true; 706 } 707 708 /** 709 * Initializes the reference manager. Scans all existing WikiPages for 710 * internal links and adds them to the ReferenceManager object. 711 * 712 * @throws WikiException If the reference manager initialization fails. 713 */ 714 @SuppressWarnings("unchecked") 715 public void initReferenceManager() throws WikiException 716 { 717 try 718 { 719 ArrayList<WikiPage> pages = new ArrayList<WikiPage>(); 720 pages.addAll( m_pageManager.getAllPages() ); 721 pages.addAll( m_attachmentManager.getAllAttachments() ); 722 723 // Build a new manager with default key lists. 724 if( m_referenceManager == null ) 725 { 726 m_referenceManager = 727 (ReferenceManager) ClassUtil.getMappedObject(ReferenceManager.class.getName(), this ); 728 m_referenceManager.initialize( pages ); 729 } 730 731 } 732 catch( ProviderException e ) 733 { 734 log.fatal("PageProvider is unable to list pages: ", e); 735 } 736 } 737 738 /** 739 * Returns the set of properties that the WikiEngine was initialized 740 * with. Note that this method returns a direct reference, so it's possible 741 * to manipulate the properties. However, this is not advised unless you 742 * really know what you're doing. 743 * 744 * @return The wiki properties 745 */ 746 747 public Properties getWikiProperties() 748 { 749 return m_properties; 750 } 751 752 /** 753 * Returns the JSPWiki working directory set with "jspwiki.workDir". 754 * 755 * @since 2.1.100 756 * @return The working directory. 757 */ 758 public String getWorkDir() 759 { 760 return m_workDir; 761 } 762 763 /** 764 * Returns the current template directory. 765 * 766 * @since 1.9.20 767 * @return The template directory as initialized by the engine. 768 */ 769 public String getTemplateDir() 770 { 771 return m_templateDir; 772 } 773 774 /** 775 * Returns the current TemplateManager. 776 * 777 * @return A TemplateManager instance. 778 */ 779 public TemplateManager getTemplateManager() 780 { 781 return m_templateManager; 782 } 783 784 /** 785 * Returns the base URL, telling where this Wiki actually lives. 786 * 787 * @since 1.6.1 788 * @return The Base URL. 789 */ 790 791 public String getBaseURL() 792 { 793 return m_baseURL; 794 } 795 796 /** 797 * Returns the moment when this engine was started. 798 * 799 * @since 2.0.15. 800 * @return The start time of this wiki. 801 */ 802 803 public Date getStartTime() 804 { 805 return (Date)m_startTime.clone(); 806 } 807 808 /** 809 * <p> 810 * Returns the basic absolute URL to a page, without any modifications. You 811 * may add any parameters to this. 812 * </p> 813 * <p> 814 * Since 2.3.90 it is safe to call this method with <code>null</code> 815 * pageName, in which case it will default to the front page. 816 * </p> 817 * @since 2.0.3 818 * @param pageName The name of the page. May be null, in which case defaults to the front page. 819 * @return An absolute URL to the page. 820 */ 821 public String getViewURL( String pageName ) 822 { 823 if( pageName == null ) 824 { 825 pageName = getFrontPage(); 826 } 827 return getURLConstructor().makeURL( WikiContext.VIEW, pageName, true, null ); 828 } 829 830 /** 831 * Returns the basic URL to an editor. Please use WikiContext.getURL() or 832 * WikiEngine.getURL() instead. 833 * 834 * @see #getURL(String, String, String, boolean) 835 * @see WikiContext#getURL(String, String) 836 * @deprecated 837 * 838 * @param pageName The name of the page. 839 * @return An URI. 840 * 841 * @since 2.0.3 842 */ 843 public String getEditURL( String pageName ) 844 { 845 return m_urlConstructor.makeURL( WikiContext.EDIT, pageName, false, null ); 846 } 847 848 /** 849 * Returns the basic attachment URL.Please use WikiContext.getURL() or 850 * WikiEngine.getURL() instead. 851 * 852 * @see #getURL(String, String, String, boolean) 853 * @see WikiContext#getURL(String, String) 854 * @since 2.0.42. 855 * @param attName Attachment name 856 * @deprecated 857 * @return An URI. 858 */ 859 public String getAttachmentURL( String attName ) 860 { 861 return m_urlConstructor.makeURL( WikiContext.ATTACH, attName, false, null ); 862 } 863 864 /** 865 * Returns an URL if a WikiContext is not available. 866 * 867 * @param context The WikiContext (VIEW, EDIT, etc...) 868 * @param pageName Name of the page, as usual 869 * @param params List of parameters. May be null, if no parameters. 870 * @param absolute If true, will generate an absolute URL regardless of properties setting. 871 * @return An URL (absolute or relative). 872 */ 873 public String getURL( String context, String pageName, String params, boolean absolute ) 874 { 875 if( pageName == null ) pageName = getFrontPage(); 876 return m_urlConstructor.makeURL( context, pageName, absolute, params ); 877 } 878 879 /** 880 * Returns the default front page, if no page is used. 881 * 882 * @return The front page name. 883 */ 884 885 public String getFrontPage() 886 { 887 return m_frontPage; 888 } 889 890 /** 891 * Returns the ServletContext that this particular WikiEngine was 892 * initialized with. <B>It may return null</B>, if the WikiEngine is not 893 * running inside a servlet container! 894 * 895 * @since 1.7.10 896 * @return ServletContext of the WikiEngine, or null. 897 */ 898 899 public ServletContext getServletContext() 900 { 901 return m_servletContext; 902 } 903 904 /** 905 * This is a safe version of the Servlet.Request.getParameter() routine. 906 * Unfortunately, the default version always assumes that the incoming 907 * character set is ISO-8859-1, even though it was something else. 908 * This means that we need to make a new string using the correct 909 * encoding. 910 * <P> 911 * For more information, see: 912 * <A HREF="http://www.jguru.com/faq/view.jsp?EID=137049">JGuru FAQ</A>. 913 * <P> 914 * Incidentally, this is almost the same as encodeName(), below. 915 * I am not yet entirely sure if it's safe to merge the code. 916 * 917 * @param request The servlet request 918 * @param name The parameter name to get. 919 * @return The parameter value or null 920 * @since 1.5.3 921 * @deprecated JSPWiki now requires servlet API 2.3, which has a better 922 * way of dealing with this stuff. This will be removed in 923 * the near future. 924 */ 925 926 public String safeGetParameter( ServletRequest request, String name ) 927 { 928 try 929 { 930 String res = request.getParameter( name ); 931 if( res != null ) 932 { 933 res = new String(res.getBytes("ISO-8859-1"), 934 getContentEncoding() ); 935 } 936 937 return res; 938 } 939 catch( UnsupportedEncodingException e ) 940 { 941 log.fatal( "Unsupported encoding", e ); 942 return ""; 943 } 944 945 } 946 947 /** 948 * Returns the query string (the portion after the question mark). 949 * 950 * @param request The HTTP request to parse. 951 * @return The query string. If the query string is null, 952 * returns an empty string. 953 * 954 * @since 2.1.3 955 */ 956 public String safeGetQueryString( HttpServletRequest request ) 957 { 958 if (request == null) 959 { 960 return ""; 961 } 962 963 try 964 { 965 String res = request.getQueryString(); 966 if( res != null ) 967 { 968 res = new String(res.getBytes("ISO-8859-1"), 969 getContentEncoding() ); 970 971 // 972 // Ensure that the 'page=xyz' attribute is removed 973 // FIXME: Is it really the mandate of this routine to 974 // do that? 975 // 976 int pos1 = res.indexOf("page="); 977 if (pos1 >= 0) 978 { 979 String tmpRes = res.substring(0, pos1); 980 int pos2 = res.indexOf("&",pos1) + 1; 981 if ( (pos2 > 0) && (pos2 < res.length()) ) 982 { 983 tmpRes = tmpRes + res.substring(pos2); 984 } 985 res = tmpRes; 986 } 987 } 988 989 return res; 990 } 991 catch( UnsupportedEncodingException e ) 992 { 993 log.fatal( "Unsupported encoding", e ); 994 return ""; 995 } 996 } 997 998 /** 999 * Returns an URL to some other Wiki that we know. 1000 * 1001 * @param wikiName The name of the other wiki. 1002 * @return null, if no such reference was found. 1003 */ 1004 public String getInterWikiURL( String wikiName ) 1005 { 1006 return TextUtil.getStringProperty(m_properties,PROP_INTERWIKIREF+wikiName,null); 1007 } 1008 1009 /** 1010 * Returns a collection of all supported InterWiki links. 1011 * 1012 * @return A Collection of Strings. 1013 */ 1014 public Collection< String > getAllInterWikiLinks() 1015 { 1016 ArrayList< String > list = new ArrayList< String >(); 1017 1018 for( Enumeration< ? > i = m_properties.propertyNames(); i.hasMoreElements(); ) 1019 { 1020 String prop = ( String )i.nextElement(); 1021 1022 if( prop.startsWith( PROP_INTERWIKIREF ) ) 1023 { 1024 list.add( prop.substring( prop.lastIndexOf( "." ) + 1 ) ); 1025 } 1026 } 1027 1028 return list; 1029 } 1030 1031 /** 1032 * Returns a collection of all image types that get inlined. 1033 * 1034 * @return A Collection of Strings with a regexp pattern. 1035 */ 1036 public Collection< String > getAllInlinedImagePatterns() 1037 { 1038 Properties props = getWikiProperties(); 1039 ArrayList<String> ptrnlist = new ArrayList<String>(); 1040 1041 for( Enumeration< ? > e = props.propertyNames(); e.hasMoreElements(); ) 1042 { 1043 String name = ( String )e.nextElement(); 1044 1045 if( name.startsWith( PROP_INLINEIMAGEPTRN ) ) 1046 { 1047 String ptrn = TextUtil.getStringProperty( props, name, null ); 1048 1049 ptrnlist.add( ptrn ); 1050 } 1051 } 1052 1053 if( ptrnlist.size() == 0 ) 1054 { 1055 ptrnlist.add( DEFAULT_INLINEPATTERN ); 1056 } 1057 1058 return ptrnlist; 1059 } 1060 1061 /** 1062 * <p>If the page is a special page, then returns a direct URL 1063 * to that page. Otherwise returns <code>null</code>. 1064 * This method delegates requests to 1065 * {@link org.apache.wiki.ui.CommandResolver#getSpecialPageReference(String)}. 1066 * </p> 1067 * <p> 1068 * Special pages are defined in jspwiki.properties using the jspwiki.specialPage 1069 * setting. They're typically used to give Wiki page names to e.g. custom JSP 1070 * pages. 1071 * </p> 1072 * 1073 * @param original The page to check 1074 * @return A reference to the page, or null, if there's no special page. 1075 */ 1076 public String getSpecialPageReference( String original ) 1077 { 1078 return m_commandResolver.getSpecialPageReference( original ); 1079 } 1080 1081 /** 1082 * Returns the name of the application. 1083 * 1084 * @return A string describing the name of this application. 1085 */ 1086 1087 // FIXME: Should use servlet context as a default instead of a constant. 1088 public String getApplicationName() 1089 { 1090 String appName = TextUtil.getStringProperty(m_properties,PROP_APPNAME,Release.APPNAME); 1091 1092 return MarkupParser.cleanLink( appName ); 1093 } 1094 1095 /** 1096 * Beautifies the title of the page by appending spaces in suitable 1097 * places, if the user has so decreed in the properties when constructing 1098 * this WikiEngine. However, attachment names are only beautified by 1099 * the name. 1100 * 1101 * @param title The title to beautify 1102 * @return A beautified title (or, if beautification is off, 1103 * returns the title without modification) 1104 * @since 1.7.11 1105 */ 1106 public String beautifyTitle( String title ) 1107 { 1108 if( m_beautifyTitle ) 1109 { 1110 try 1111 { 1112 Attachment att = m_attachmentManager.getAttachmentInfo(title); 1113 1114 if(att == null) 1115 { 1116 return TextUtil.beautifyString( title ); 1117 } 1118 1119 String parent = TextUtil.beautifyString( att.getParentName() ); 1120 1121 return parent + "/" + att.getFileName(); 1122 } 1123 catch( ProviderException e ) 1124 { 1125 return title; 1126 } 1127 } 1128 1129 return title; 1130 } 1131 1132 /** 1133 * Beautifies the title of the page by appending non-breaking spaces 1134 * in suitable places. This is really suitable only for HTML output, 1135 * as it uses the &nbsp; -character. 1136 * 1137 * @param title The title to beautify 1138 * @return A beautified title. 1139 * @since 2.1.127 1140 */ 1141 public String beautifyTitleNoBreak( String title ) 1142 { 1143 if( m_beautifyTitle ) 1144 { 1145 return TextUtil.beautifyString( title, " " ); 1146 } 1147 1148 return title; 1149 } 1150 1151 /** 1152 * Returns true, if the requested page (or an alias) exists. Will consider 1153 * any version as existing. Will also consider attachments. 1154 * 1155 * @param page WikiName of the page. 1156 * @return true, if page (or attachment) exists. 1157 */ 1158 public boolean pageExists( String page ) 1159 { 1160 Attachment att = null; 1161 1162 try 1163 { 1164 if( m_commandResolver.getSpecialPageReference(page) != null ) return true; 1165 1166 if( getFinalPageName( page ) != null ) 1167 { 1168 return true; 1169 } 1170 1171 att = getAttachmentManager().getAttachmentInfo( (WikiContext)null, page ); 1172 } 1173 catch( ProviderException e ) 1174 { 1175 log.debug("pageExists() failed to find attachments",e); 1176 } 1177 1178 return att != null; 1179 } 1180 1181 /** 1182 * Returns true, if the requested page (or an alias) exists with the 1183 * requested version. 1184 * 1185 * @param page Page name 1186 * @param version Page version 1187 * @return True, if page (or alias, or attachment) exists 1188 * @throws ProviderException If the provider fails. 1189 */ 1190 public boolean pageExists( String page, int version ) 1191 throws ProviderException 1192 { 1193 if( m_commandResolver.getSpecialPageReference(page) != null ) return true; 1194 1195 String finalName = getFinalPageName( page ); 1196 1197 boolean isThere = false; 1198 1199 if( finalName != null ) 1200 { 1201 // 1202 // Go and check if this particular version of this page 1203 // exists. 1204 // 1205 isThere = m_pageManager.pageExists( finalName, version ); 1206 } 1207 1208 if( isThere == false ) 1209 { 1210 // 1211 // Go check if such an attachment exists. 1212 // 1213 try 1214 { 1215 isThere = getAttachmentManager().getAttachmentInfo( (WikiContext)null, page, version ) != null; 1216 } 1217 catch( ProviderException e ) 1218 { 1219 log.debug("pageExists() failed to find attachments",e); 1220 } 1221 } 1222 1223 return isThere; 1224 } 1225 1226 /** 1227 * Returns true, if the requested page (or an alias) exists, with the 1228 * specified version in the WikiPage. 1229 * 1230 * @param page A WikiPage object describing the name and version. 1231 * @return true, if the page (or alias, or attachment) exists. 1232 * @throws ProviderException If something goes badly wrong. 1233 * @since 2.0 1234 */ 1235 public boolean pageExists( WikiPage page ) 1236 throws ProviderException 1237 { 1238 if( page != null ) 1239 { 1240 return pageExists( page.getName(), page.getVersion() ); 1241 } 1242 return false; 1243 } 1244 1245 /** 1246 * Returns the correct page name, or null, if no such 1247 * page can be found. Aliases are considered. This 1248 * method simply delegates to 1249 * {@link org.apache.wiki.ui.CommandResolver#getFinalPageName(String)}. 1250 * @since 2.0 1251 * @param page Page name. 1252 * @return The rewritten page name, or null, if the page does not exist. 1253 * @throws ProviderException If something goes wrong in the backend. 1254 */ 1255 public String getFinalPageName( String page ) 1256 throws ProviderException 1257 { 1258 return m_commandResolver.getFinalPageName( page ); 1259 } 1260 1261 /** 1262 * Turns a WikiName into something that can be 1263 * called through using an URL. 1264 * 1265 * @since 1.4.1 1266 * @param pagename A name. Can be actually any string. 1267 * @return A properly encoded name. 1268 * @see #decodeName(String) 1269 */ 1270 public String encodeName( String pagename ) 1271 { 1272 try 1273 { 1274 return URLEncoder.encode( pagename, m_useUTF8 ? "UTF-8" : "ISO-8859-1" ); 1275 } 1276 catch( UnsupportedEncodingException e ) 1277 { 1278 throw new InternalWikiException( "ISO-8859-1 not a supported encoding!?! Your platform is borked." ); 1279 } 1280 } 1281 1282 /** 1283 * Decodes a URL-encoded request back to regular life. This properly heeds 1284 * the encoding as defined in the settings file. 1285 * 1286 * @param pagerequest The URL-encoded string to decode 1287 * @return A decoded string. 1288 * @see #encodeName(String) 1289 */ 1290 public String decodeName( String pagerequest ) 1291 { 1292 try 1293 { 1294 return URLDecoder.decode( pagerequest, m_useUTF8 ? "UTF-8" : "ISO-8859-1" ); 1295 } 1296 catch( UnsupportedEncodingException e ) 1297 { 1298 throw new InternalWikiException("ISO-8859-1 not a supported encoding!?! Your platform is borked."); 1299 } 1300 } 1301 1302 /** 1303 * Returns the IANA name of the character set encoding we're 1304 * supposed to be using right now. 1305 * 1306 * @since 1.5.3 1307 * @return The content encoding (either UTF-8 or ISO-8859-1). 1308 */ 1309 public String getContentEncoding() 1310 { 1311 if( m_useUTF8 ) 1312 return "UTF-8"; 1313 1314 return "ISO-8859-1"; 1315 } 1316 1317 /** 1318 * Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this 1319 * WikiEngine. If the WIkiEngine has not been initialized, this method will return 1320 * <code>null</code>. 1321 * @return the task queue 1322 */ 1323 public WorkflowManager getWorkflowManager() 1324 { 1325 return m_workflowMgr; 1326 } 1327 1328 /** 1329 * Returns the un-HTMLized text of the latest version of a page. 1330 * This method also replaces the < and & -characters with 1331 * their respective HTML entities, thus making it suitable 1332 * for inclusion on an HTML page. If you want to have the 1333 * page text without any conversions, use getPureText(). 1334 * 1335 * @param page WikiName of the page to fetch. 1336 * @return WikiText. 1337 */ 1338 public String getText( String page ) 1339 { 1340 return getText( page, WikiPageProvider.LATEST_VERSION ); 1341 } 1342 1343 /** 1344 * Returns the un-HTMLized text of the given version of a page. 1345 * This method also replaces the < and & -characters with 1346 * their respective HTML entities, thus making it suitable 1347 * for inclusion on an HTML page. If you want to have the 1348 * page text without any conversions, use getPureText(). 1349 * 1350 * 1351 * @param page WikiName of the page to fetch 1352 * @param version Version of the page to fetch 1353 * @return WikiText. 1354 */ 1355 public String getText( String page, int version ) 1356 { 1357 String result = getPureText( page, version ); 1358 1359 // 1360 // Replace ampersand first, or else all quotes and stuff 1361 // get replaced as well with " etc. 1362 // 1363 /* 1364 result = TextUtil.replaceString( result, "&", "&" ); 1365 */ 1366 1367 result = TextUtil.replaceEntities( result ); 1368 1369 return result; 1370 } 1371 1372 /** 1373 * Returns the un-HTMLized text of the given version of a page in 1374 * the given context. USE THIS METHOD if you don't know what 1375 * doing. 1376 * <p> 1377 * This method also replaces the < and & -characters with 1378 * their respective HTML entities, thus making it suitable 1379 * for inclusion on an HTML page. If you want to have the 1380 * page text without any conversions, use getPureText(). 1381 * 1382 * @since 1.9.15. 1383 * @param context The WikiContext 1384 * @param page A page reference (not an attachment) 1385 * @return The page content as HTMLized String. 1386 * @see #getPureText(WikiPage) 1387 */ 1388 public String getText( WikiContext context, WikiPage page ) 1389 { 1390 return getText( page.getName(), page.getVersion() ); 1391 } 1392 1393 1394 /** 1395 * Returns the pure text of a page, no conversions. Use this 1396 * if you are writing something that depends on the parsing 1397 * of the page. Note that you should always check for page 1398 * existence through pageExists() before attempting to fetch 1399 * the page contents. 1400 * 1401 * @param page The name of the page to fetch. 1402 * @param version If WikiPageProvider.LATEST_VERSION, then uses the 1403 * latest version. 1404 * @return The page contents. If the page does not exist, 1405 * returns an empty string. 1406 */ 1407 // FIXME: Should throw an exception on unknown page/version? 1408 public String getPureText( String page, int version ) 1409 { 1410 String result = null; 1411 1412 try 1413 { 1414 result = m_pageManager.getPageText( page, version ); 1415 } 1416 catch( ProviderException e ) 1417 { 1418 // FIXME 1419 } 1420 finally 1421 { 1422 if( result == null ) 1423 result = ""; 1424 } 1425 1426 return result; 1427 } 1428 1429 /** 1430 * Returns the pure text of a page, no conversions. Use this 1431 * if you are writing something that depends on the parsing 1432 * the page. Note that you should always check for page 1433 * existence through pageExists() before attempting to fetch 1434 * the page contents. 1435 * 1436 * @param page A handle to the WikiPage 1437 * @return String of WikiText. 1438 * @since 2.1.13. 1439 */ 1440 public String getPureText( WikiPage page ) 1441 { 1442 return getPureText( page.getName(), page.getVersion() ); 1443 } 1444 1445 /** 1446 * Returns the converted HTML of the page using a different 1447 * context than the default context. 1448 * 1449 * @param context A WikiContext in which you wish to render this page in. 1450 * @param page WikiPage reference. 1451 * @return HTML-rendered version of the page. 1452 */ 1453 1454 public String getHTML( WikiContext context, WikiPage page ) 1455 { 1456 String pagedata = null; 1457 1458 pagedata = getPureText( page.getName(), page.getVersion() ); 1459 1460 String res = textToHTML( context, pagedata ); 1461 1462 return res; 1463 } 1464 1465 /** 1466 * Returns the converted HTML of the page. 1467 * 1468 * @param page WikiName of the page to convert. 1469 * @return HTML-rendered version of the page. 1470 */ 1471 public String getHTML( String page ) 1472 { 1473 return getHTML( page, WikiPageProvider.LATEST_VERSION ); 1474 } 1475 1476 /** 1477 * Returns the converted HTML of the page's specific version. 1478 * The version must be a positive integer, otherwise the current 1479 * version is returned. 1480 * 1481 * @param pagename WikiName of the page to convert. 1482 * @param version Version number to fetch 1483 * @return HTML-rendered page text. 1484 */ 1485 public String getHTML( String pagename, int version ) 1486 { 1487 WikiPage page = getPage( pagename, version ); 1488 1489 WikiContext context = new WikiContext( this, 1490 page ); 1491 context.setRequestContext( WikiContext.NONE ); 1492 1493 String res = getHTML( context, page ); 1494 1495 return res; 1496 } 1497 1498 /** 1499 * Converts raw page data to HTML. 1500 * 1501 * @param pagedata Raw page data to convert to HTML 1502 * @param context The WikiContext in which the page is to be rendered 1503 * @return Rendered page text 1504 */ 1505 public String textToHTML( WikiContext context, String pagedata ) 1506 { 1507 String result = ""; 1508 1509 boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true")); 1510 1511 StopWatch sw = new StopWatch(); 1512 sw.start(); 1513 try 1514 { 1515 if( runFilters ) 1516 pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata ); 1517 1518 result = m_renderingManager.getHTML( context, pagedata ); 1519 1520 if( runFilters ) 1521 result = m_filterManager.doPostTranslateFiltering( context, result ); 1522 } 1523 catch( FilterException e ) 1524 { 1525 // FIXME: Don't yet know what to do 1526 } 1527 sw.stop(); 1528 if( log.isDebugEnabled() ) 1529 log.debug("Page "+context.getRealPage().getName()+" rendered, took "+sw ); 1530 1531 return result; 1532 } 1533 1534 /** 1535 * Protected method that signals that the WikiEngine will be 1536 * shut down by the servlet container. It is called by 1537 * {@link WikiServlet#destroy()}. When this method is called, 1538 * it fires a "shutdown" WikiEngineEvent to all registered 1539 * listeners. 1540 */ 1541 protected void shutdown() 1542 { 1543 fireEvent( WikiEngineEvent.SHUTDOWN ); 1544 m_filterManager.destroy(); 1545 } 1546 1547 /** 1548 * Reads a WikiPageful of data from a String and returns all links 1549 * internal to this Wiki in a Collection. 1550 * 1551 * @param page The WikiPage to scan 1552 * @param pagedata The page contents 1553 * @return a Collection of Strings 1554 */ 1555 public Collection< String > scanWikiLinks( WikiPage page, String pagedata ) { 1556 LinkCollector localCollector = new LinkCollector(); 1557 1558 textToHTML( new WikiContext( this, page ), 1559 pagedata, 1560 localCollector, 1561 null, 1562 localCollector, 1563 false, 1564 true ); 1565 1566 return localCollector.getLinks(); 1567 } 1568 1569 /** 1570 * Just convert WikiText to HTML. 1571 * 1572 * @param context The WikiContext in which to do the conversion 1573 * @param pagedata The data to render 1574 * @param localLinkHook Is called whenever a wiki link is found 1575 * @param extLinkHook Is called whenever an external link is found 1576 * 1577 * @return HTML-rendered page text. 1578 */ 1579 1580 public String textToHTML( WikiContext context, 1581 String pagedata, 1582 StringTransmutator localLinkHook, 1583 StringTransmutator extLinkHook ) 1584 { 1585 return textToHTML( context, pagedata, localLinkHook, extLinkHook, null, true, false ); 1586 } 1587 1588 /** 1589 * Just convert WikiText to HTML. 1590 * 1591 * @param context The WikiContext in which to do the conversion 1592 * @param pagedata The data to render 1593 * @param localLinkHook Is called whenever a wiki link is found 1594 * @param extLinkHook Is called whenever an external link is found 1595 * @param attLinkHook Is called whenever an attachment link is found 1596 * @return HTML-rendered page text. 1597 */ 1598 1599 public String textToHTML( WikiContext context, 1600 String pagedata, 1601 StringTransmutator localLinkHook, 1602 StringTransmutator extLinkHook, 1603 StringTransmutator attLinkHook ) 1604 { 1605 return textToHTML( context, pagedata, localLinkHook, extLinkHook, attLinkHook, true, false ); 1606 } 1607 1608 /** 1609 * Helper method for doing the HTML translation. 1610 * 1611 * @param context The WikiContext in which to do the conversion 1612 * @param pagedata The data to render 1613 * @param localLinkHook Is called whenever a wiki link is found 1614 * @param extLinkHook Is called whenever an external link is found 1615 * @param parseAccessRules Parse the access rules if we encounter them 1616 * @param justParse Just parses the pagedata, does not actually render. In this case, 1617 * this methods an empty string. 1618 * @return HTML-rendered page text. 1619 1620 */ 1621 private String textToHTML( WikiContext context, 1622 String pagedata, 1623 StringTransmutator localLinkHook, 1624 StringTransmutator extLinkHook, 1625 StringTransmutator attLinkHook, 1626 boolean parseAccessRules, 1627 boolean justParse ) 1628 { 1629 String result = ""; 1630 1631 if( pagedata == null ) 1632 { 1633 log.error("NULL pagedata to textToHTML()"); 1634 return null; 1635 } 1636 1637 boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true")); 1638 1639 try 1640 { 1641 StopWatch sw = new StopWatch(); 1642 sw.start(); 1643 1644 if( runFilters && m_filterManager != null ) 1645 pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata ); 1646 1647 MarkupParser mp = m_renderingManager.getParser( context, pagedata ); 1648 mp.addLocalLinkHook( localLinkHook ); 1649 mp.addExternalLinkHook( extLinkHook ); 1650 mp.addAttachmentLinkHook( attLinkHook ); 1651 1652 if( !parseAccessRules ) mp.disableAccessRules(); 1653 1654 WikiDocument doc = mp.parse(); 1655 1656 // 1657 // In some cases it's better just to parse, not to render 1658 // 1659 if( !justParse ) 1660 { 1661 result = m_renderingManager.getHTML( context, doc ); 1662 1663 if( runFilters && m_filterManager != null ) 1664 result = m_filterManager.doPostTranslateFiltering( context, result ); 1665 } 1666 1667 sw.stop(); 1668 1669 if( log.isDebugEnabled() ) 1670 log.debug("Page "+context.getRealPage().getName()+" rendered, took "+sw ); 1671 } 1672 catch( IOException e ) 1673 { 1674 log.error( "Failed to scan page data: ", e ); 1675 } 1676 catch( FilterException e ) 1677 { 1678 log.error( "page filter threw exception: ", e ); 1679 // FIXME: Don't yet know what to do 1680 } 1681 1682 return result; 1683 } 1684 1685 /** 1686 * Updates all references for the given page. 1687 * 1688 * @param page wiki page for which references should be updated 1689 */ 1690 public void updateReferences( WikiPage page ) 1691 { 1692 String pageData = getPureText( page.getName(), WikiProvider.LATEST_VERSION ); 1693 1694 m_referenceManager.updateReferences( page.getName(), 1695 scanWikiLinks( page, pageData ) ); 1696 } 1697 1698 1699 /** 1700 * Writes the WikiText of a page into the 1701 * page repository. If the <code>jspwiki.properties</code> file contains 1702 * the property <code>jspwiki.approver.workflow.saveWikiPage</code> and 1703 * its value resolves to a valid user, {@link org.apache.wiki.auth.authorize.Group} 1704 * or {@link org.apache.wiki.auth.authorize.Role}, this method will 1705 * place a {@link org.apache.wiki.workflow.Decision} in the approver's 1706 * workflow inbox and throw a {@link org.apache.wiki.workflow.DecisionRequiredException}. 1707 * If the submitting user is authenticated and the page save is rejected, 1708 * a notification will be placed in the user's decision queue. 1709 * 1710 * @since 2.1.28 1711 * @param context The current WikiContext 1712 * @param text The Wiki markup for the page. 1713 * @throws WikiException if the save operation encounters an error during the 1714 * save operation. If the page-save operation requires approval, the exception will 1715 * be of type {@link org.apache.wiki.workflow.DecisionRequiredException}. Individual 1716 * PageFilters, such as the {@link org.apache.wiki.filters.SpamFilter} may also 1717 * throw a {@link org.apache.wiki.api.exceptions.RedirectException}. 1718 */ 1719 public void saveText( WikiContext context, String text ) 1720 throws WikiException 1721 { 1722 // Check if page data actually changed; bail if not 1723 WikiPage page = context.getPage(); 1724 String oldText = getPureText( page ); 1725 String proposedText = TextUtil.normalizePostData( text ); 1726 if ( oldText != null && oldText.equals( proposedText ) ) 1727 { 1728 return; 1729 } 1730 1731 // Check if creation of empty pages is allowed; bail if not 1732 boolean allowEmpty = TextUtil.getBooleanProperty( m_properties, 1733 PROP_ALLOW_CREATION_OF_EMPTY_PAGES, 1734 false ); 1735 if ( !allowEmpty && !pageExists( page ) && text.trim().equals( "" ) ) 1736 { 1737 return; 1738 } 1739 1740 // Create approval workflow for page save; add the diffed, proposed 1741 // and old text versions as Facts for the approver (if approval is required) 1742 // If submitter is authenticated, any reject messages will appear in his/her workflow inbox. 1743 WorkflowBuilder builder = WorkflowBuilder.getBuilder( this ); 1744 Principal submitter = context.getCurrentUser(); 1745 Task prepTask = new PageManager.PreSaveWikiPageTask( context, proposedText ); 1746 Task completionTask = new PageManager.SaveWikiPageTask(); 1747 String diffText = m_differenceManager.makeDiff( context, oldText, proposedText ); 1748 boolean isAuthenticated = context.getWikiSession().isAuthenticated(); 1749 Fact[] facts = new Fact[5]; 1750 facts[0] = new Fact( PageManager.FACT_PAGE_NAME, page.getName() ); 1751 facts[1] = new Fact( PageManager.FACT_DIFF_TEXT, diffText ); 1752 facts[2] = new Fact( PageManager.FACT_PROPOSED_TEXT, proposedText ); 1753 facts[3] = new Fact( PageManager.FACT_CURRENT_TEXT, oldText); 1754 facts[4] = new Fact( PageManager.FACT_IS_AUTHENTICATED, Boolean.valueOf( isAuthenticated ) ); 1755 String rejectKey = isAuthenticated ? PageManager.SAVE_REJECT_MESSAGE_KEY : null; 1756 Workflow workflow = builder.buildApprovalWorkflow( submitter, 1757 PageManager.SAVE_APPROVER, 1758 prepTask, 1759 PageManager.SAVE_DECISION_MESSAGE_KEY, 1760 facts, 1761 completionTask, 1762 rejectKey ); 1763 m_workflowMgr.start(workflow); 1764 1765 // Let callers know if the page-save requires approval 1766 if ( workflow.getCurrentStep() instanceof Decision ) 1767 { 1768 throw new DecisionRequiredException( "The page contents must be approved before they become active." ); 1769 } 1770 } 1771 1772 /** 1773 * Returns the number of pages in this Wiki 1774 * @return The total number of pages. 1775 */ 1776 public int getPageCount() 1777 { 1778 return m_pageManager.getTotalPageCount(); 1779 } 1780 1781 /** 1782 * Returns the provider name. 1783 * @return The full class name of the current page provider. 1784 */ 1785 1786 public String getCurrentProvider() 1787 { 1788 return m_pageManager.getProvider().getClass().getName(); 1789 } 1790 1791 /** 1792 * Return information about current provider. This method just calls 1793 * the corresponding PageManager method, which in turn calls the 1794 * provider method. 1795 * 1796 * @return A textual description of the current provider. 1797 * @since 1.6.4 1798 */ 1799 public String getCurrentProviderInfo() 1800 { 1801 return m_pageManager.getProviderDescription(); 1802 } 1803 1804 /** 1805 * Returns a Collection of WikiPages, sorted in time 1806 * order of last change (i.e. first object is the most 1807 * recently changed). This method also includes attachments. 1808 * 1809 * @return Collection of WikiPage objects. In reality, the returned 1810 * collection is a Set, but due to API compatibility reasons, 1811 * we're not changing the signature soon... 1812 */ 1813 1814 // FIXME: Should really get a Date object and do proper comparisons. 1815 // This is terribly wasteful. 1816 @SuppressWarnings("unchecked") 1817 public Collection getRecentChanges() 1818 { 1819 try 1820 { 1821 Collection<WikiPage> pages = m_pageManager.getAllPages(); 1822 Collection<Attachment> atts = m_attachmentManager.getAllAttachments(); 1823 1824 TreeSet<WikiPage> sortedPages = new TreeSet<WikiPage>( new PageTimeComparator() ); 1825 1826 sortedPages.addAll( pages ); 1827 sortedPages.addAll( atts ); 1828 1829 return sortedPages; 1830 } 1831 catch( ProviderException e ) 1832 { 1833 log.error( "Unable to fetch all pages: ",e); 1834 return null; 1835 } 1836 } 1837 1838 /** 1839 * Parses an incoming search request, then 1840 * does a search. 1841 * <P> 1842 * The query is dependent on the actual chosen search provider - each one of them has 1843 * a language of its own. 1844 * 1845 * @param query The query string 1846 * @return A Collection of SearchResult objects. 1847 * @throws ProviderException If the searching failed 1848 * @throws IOException If the searching failed 1849 */ 1850 1851 // 1852 // FIXME: Should also have attributes attached. 1853 // 1854 public Collection findPages( String query ) 1855 throws ProviderException, IOException 1856 { 1857 Collection results = m_searchManager.findPages( query ); 1858 1859 return results; 1860 } 1861 1862 /** 1863 * Finds the corresponding WikiPage object based on the page name. It always finds 1864 * the latest version of a page. 1865 * 1866 * @param pagereq The name of the page to look for. 1867 * @return A WikiPage object, or null, if the page by the name could not be found. 1868 */ 1869 1870 public WikiPage getPage( String pagereq ) 1871 { 1872 return getPage( pagereq, WikiProvider.LATEST_VERSION ); 1873 } 1874 1875 /** 1876 * Finds the corresponding WikiPage object base on the page name and version. 1877 * 1878 * @param pagereq The name of the page to look for. 1879 * @param version The version number to look for. May be WikiProvider.LATEST_VERSION, 1880 * in which case it will look for the latest version (and this method then becomes 1881 * the equivalent of getPage(String). 1882 * 1883 * @return A WikiPage object, or null, if the page could not be found; or if there 1884 * is no such version of the page. 1885 * @since 1.6.7. 1886 */ 1887 1888 public WikiPage getPage( String pagereq, int version ) 1889 { 1890 try 1891 { 1892 WikiPage p = m_pageManager.getPageInfo( pagereq, version ); 1893 1894 if( p == null ) 1895 { 1896 p = m_attachmentManager.getAttachmentInfo( (WikiContext)null, pagereq ); 1897 } 1898 1899 return p; 1900 } 1901 catch( ProviderException e ) 1902 { 1903 log.error( "Unable to fetch page info",e); 1904 return null; 1905 } 1906 } 1907 1908 1909 /** 1910 * Returns a Collection of WikiPages containing the 1911 * version history of a page. 1912 * 1913 * @param page Name of the page to look for 1914 * @return an ordered List of WikiPages, each corresponding to a different 1915 * revision of the page. 1916 */ 1917 1918 public List getVersionHistory( String page ) 1919 { 1920 List c = null; 1921 1922 try 1923 { 1924 c = m_pageManager.getVersionHistory( page ); 1925 1926 if( c == null ) 1927 { 1928 c = m_attachmentManager.getVersionHistory( page ); 1929 } 1930 } 1931 catch( ProviderException e ) 1932 { 1933 log.error( "FIXME", e ); 1934 } 1935 1936 return c; 1937 } 1938 1939 /** 1940 * Returns a diff of two versions of a page. 1941 * <p> 1942 * Note that the API was changed in 2.6 to provide a WikiContext object! 1943 * 1944 * @param context The WikiContext of the page you wish to get a diff from 1945 * @param version1 Version number of the old page. If 1946 * WikiPageProvider.LATEST_VERSION (-1), then uses current page. 1947 * @param version2 Version number of the new page. If 1948 * WikiPageProvider.LATEST_VERSION (-1), then uses current page. 1949 * 1950 * @return A HTML-ized difference between two pages. If there is no difference, 1951 * returns an empty string. 1952 */ 1953 public String getDiff( WikiContext context, int version1, int version2 ) 1954 { 1955 String page = context.getPage().getName(); 1956 String page1 = getPureText( page, version1 ); 1957 String page2 = getPureText( page, version2 ); 1958 1959 // Kludge to make diffs for new pages to work this way. 1960 1961 if( version1 == WikiPageProvider.LATEST_VERSION ) 1962 { 1963 page1 = ""; 1964 } 1965 1966 String diff = m_differenceManager.makeDiff( context, page1, page2 ); 1967 1968 return diff; 1969 } 1970 1971 /** 1972 * Returns this object's ReferenceManager. 1973 * @return The current ReferenceManager instance. 1974 * 1975 * @since 1.6.1 1976 */ 1977 public ReferenceManager getReferenceManager() 1978 { 1979 return m_referenceManager; 1980 } 1981 1982 /** 1983 * Returns the current rendering manager for this wiki application. 1984 * 1985 * @since 2.3.27 1986 * @return A RenderingManager object. 1987 */ 1988 public RenderingManager getRenderingManager() 1989 { 1990 return m_renderingManager; 1991 } 1992 1993 /** 1994 * Returns the current plugin manager. 1995 * 1996 * In 2.10 the PluginManager will be returned instead of the generic 1997 * 1998 * @since 1.6.1 1999 * @return The current PluginManager instance 2000 */ 2001 @SuppressWarnings("unchecked") 2002 public < T extends PluginManager > T getPluginManager() 2003 { 2004 return (T)m_pluginManager; 2005 } 2006 2007 /** 2008 * Returns the current variable manager. 2009 * @return The current VariableManager. 2010 */ 2011 2012 public VariableManager getVariableManager() 2013 { 2014 return m_variableManager; 2015 } 2016 2017 /** 2018 * Shortcut to getVariableManager().getValue(). However, this method does not 2019 * throw a NoSuchVariableException, but returns null in case the variable does 2020 * not exist. 2021 * 2022 * @param context WikiContext to look the variable in 2023 * @param name Name of the variable to look for 2024 * @return Variable value, or null, if there is no such variable. 2025 * @since 2.2 2026 */ 2027 public String getVariable( WikiContext context, String name ) 2028 { 2029 try 2030 { 2031 return m_variableManager.getValue( context, name ); 2032 } 2033 catch( NoSuchVariableException e ) 2034 { 2035 return null; 2036 } 2037 } 2038 2039 /** 2040 * Returns the current PageManager which is responsible for storing 2041 * and managing WikiPages. 2042 * 2043 * @return The current PageManager instance. 2044 */ 2045 public PageManager getPageManager() 2046 { 2047 return m_pageManager; 2048 } 2049 2050 /** 2051 * Returns the CommandResolver for this wiki engine. 2052 * @return the resolver 2053 */ 2054 public CommandResolver getCommandResolver() 2055 { 2056 return m_commandResolver; 2057 } 2058 2059 /** 2060 * Returns the current AttachmentManager, which is responsible for 2061 * storing and managing attachments. 2062 * 2063 * @since 1.9.31. 2064 * @return The current AttachmentManager instance 2065 */ 2066 public AttachmentManager getAttachmentManager() 2067 { 2068 return m_attachmentManager; 2069 } 2070 2071 /** 2072 * Returns the currently used authorization manager. 2073 * 2074 * @return The current AuthorizationManager instance 2075 */ 2076 public AuthorizationManager getAuthorizationManager() 2077 { 2078 return m_authorizationManager; 2079 } 2080 2081 /** 2082 * Returns the currently used authentication manager. 2083 * 2084 * @return The current AuthenticationManager instance. 2085 */ 2086 public AuthenticationManager getAuthenticationManager() 2087 { 2088 return m_authenticationManager; 2089 } 2090 2091 /** 2092 * Returns the manager responsible for the filters. 2093 * @since 2.1.88 2094 * @return The current FilterManager instance 2095 */ 2096 @SuppressWarnings("unchecked") 2097 public < T extends FilterManager > T getFilterManager() 2098 { 2099 return (T)m_filterManager; 2100 } 2101 2102 /** 2103 * Returns the manager responsible for searching the Wiki. 2104 * @since 2.2.21 2105 * @return The current SearchManager instance 2106 */ 2107 public SearchManager getSearchManager() 2108 { 2109 return m_searchManager; 2110 } 2111 2112 /** 2113 * Returns the progress manager we're using 2114 * @return A ProgressManager 2115 * @since 2.6 2116 */ 2117 public ProgressManager getProgressManager() 2118 { 2119 return m_progressManager; 2120 } 2121 2122 /** 2123 * Figure out to which page we are really going to. Considers 2124 * special page names from the jspwiki.properties, and possible aliases. 2125 * This method delgates requests to 2126 * {@link org.apache.wiki.WikiContext#getRedirectURL()}. 2127 * @param context The Wiki Context in which the request is being made. 2128 * @return A complete URL to the new page to redirect to 2129 * @since 2.2 2130 */ 2131 2132 public String getRedirectURL( WikiContext context ) 2133 { 2134 return context.getRedirectURL(); 2135 } 2136 2137 /** 2138 * Shortcut to create a WikiContext from a supplied HTTP request, 2139 * using a default wiki context. 2140 * @param request the HTTP request 2141 * @param requestContext the default context to use 2142 * @return a new WikiContext object. 2143 * 2144 * @see org.apache.wiki.ui.CommandResolver 2145 * @see org.apache.wiki.ui.Command 2146 * @since 2.1.15. 2147 */ 2148 // FIXME: We need to have a version which takes a fixed page 2149 // name as well, or check it elsewhere. 2150 public WikiContext createContext( HttpServletRequest request, 2151 String requestContext ) 2152 { 2153 if( !m_isConfigured ) 2154 { 2155 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."); 2156 } 2157 2158 // Build the wiki context 2159 Command command = m_commandResolver.findCommand( request, requestContext ); 2160 return new WikiContext( this, request, command ); 2161 } 2162 2163 /** 2164 * Deletes a page or an attachment completely, including all versions. If the page 2165 * does not exist, does nothing. 2166 * 2167 * @param pageName The name of the page. 2168 * @throws ProviderException If something goes wrong. 2169 */ 2170 public void deletePage( String pageName ) 2171 throws ProviderException 2172 { 2173 WikiPage p = getPage( pageName ); 2174 2175 if( p != null ) 2176 { 2177 if( p instanceof Attachment ) 2178 { 2179 m_attachmentManager.deleteAttachment( (Attachment) p ); 2180 } 2181 else 2182 { 2183 if (m_attachmentManager.hasAttachments( p )) 2184 { 2185 Collection attachments = m_attachmentManager.listAttachments( p ); 2186 for( Iterator atti = attachments.iterator(); atti.hasNext(); ) 2187 { 2188 m_attachmentManager.deleteAttachment( (Attachment)(atti.next()) ); 2189 } 2190 } 2191 m_pageManager.deletePage( p ); 2192 firePageEvent( WikiPageEvent.PAGE_DELETED, pageName ); 2193 } 2194 } 2195 } 2196 2197 /** 2198 * Deletes a specific version of a page or an attachment. 2199 * 2200 * @param page The page object. 2201 * @throws ProviderException If something goes wrong. 2202 */ 2203 public void deleteVersion( WikiPage page ) 2204 throws ProviderException 2205 { 2206 if( page instanceof Attachment ) 2207 { 2208 m_attachmentManager.deleteVersion( (Attachment) page ); 2209 } 2210 else 2211 { 2212 m_pageManager.deleteVersion( page ); 2213 } 2214 } 2215 2216 /** 2217 * Returns the URL of the global RSS file. May be null, if the 2218 * RSS file generation is not operational. 2219 * @since 1.7.10 2220 * @return The global RSS url 2221 */ 2222 public String getGlobalRSSURL() 2223 { 2224 if( m_rssGenerator != null && m_rssGenerator.isEnabled() ) 2225 { 2226 return getBaseURL()+m_rssFile; 2227 } 2228 2229 return null; 2230 } 2231 2232 /** 2233 * Returns the root path. The root path is where the WikiEngine is 2234 * located in the file system. 2235 * 2236 * @since 2.2 2237 * @return A path to where the Wiki is installed in the local filesystem. 2238 */ 2239 public String getRootPath() 2240 { 2241 return m_rootPath; 2242 } 2243 2244 /** 2245 * @since 2.2.6 2246 * @return the URL constructor 2247 */ 2248 public URLConstructor getURLConstructor() 2249 { 2250 return m_urlConstructor; 2251 } 2252 2253 /** 2254 * Returns the RSSGenerator. If the property <code>jspwiki.rss.generate</code> 2255 * has not been set to <code>true</code>, this method will return <code>null</code>, 2256 * <em>and callers should check for this value.</em> 2257 * @since 2.1.165 2258 * @return the RSS generator 2259 */ 2260 public RSSGenerator getRSSGenerator() 2261 { 2262 return m_rssGenerator; 2263 } 2264 2265 /** 2266 * Renames, or moves, a wiki page. Can also alter referring wiki 2267 * links to point to the renamed page. 2268 * 2269 * @param context The context during which this rename takes 2270 * place. 2271 * @param renameFrom Name of the source page. 2272 * @param renameTo Name of the destination page. 2273 * @param changeReferrers If true, then changes any referring links 2274 * to point to the renamed page. 2275 * 2276 * @return The name of the page that the source was renamed to. 2277 * 2278 * @throws WikiException In the case of an error, such as the destination 2279 * page already existing. 2280 */ 2281 public String renamePage( WikiContext context, 2282 String renameFrom, 2283 String renameTo, 2284 boolean changeReferrers) 2285 throws WikiException 2286 { 2287 String newPageName = m_pageRenamer.renamePage(context, renameFrom, renameTo, changeReferrers); 2288 firePageRenameEvent(renameFrom, newPageName); 2289 return newPageName; 2290 } 2291 2292 /** 2293 * Returns the PageRenamer employed by this WikiEngine. 2294 * @since 2.5.141 2295 * @return The current PageRenamer instance. 2296 */ 2297 public PageRenamer getPageRenamer() 2298 { 2299 return m_pageRenamer; 2300 } 2301 2302 /** 2303 * Returns the UserManager employed by this WikiEngine. 2304 * @since 2.3 2305 * @return The current UserManager instance. 2306 */ 2307 public UserManager getUserManager() 2308 { 2309 return m_userManager; 2310 } 2311 2312 /** 2313 * Returns the GroupManager employed by this WikiEngine. 2314 * @since 2.3 2315 * @return The current GroupManager instance 2316 */ 2317 public GroupManager getGroupManager() 2318 { 2319 return m_groupManager; 2320 } 2321 2322 /** 2323 * Returns the current {@link AdminBeanManager}. 2324 * 2325 * @return The current {@link AdminBeanManager}. 2326 * @since 2.6 2327 */ 2328 public AdminBeanManager getAdminBeanManager() { 2329 return m_adminBeanManager; 2330 } 2331 2332 /** 2333 * Returns the AclManager employed by this WikiEngine. 2334 * The AclManager is lazily initialized. 2335 * <p> 2336 * The AclManager implementing class may be set by the 2337 * System property {@link #PROP_ACL_MANAGER_IMPL}. 2338 * </p> 2339 * 2340 * @since 2.3 2341 * @return The current AclManager. 2342 */ 2343 public AclManager getAclManager() 2344 { 2345 if( m_aclManager == null ) 2346 { 2347 try 2348 { 2349 String s = m_properties.getProperty( PROP_ACL_MANAGER_IMPL, 2350 DefaultAclManager.class.getName() ); 2351 m_aclManager = (AclManager)ClassUtil.getMappedObject(s); // TODO: I am not sure whether this is the right call 2352 m_aclManager.initialize( this, m_properties ); 2353 } 2354 catch ( WikiException we ) 2355 { 2356 log.fatal( "unable to instantiate class for AclManager: " + we.getMessage() ); 2357 throw new InternalWikiException("Cannot instantiate AclManager, please check logs."); 2358 } 2359 } 2360 return m_aclManager; 2361 } 2362 2363 /** 2364 * Returns the DifferenceManager so that texts can be compared. 2365 * @return the difference manager 2366 */ 2367 public DifferenceManager getDifferenceManager() 2368 { 2369 return m_differenceManager; 2370 } 2371 2372 /** 2373 * Returns the current EditorManager instance. 2374 * 2375 * @return The current EditorManager. 2376 */ 2377 public EditorManager getEditorManager() 2378 { 2379 return m_editorManager; 2380 } 2381 2382 /** 2383 * Returns the current i18n manager. 2384 * 2385 * @return The current Intertan... Interante... Internatatializ... Whatever. 2386 */ 2387 public InternationalizationManager getInternationalizationManager() 2388 { 2389 return m_internationalizationManager; 2390 } 2391 2392 /** 2393 * Registers a WikiEventListener with this instance. 2394 * @param listener the event listener 2395 */ 2396 public final synchronized void addWikiEventListener( WikiEventListener listener ) 2397 { 2398 WikiEventManager.addWikiEventListener( this, listener ); 2399 } 2400 2401 /** 2402 * Un-registers a WikiEventListener with this instance. 2403 * @param listener the event listener 2404 */ 2405 public final synchronized void removeWikiEventListener( WikiEventListener listener ) 2406 { 2407 WikiEventManager.removeWikiEventListener( this, listener ); 2408 } 2409 2410 /** 2411 * Fires a WikiEngineEvent to all registered listeners. 2412 * @param type the event type 2413 */ 2414 protected final void fireEvent( int type ) 2415 { 2416 if ( WikiEventManager.isListening(this) ) 2417 { 2418 WikiEventManager.fireEvent(this,new WikiEngineEvent(this,type)); 2419 } 2420 } 2421 2422 /** 2423 * Fires a WikiPageEvent to all registered listeners. 2424 * @param type the event type 2425 */ 2426 protected final void firePageEvent( int type, String pageName ) 2427 { 2428 if ( WikiEventManager.isListening(this) ) 2429 { 2430 WikiEventManager.fireEvent(this,new WikiPageEvent(this,type,pageName)); 2431 } 2432 } 2433 2434 /** 2435 * Fires a WikiPageRenameEvent to all registered listeners. 2436 * @param oldName the former page name 2437 * @param newName the new page name 2438 */ 2439 protected final void firePageRenameEvent(String oldName, String newName ) 2440 { 2441 if ( WikiEventManager.isListening(this) ) 2442 { 2443 WikiEventManager.fireEvent(this,new WikiPageRenameEvent(this,oldName,newName)); 2444 } 2445 } 2446 2447 /** 2448 * Adds an attribute to the engine for the duration of this engine. The 2449 * value is not persisted. 2450 * 2451 * @since 2.4.91 2452 * @param key the attribute name 2453 * @param value the value 2454 */ 2455 public void setAttribute( String key, Object value ) 2456 { 2457 m_attributes.put( key, value ); 2458 } 2459 2460 /** 2461 * Gets an attribute from the engine. 2462 * 2463 * @param key the attribute name 2464 * @return the value 2465 */ 2466 public Object getAttribute( String key ) 2467 { 2468 return m_attributes.get( key ); 2469 } 2470 2471 /** 2472 * Removes an attribute. 2473 * 2474 * @param key The key of the attribute to remove. 2475 * @return The previous attribute, if it existed. 2476 */ 2477 public Object removeAttribute( String key ) 2478 { 2479 return m_attributes.remove( key ); 2480 } 2481 2482 /** 2483 * Returns a WatchDog for current thread. 2484 * 2485 * @return The current thread WatchDog. 2486 * @since 2.4.92 2487 */ 2488 public WatchDog getCurrentWatchDog() 2489 { 2490 return WatchDog.getCurrentWatchDog(this); 2491 } 2492 2493 /** 2494 * Initialize the page name comparator. 2495 */ 2496 private void initPageSorter( Properties props ) 2497 { 2498 m_pageSorter = new PageSorter(); 2499 m_pageSorter.initialize( props ); 2500 } 2501 2502 /** 2503 * Get this engine's page name comparator. 2504 * 2505 * @return the PageSorter used to sort pages by name in this engine 2506 */ 2507 public PageSorter getPageSorter() 2508 { 2509 return m_pageSorter; 2510 } 2511 }