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 */ 019package org.apache.wiki; 020 021import java.io.File; 022import java.io.IOException; 023import java.io.UnsupportedEncodingException; 024import java.net.URLDecoder; 025import java.net.URLEncoder; 026import java.security.Principal; 027import java.util.ArrayList; 028import java.util.Collection; 029import java.util.Collections; 030import java.util.Date; 031import java.util.Enumeration; 032import java.util.HashMap; 033import java.util.Iterator; 034import java.util.List; 035import java.util.Locale; 036import java.util.Map; 037import java.util.Properties; 038import java.util.TimeZone; 039import java.util.TreeSet; 040 041import javax.servlet.ServletConfig; 042import javax.servlet.ServletContext; 043import javax.servlet.ServletRequest; 044import javax.servlet.http.HttpServletRequest; 045 046import org.apache.commons.lang.time.StopWatch; 047import org.apache.log4j.Logger; 048import org.apache.log4j.PropertyConfigurator; 049import org.apache.wiki.api.engine.AdminBeanManager; 050import org.apache.wiki.api.engine.FilterManager; 051import org.apache.wiki.api.engine.PluginManager; 052import org.apache.wiki.api.exceptions.FilterException; 053import org.apache.wiki.api.exceptions.NoSuchVariableException; 054import org.apache.wiki.api.exceptions.ProviderException; 055import org.apache.wiki.api.exceptions.WikiException; 056import org.apache.wiki.attachment.Attachment; 057import org.apache.wiki.attachment.AttachmentManager; 058import org.apache.wiki.auth.AuthenticationManager; 059import org.apache.wiki.auth.AuthorizationManager; 060import org.apache.wiki.auth.UserManager; 061import org.apache.wiki.auth.acl.AclManager; 062import org.apache.wiki.auth.acl.DefaultAclManager; 063import org.apache.wiki.auth.authorize.GroupManager; 064import org.apache.wiki.content.PageRenamer; 065import org.apache.wiki.diff.DifferenceManager; 066import org.apache.wiki.event.WikiEngineEvent; 067import org.apache.wiki.event.WikiEventListener; 068import org.apache.wiki.event.WikiEventManager; 069import org.apache.wiki.event.WikiPageEvent; 070import org.apache.wiki.event.WikiPageRenameEvent; 071import org.apache.wiki.i18n.InternationalizationManager; 072import org.apache.wiki.parser.MarkupParser; 073import org.apache.wiki.parser.WikiDocument; 074import org.apache.wiki.providers.WikiPageProvider; 075import org.apache.wiki.render.RenderingManager; 076import org.apache.wiki.rss.RSSGenerator; 077import org.apache.wiki.rss.RSSThread; 078import org.apache.wiki.search.SearchManager; 079import org.apache.wiki.ui.Command; 080import org.apache.wiki.ui.CommandResolver; 081import org.apache.wiki.ui.EditorManager; 082import org.apache.wiki.ui.TemplateManager; 083import org.apache.wiki.ui.progress.ProgressManager; 084import org.apache.wiki.url.URLConstructor; 085import org.apache.wiki.util.ClassUtil; 086import org.apache.wiki.util.PropertyReader; 087import org.apache.wiki.util.TextUtil; 088import org.apache.wiki.util.comparators.PageTimeComparator; 089import org.apache.wiki.workflow.Decision; 090import org.apache.wiki.workflow.DecisionRequiredException; 091import org.apache.wiki.workflow.Fact; 092import org.apache.wiki.workflow.Task; 093import org.apache.wiki.workflow.Workflow; 094import org.apache.wiki.workflow.WorkflowBuilder; 095import 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 */ 112public 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 = TextUtil.getStringProperty(props,"jspwiki.use.external.logconfig","false"); 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.getMessage(), 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.getMessage(), 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.getMessage(), 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. Caused by: " + e.getMessage() + 658 "; please check log files for better information.", e ); 659 } 660 661 // 662 // Initialize the good-to-have-but-not-fatal modules. 663 // 664 try 665 { 666 if( TextUtil.getBooleanProperty( props, 667 RSSGenerator.PROP_GENERATE_RSS, 668 false ) ) 669 { 670 m_rssGenerator = (RSSGenerator)ClassUtil.getMappedObject(RSSGenerator.class.getName(), this, props ); 671 } 672 673 m_pageRenamer = (PageRenamer)ClassUtil.getMappedObject(PageRenamer.class.getName(), this, props ); 674 } 675 catch( Exception e ) 676 { 677 log.error( "Unable to start RSS generator - JSPWiki will still work, "+ 678 "but there will be no RSS feed.", e ); 679 } 680 681 // Start the RSS generator & generator thread 682 if( m_rssGenerator != null ) 683 { 684 m_rssFile = TextUtil.getStringProperty( props, 685 RSSGenerator.PROP_RSSFILE, "rss.rdf" ); 686 File rssFile=null; 687 if (m_rssFile.startsWith(File.separator)) 688 { 689 // honor absolute pathnames: 690 rssFile = new File(m_rssFile ); 691 } 692 else 693 { 694 // relative path names are anchored from the webapp root path: 695 rssFile = new File( getRootPath(), m_rssFile ); 696 } 697 int rssInterval = TextUtil.getIntegerProperty( props, 698 RSSGenerator.PROP_INTERVAL, 3600 ); 699 RSSThread rssThread = new RSSThread( this, rssFile, rssInterval ); 700 rssThread.start(); 701 } 702 703 fireEvent( WikiEngineEvent.INITIALIZED ); // initialization complete 704 705 log.info("WikiEngine configured."); 706 m_isConfigured = true; 707 } 708 709 /** 710 * Initializes the reference manager. Scans all existing WikiPages for 711 * internal links and adds them to the ReferenceManager object. 712 * 713 * @throws WikiException If the reference manager initialization fails. 714 */ 715 @SuppressWarnings("unchecked") 716 public void initReferenceManager() throws WikiException 717 { 718 try 719 { 720 ArrayList<WikiPage> pages = new ArrayList<WikiPage>(); 721 pages.addAll( m_pageManager.getAllPages() ); 722 pages.addAll( m_attachmentManager.getAllAttachments() ); 723 724 // Build a new manager with default key lists. 725 if( m_referenceManager == null ) 726 { 727 m_referenceManager = 728 (ReferenceManager) ClassUtil.getMappedObject(ReferenceManager.class.getName(), this ); 729 m_referenceManager.initialize( pages ); 730 } 731 732 } 733 catch( ProviderException e ) 734 { 735 log.fatal("PageProvider is unable to list pages: ", e); 736 } 737 } 738 739 /** 740 * Returns the set of properties that the WikiEngine was initialized 741 * with. Note that this method returns a direct reference, so it's possible 742 * to manipulate the properties. However, this is not advised unless you 743 * really know what you're doing. 744 * 745 * @return The wiki properties 746 */ 747 748 public Properties getWikiProperties() 749 { 750 return m_properties; 751 } 752 753 /** 754 * Returns the JSPWiki working directory set with "jspwiki.workDir". 755 * 756 * @since 2.1.100 757 * @return The working directory. 758 */ 759 public String getWorkDir() 760 { 761 return m_workDir; 762 } 763 764 /** 765 * Returns the current template directory. 766 * 767 * @since 1.9.20 768 * @return The template directory as initialized by the engine. 769 */ 770 public String getTemplateDir() 771 { 772 return m_templateDir; 773 } 774 775 /** 776 * Returns the current TemplateManager. 777 * 778 * @return A TemplateManager instance. 779 */ 780 public TemplateManager getTemplateManager() 781 { 782 return m_templateManager; 783 } 784 785 /** 786 * Returns the base URL, telling where this Wiki actually lives. 787 * 788 * @since 1.6.1 789 * @return The Base URL. 790 */ 791 792 public String getBaseURL() 793 { 794 return m_baseURL; 795 } 796 797 /** 798 * Returns the moment when this engine was started. 799 * 800 * @since 2.0.15. 801 * @return The start time of this wiki. 802 */ 803 804 public Date getStartTime() 805 { 806 return (Date)m_startTime.clone(); 807 } 808 809 /** 810 * <p> 811 * Returns the basic absolute URL to a page, without any modifications. You 812 * may add any parameters to this. 813 * </p> 814 * <p> 815 * Since 2.3.90 it is safe to call this method with <code>null</code> 816 * pageName, in which case it will default to the front page. 817 * </p> 818 * @since 2.0.3 819 * @param pageName The name of the page. May be null, in which case defaults to the front page. 820 * @return An absolute URL to the page. 821 */ 822 public String getViewURL( String pageName ) 823 { 824 if( pageName == null ) 825 { 826 pageName = getFrontPage(); 827 } 828 return getURLConstructor().makeURL( WikiContext.VIEW, pageName, true, null ); 829 } 830 831 /** 832 * Returns the basic URL to an editor. Please use WikiContext.getURL() or 833 * WikiEngine.getURL() instead. 834 * 835 * @see #getURL(String, String, String, boolean) 836 * @see WikiContext#getURL(String, String) 837 * @deprecated 838 * 839 * @param pageName The name of the page. 840 * @return An URI. 841 * 842 * @since 2.0.3 843 */ 844 public String getEditURL( String pageName ) 845 { 846 return m_urlConstructor.makeURL( WikiContext.EDIT, pageName, false, null ); 847 } 848 849 /** 850 * Returns the basic attachment URL.Please use WikiContext.getURL() or 851 * WikiEngine.getURL() instead. 852 * 853 * @see #getURL(String, String, String, boolean) 854 * @see WikiContext#getURL(String, String) 855 * @since 2.0.42. 856 * @param attName Attachment name 857 * @deprecated 858 * @return An URI. 859 */ 860 public String getAttachmentURL( String attName ) 861 { 862 return m_urlConstructor.makeURL( WikiContext.ATTACH, attName, false, null ); 863 } 864 865 /** 866 * Returns an URL if a WikiContext is not available. 867 * 868 * @param context The WikiContext (VIEW, EDIT, etc...) 869 * @param pageName Name of the page, as usual 870 * @param params List of parameters. May be null, if no parameters. 871 * @param absolute If true, will generate an absolute URL regardless of properties setting. 872 * @return An URL (absolute or relative). 873 */ 874 public String getURL( String context, String pageName, String params, boolean absolute ) 875 { 876 if( pageName == null ) pageName = getFrontPage(); 877 return m_urlConstructor.makeURL( context, pageName, absolute, params ); 878 } 879 880 /** 881 * Returns the default front page, if no page is used. 882 * 883 * @return The front page name. 884 */ 885 886 public String getFrontPage() 887 { 888 return m_frontPage; 889 } 890 891 /** 892 * Returns the ServletContext that this particular WikiEngine was 893 * initialized with. <B>It may return null</B>, if the WikiEngine is not 894 * running inside a servlet container! 895 * 896 * @since 1.7.10 897 * @return ServletContext of the WikiEngine, or null. 898 */ 899 900 public ServletContext getServletContext() 901 { 902 return m_servletContext; 903 } 904 905 /** 906 * This is a safe version of the Servlet.Request.getParameter() routine. 907 * Unfortunately, the default version always assumes that the incoming 908 * character set is ISO-8859-1, even though it was something else. 909 * This means that we need to make a new string using the correct 910 * encoding. 911 * <P> 912 * For more information, see: 913 * <A HREF="http://www.jguru.com/faq/view.jsp?EID=137049">JGuru FAQ</A>. 914 * <P> 915 * Incidentally, this is almost the same as encodeName(), below. 916 * I am not yet entirely sure if it's safe to merge the code. 917 * 918 * @param request The servlet request 919 * @param name The parameter name to get. 920 * @return The parameter value or null 921 * @since 1.5.3 922 * @deprecated JSPWiki now requires servlet API 2.3, which has a better 923 * way of dealing with this stuff. This will be removed in 924 * the near future. 925 */ 926 927 public String safeGetParameter( ServletRequest request, String name ) 928 { 929 try 930 { 931 String res = request.getParameter( name ); 932 if( res != null ) 933 { 934 res = new String(res.getBytes("ISO-8859-1"), 935 getContentEncoding() ); 936 } 937 938 return res; 939 } 940 catch( UnsupportedEncodingException e ) 941 { 942 log.fatal( "Unsupported encoding", e ); 943 return ""; 944 } 945 946 } 947 948 /** 949 * Returns the query string (the portion after the question mark). 950 * 951 * @param request The HTTP request to parse. 952 * @return The query string. If the query string is null, 953 * returns an empty string. 954 * 955 * @since 2.1.3 956 */ 957 public String safeGetQueryString( HttpServletRequest request ) 958 { 959 if (request == null) 960 { 961 return ""; 962 } 963 964 try 965 { 966 String res = request.getQueryString(); 967 if( res != null ) 968 { 969 res = new String(res.getBytes("ISO-8859-1"), 970 getContentEncoding() ); 971 972 // 973 // Ensure that the 'page=xyz' attribute is removed 974 // FIXME: Is it really the mandate of this routine to 975 // do that? 976 // 977 int pos1 = res.indexOf("page="); 978 if (pos1 >= 0) 979 { 980 String tmpRes = res.substring(0, pos1); 981 int pos2 = res.indexOf("&",pos1) + 1; 982 if ( (pos2 > 0) && (pos2 < res.length()) ) 983 { 984 tmpRes = tmpRes + res.substring(pos2); 985 } 986 res = tmpRes; 987 } 988 } 989 990 return res; 991 } 992 catch( UnsupportedEncodingException e ) 993 { 994 log.fatal( "Unsupported encoding", e ); 995 return ""; 996 } 997 } 998 999 /** 1000 * Returns an URL to some other Wiki that we know. 1001 * 1002 * @param wikiName The name of the other wiki. 1003 * @return null, if no such reference was found. 1004 */ 1005 public String getInterWikiURL( String wikiName ) 1006 { 1007 return TextUtil.getStringProperty(m_properties,PROP_INTERWIKIREF+wikiName,null); 1008 } 1009 1010 /** 1011 * Returns a collection of all supported InterWiki links. 1012 * 1013 * @return A Collection of Strings. 1014 */ 1015 public Collection< String > getAllInterWikiLinks() 1016 { 1017 ArrayList< String > list = new ArrayList< String >(); 1018 1019 for( Enumeration< ? > i = m_properties.propertyNames(); i.hasMoreElements(); ) 1020 { 1021 String prop = ( String )i.nextElement(); 1022 1023 if( prop.startsWith( PROP_INTERWIKIREF ) ) 1024 { 1025 list.add( prop.substring( prop.lastIndexOf( "." ) + 1 ) ); 1026 } 1027 } 1028 1029 return list; 1030 } 1031 1032 /** 1033 * Returns a collection of all image types that get inlined. 1034 * 1035 * @return A Collection of Strings with a regexp pattern. 1036 */ 1037 public Collection< String > getAllInlinedImagePatterns() 1038 { 1039 Properties props = getWikiProperties(); 1040 ArrayList<String> ptrnlist = new ArrayList<String>(); 1041 1042 for( Enumeration< ? > e = props.propertyNames(); e.hasMoreElements(); ) 1043 { 1044 String name = ( String )e.nextElement(); 1045 1046 if( name.startsWith( PROP_INLINEIMAGEPTRN ) ) 1047 { 1048 String ptrn = TextUtil.getStringProperty( props, name, null ); 1049 1050 ptrnlist.add( ptrn ); 1051 } 1052 } 1053 1054 if( ptrnlist.size() == 0 ) 1055 { 1056 ptrnlist.add( DEFAULT_INLINEPATTERN ); 1057 } 1058 1059 return ptrnlist; 1060 } 1061 1062 /** 1063 * <p>If the page is a special page, then returns a direct URL 1064 * to that page. Otherwise returns <code>null</code>. 1065 * This method delegates requests to 1066 * {@link org.apache.wiki.ui.CommandResolver#getSpecialPageReference(String)}. 1067 * </p> 1068 * <p> 1069 * Special pages are defined in jspwiki.properties using the jspwiki.specialPage 1070 * setting. They're typically used to give Wiki page names to e.g. custom JSP 1071 * pages. 1072 * </p> 1073 * 1074 * @param original The page to check 1075 * @return A reference to the page, or null, if there's no special page. 1076 */ 1077 public String getSpecialPageReference( String original ) 1078 { 1079 return m_commandResolver.getSpecialPageReference( original ); 1080 } 1081 1082 /** 1083 * Returns the name of the application. 1084 * 1085 * @return A string describing the name of this application. 1086 */ 1087 1088 // FIXME: Should use servlet context as a default instead of a constant. 1089 public String getApplicationName() 1090 { 1091 String appName = TextUtil.getStringProperty(m_properties,PROP_APPNAME,Release.APPNAME); 1092 1093 return MarkupParser.cleanLink( appName ); 1094 } 1095 1096 /** 1097 * Beautifies the title of the page by appending spaces in suitable 1098 * places, if the user has so decreed in the properties when constructing 1099 * this WikiEngine. However, attachment names are only beautified by 1100 * the name. 1101 * 1102 * @param title The title to beautify 1103 * @return A beautified title (or, if beautification is off, 1104 * returns the title without modification) 1105 * @since 1.7.11 1106 */ 1107 public String beautifyTitle( String title ) 1108 { 1109 if( m_beautifyTitle ) 1110 { 1111 try 1112 { 1113 Attachment att = m_attachmentManager.getAttachmentInfo(title); 1114 1115 if(att == null) 1116 { 1117 return TextUtil.beautifyString( title ); 1118 } 1119 1120 String parent = TextUtil.beautifyString( att.getParentName() ); 1121 1122 return parent + "/" + att.getFileName(); 1123 } 1124 catch( ProviderException e ) 1125 { 1126 return title; 1127 } 1128 } 1129 1130 return title; 1131 } 1132 1133 /** 1134 * Beautifies the title of the page by appending non-breaking spaces 1135 * in suitable places. This is really suitable only for HTML output, 1136 * as it uses the &nbsp; -character. 1137 * 1138 * @param title The title to beautify 1139 * @return A beautified title. 1140 * @since 2.1.127 1141 */ 1142 public String beautifyTitleNoBreak( String title ) 1143 { 1144 if( m_beautifyTitle ) 1145 { 1146 return TextUtil.beautifyString( title, " " ); 1147 } 1148 1149 return title; 1150 } 1151 1152 /** 1153 * Returns true, if the requested page (or an alias) exists. Will consider 1154 * any version as existing. Will also consider attachments. 1155 * 1156 * @param page WikiName of the page. 1157 * @return true, if page (or attachment) exists. 1158 */ 1159 public boolean pageExists( String page ) 1160 { 1161 Attachment att = null; 1162 1163 try 1164 { 1165 if( m_commandResolver.getSpecialPageReference(page) != null ) return true; 1166 1167 if( getFinalPageName( page ) != null ) 1168 { 1169 return true; 1170 } 1171 1172 att = getAttachmentManager().getAttachmentInfo( (WikiContext)null, page ); 1173 } 1174 catch( ProviderException e ) 1175 { 1176 log.debug("pageExists() failed to find attachments",e); 1177 } 1178 1179 return att != null; 1180 } 1181 1182 /** 1183 * Returns true, if the requested page (or an alias) exists with the 1184 * requested version. 1185 * 1186 * @param page Page name 1187 * @param version Page version 1188 * @return True, if page (or alias, or attachment) exists 1189 * @throws ProviderException If the provider fails. 1190 */ 1191 public boolean pageExists( String page, int version ) 1192 throws ProviderException 1193 { 1194 if( m_commandResolver.getSpecialPageReference(page) != null ) return true; 1195 1196 String finalName = getFinalPageName( page ); 1197 1198 boolean isThere = false; 1199 1200 if( finalName != null ) 1201 { 1202 // 1203 // Go and check if this particular version of this page 1204 // exists. 1205 // 1206 isThere = m_pageManager.pageExists( finalName, version ); 1207 } 1208 1209 if( isThere == false ) 1210 { 1211 // 1212 // Go check if such an attachment exists. 1213 // 1214 try 1215 { 1216 isThere = getAttachmentManager().getAttachmentInfo( (WikiContext)null, page, version ) != null; 1217 } 1218 catch( ProviderException e ) 1219 { 1220 log.debug("pageExists() failed to find attachments",e); 1221 } 1222 } 1223 1224 return isThere; 1225 } 1226 1227 /** 1228 * Returns true, if the requested page (or an alias) exists, with the 1229 * specified version in the WikiPage. 1230 * 1231 * @param page A WikiPage object describing the name and version. 1232 * @return true, if the page (or alias, or attachment) exists. 1233 * @throws ProviderException If something goes badly wrong. 1234 * @since 2.0 1235 */ 1236 public boolean pageExists( WikiPage page ) 1237 throws ProviderException 1238 { 1239 if( page != null ) 1240 { 1241 return pageExists( page.getName(), page.getVersion() ); 1242 } 1243 return false; 1244 } 1245 1246 /** 1247 * Returns the correct page name, or null, if no such 1248 * page can be found. Aliases are considered. This 1249 * method simply delegates to 1250 * {@link org.apache.wiki.ui.CommandResolver#getFinalPageName(String)}. 1251 * @since 2.0 1252 * @param page Page name. 1253 * @return The rewritten page name, or null, if the page does not exist. 1254 * @throws ProviderException If something goes wrong in the backend. 1255 */ 1256 public String getFinalPageName( String page ) 1257 throws ProviderException 1258 { 1259 return m_commandResolver.getFinalPageName( page ); 1260 } 1261 1262 /** 1263 * Turns a WikiName into something that can be 1264 * called through using an URL. 1265 * 1266 * @since 1.4.1 1267 * @param pagename A name. Can be actually any string. 1268 * @return A properly encoded name. 1269 * @see #decodeName(String) 1270 */ 1271 public String encodeName( String pagename ) 1272 { 1273 try 1274 { 1275 return URLEncoder.encode( pagename, m_useUTF8 ? "UTF-8" : "ISO-8859-1" ); 1276 } 1277 catch( UnsupportedEncodingException e ) 1278 { 1279 throw new InternalWikiException( "ISO-8859-1 not a supported encoding!?! Your platform is borked." ); 1280 } 1281 } 1282 1283 /** 1284 * Decodes a URL-encoded request back to regular life. This properly heeds 1285 * the encoding as defined in the settings file. 1286 * 1287 * @param pagerequest The URL-encoded string to decode 1288 * @return A decoded string. 1289 * @see #encodeName(String) 1290 */ 1291 public String decodeName( String pagerequest ) 1292 { 1293 try 1294 { 1295 return URLDecoder.decode( pagerequest, m_useUTF8 ? "UTF-8" : "ISO-8859-1" ); 1296 } 1297 catch( UnsupportedEncodingException e ) 1298 { 1299 throw new InternalWikiException("ISO-8859-1 not a supported encoding!?! Your platform is borked."); 1300 } 1301 } 1302 1303 /** 1304 * Returns the IANA name of the character set encoding we're 1305 * supposed to be using right now. 1306 * 1307 * @since 1.5.3 1308 * @return The content encoding (either UTF-8 or ISO-8859-1). 1309 */ 1310 public String getContentEncoding() 1311 { 1312 if( m_useUTF8 ) 1313 return "UTF-8"; 1314 1315 return "ISO-8859-1"; 1316 } 1317 1318 /** 1319 * Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this 1320 * WikiEngine. If the WIkiEngine has not been initialized, this method will return 1321 * <code>null</code>. 1322 * @return the task queue 1323 */ 1324 public WorkflowManager getWorkflowManager() 1325 { 1326 return m_workflowMgr; 1327 } 1328 1329 /** 1330 * Returns the un-HTMLized text of the latest version of a page. 1331 * This method also replaces the < and & -characters with 1332 * their respective HTML entities, thus making it suitable 1333 * for inclusion on an HTML page. If you want to have the 1334 * page text without any conversions, use getPureText(). 1335 * 1336 * @param page WikiName of the page to fetch. 1337 * @return WikiText. 1338 */ 1339 public String getText( String page ) 1340 { 1341 return getText( page, WikiPageProvider.LATEST_VERSION ); 1342 } 1343 1344 /** 1345 * Returns the un-HTMLized text of the given version of a page. 1346 * This method also replaces the < and & -characters with 1347 * their respective HTML entities, thus making it suitable 1348 * for inclusion on an HTML page. If you want to have the 1349 * page text without any conversions, use getPureText(). 1350 * 1351 * 1352 * @param page WikiName of the page to fetch 1353 * @param version Version of the page to fetch 1354 * @return WikiText. 1355 */ 1356 public String getText( String page, int version ) 1357 { 1358 String result = getPureText( page, version ); 1359 1360 // 1361 // Replace ampersand first, or else all quotes and stuff 1362 // get replaced as well with " etc. 1363 // 1364 /* 1365 result = TextUtil.replaceString( result, "&", "&" ); 1366 */ 1367 1368 result = TextUtil.replaceEntities( result ); 1369 1370 return result; 1371 } 1372 1373 /** 1374 * Returns the un-HTMLized text of the given version of a page in 1375 * the given context. USE THIS METHOD if you don't know what 1376 * doing. 1377 * <p> 1378 * This method also replaces the < and & -characters with 1379 * their respective HTML entities, thus making it suitable 1380 * for inclusion on an HTML page. If you want to have the 1381 * page text without any conversions, use getPureText(). 1382 * 1383 * @since 1.9.15. 1384 * @param context The WikiContext 1385 * @param page A page reference (not an attachment) 1386 * @return The page content as HTMLized String. 1387 * @see #getPureText(WikiPage) 1388 */ 1389 public String getText( WikiContext context, WikiPage page ) 1390 { 1391 return getText( page.getName(), page.getVersion() ); 1392 } 1393 1394 1395 /** 1396 * Returns the pure text of a page, no conversions. Use this 1397 * if you are writing something that depends on the parsing 1398 * of the page. Note that you should always check for page 1399 * existence through pageExists() before attempting to fetch 1400 * the page contents. 1401 * 1402 * @param page The name of the page to fetch. 1403 * @param version If WikiPageProvider.LATEST_VERSION, then uses the 1404 * latest version. 1405 * @return The page contents. If the page does not exist, 1406 * returns an empty string. 1407 */ 1408 // FIXME: Should throw an exception on unknown page/version? 1409 public String getPureText( String page, int version ) 1410 { 1411 String result = null; 1412 1413 try 1414 { 1415 result = m_pageManager.getPageText( page, version ); 1416 } 1417 catch( ProviderException e ) 1418 { 1419 // FIXME 1420 } 1421 finally 1422 { 1423 if( result == null ) 1424 result = ""; 1425 } 1426 1427 return result; 1428 } 1429 1430 /** 1431 * Returns the pure text of a page, no conversions. Use this 1432 * if you are writing something that depends on the parsing 1433 * the page. Note that you should always check for page 1434 * existence through pageExists() before attempting to fetch 1435 * the page contents. 1436 * 1437 * @param page A handle to the WikiPage 1438 * @return String of WikiText. 1439 * @since 2.1.13. 1440 */ 1441 public String getPureText( WikiPage page ) 1442 { 1443 return getPureText( page.getName(), page.getVersion() ); 1444 } 1445 1446 /** 1447 * Returns the converted HTML of the page using a different 1448 * context than the default context. 1449 * 1450 * @param context A WikiContext in which you wish to render this page in. 1451 * @param page WikiPage reference. 1452 * @return HTML-rendered version of the page. 1453 */ 1454 1455 public String getHTML( WikiContext context, WikiPage page ) 1456 { 1457 String pagedata = null; 1458 1459 pagedata = getPureText( page.getName(), page.getVersion() ); 1460 1461 String res = textToHTML( context, pagedata ); 1462 1463 return res; 1464 } 1465 1466 /** 1467 * Returns the converted HTML of the page. 1468 * 1469 * @param page WikiName of the page to convert. 1470 * @return HTML-rendered version of the page. 1471 */ 1472 public String getHTML( String page ) 1473 { 1474 return getHTML( page, WikiPageProvider.LATEST_VERSION ); 1475 } 1476 1477 /** 1478 * Returns the converted HTML of the page's specific version. 1479 * The version must be a positive integer, otherwise the current 1480 * version is returned. 1481 * 1482 * @param pagename WikiName of the page to convert. 1483 * @param version Version number to fetch 1484 * @return HTML-rendered page text. 1485 */ 1486 public String getHTML( String pagename, int version ) 1487 { 1488 WikiPage page = getPage( pagename, version ); 1489 1490 WikiContext context = new WikiContext( this, 1491 page ); 1492 context.setRequestContext( WikiContext.NONE ); 1493 1494 String res = getHTML( context, page ); 1495 1496 return res; 1497 } 1498 1499 /** 1500 * Converts raw page data to HTML. 1501 * 1502 * @param pagedata Raw page data to convert to HTML 1503 * @param context The WikiContext in which the page is to be rendered 1504 * @return Rendered page text 1505 */ 1506 public String textToHTML( WikiContext context, String pagedata ) 1507 { 1508 String result = ""; 1509 1510 boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true")); 1511 1512 StopWatch sw = new StopWatch(); 1513 sw.start(); 1514 try 1515 { 1516 if( runFilters ) 1517 pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata ); 1518 1519 result = m_renderingManager.getHTML( context, pagedata ); 1520 1521 if( runFilters ) 1522 result = m_filterManager.doPostTranslateFiltering( context, result ); 1523 } 1524 catch( FilterException e ) 1525 { 1526 // FIXME: Don't yet know what to do 1527 } 1528 sw.stop(); 1529 if( log.isDebugEnabled() ) 1530 log.debug("Page "+context.getRealPage().getName()+" rendered, took "+sw ); 1531 1532 return result; 1533 } 1534 1535 /** 1536 * Protected method that signals that the WikiEngine will be 1537 * shut down by the servlet container. It is called by 1538 * {@link WikiServlet#destroy()}. When this method is called, 1539 * it fires a "shutdown" WikiEngineEvent to all registered 1540 * listeners. 1541 */ 1542 protected void shutdown() 1543 { 1544 fireEvent( WikiEngineEvent.SHUTDOWN ); 1545 m_filterManager.destroy(); 1546 } 1547 1548 /** 1549 * Reads a WikiPageful of data from a String and returns all links 1550 * internal to this Wiki in a Collection. 1551 * 1552 * @param page The WikiPage to scan 1553 * @param pagedata The page contents 1554 * @return a Collection of Strings 1555 */ 1556 public Collection< String > scanWikiLinks( WikiPage page, String pagedata ) { 1557 LinkCollector localCollector = new LinkCollector(); 1558 1559 textToHTML( new WikiContext( this, page ), 1560 pagedata, 1561 localCollector, 1562 null, 1563 localCollector, 1564 false, 1565 true ); 1566 1567 return localCollector.getLinks(); 1568 } 1569 1570 /** 1571 * Just convert WikiText to HTML. 1572 * 1573 * @param context The WikiContext in which to do the conversion 1574 * @param pagedata The data to render 1575 * @param localLinkHook Is called whenever a wiki link is found 1576 * @param extLinkHook Is called whenever an external link is found 1577 * 1578 * @return HTML-rendered page text. 1579 */ 1580 1581 public String textToHTML( WikiContext context, 1582 String pagedata, 1583 StringTransmutator localLinkHook, 1584 StringTransmutator extLinkHook ) 1585 { 1586 return textToHTML( context, pagedata, localLinkHook, extLinkHook, null, true, false ); 1587 } 1588 1589 /** 1590 * Just convert WikiText to HTML. 1591 * 1592 * @param context The WikiContext in which to do the conversion 1593 * @param pagedata The data to render 1594 * @param localLinkHook Is called whenever a wiki link is found 1595 * @param extLinkHook Is called whenever an external link is found 1596 * @param attLinkHook Is called whenever an attachment link is found 1597 * @return HTML-rendered page text. 1598 */ 1599 1600 public String textToHTML( WikiContext context, 1601 String pagedata, 1602 StringTransmutator localLinkHook, 1603 StringTransmutator extLinkHook, 1604 StringTransmutator attLinkHook ) 1605 { 1606 return textToHTML( context, pagedata, localLinkHook, extLinkHook, attLinkHook, true, false ); 1607 } 1608 1609 /** 1610 * Helper method for doing the HTML translation. 1611 * 1612 * @param context The WikiContext in which to do the conversion 1613 * @param pagedata The data to render 1614 * @param localLinkHook Is called whenever a wiki link is found 1615 * @param extLinkHook Is called whenever an external link is found 1616 * @param parseAccessRules Parse the access rules if we encounter them 1617 * @param justParse Just parses the pagedata, does not actually render. In this case, 1618 * this methods an empty string. 1619 * @return HTML-rendered page text. 1620 1621 */ 1622 private String textToHTML( WikiContext context, 1623 String pagedata, 1624 StringTransmutator localLinkHook, 1625 StringTransmutator extLinkHook, 1626 StringTransmutator attLinkHook, 1627 boolean parseAccessRules, 1628 boolean justParse ) 1629 { 1630 String result = ""; 1631 1632 if( pagedata == null ) 1633 { 1634 log.error("NULL pagedata to textToHTML()"); 1635 return null; 1636 } 1637 1638 boolean runFilters = "true".equals(m_variableManager.getValue(context,PROP_RUNFILTERS,"true")); 1639 1640 try 1641 { 1642 StopWatch sw = new StopWatch(); 1643 sw.start(); 1644 1645 if( runFilters && m_filterManager != null ) 1646 pagedata = m_filterManager.doPreTranslateFiltering( context, pagedata ); 1647 1648 MarkupParser mp = m_renderingManager.getParser( context, pagedata ); 1649 mp.addLocalLinkHook( localLinkHook ); 1650 mp.addExternalLinkHook( extLinkHook ); 1651 mp.addAttachmentLinkHook( attLinkHook ); 1652 1653 if( !parseAccessRules ) mp.disableAccessRules(); 1654 1655 WikiDocument doc = mp.parse(); 1656 1657 // 1658 // In some cases it's better just to parse, not to render 1659 // 1660 if( !justParse ) 1661 { 1662 result = m_renderingManager.getHTML( context, doc ); 1663 1664 if( runFilters && m_filterManager != null ) 1665 result = m_filterManager.doPostTranslateFiltering( context, result ); 1666 } 1667 1668 sw.stop(); 1669 1670 if( log.isDebugEnabled() ) 1671 log.debug("Page "+context.getRealPage().getName()+" rendered, took "+sw ); 1672 } 1673 catch( IOException e ) 1674 { 1675 log.error( "Failed to scan page data: ", e ); 1676 } 1677 catch( FilterException e ) 1678 { 1679 log.error( "page filter threw exception: ", e ); 1680 // FIXME: Don't yet know what to do 1681 } 1682 1683 return result; 1684 } 1685 1686 /** 1687 * Updates all references for the given page. 1688 * 1689 * @param page wiki page for which references should be updated 1690 */ 1691 public void updateReferences( WikiPage page ) 1692 { 1693 String pageData = getPureText( page.getName(), WikiProvider.LATEST_VERSION ); 1694 1695 m_referenceManager.updateReferences( page.getName(), 1696 scanWikiLinks( page, pageData ) ); 1697 } 1698 1699 1700 /** 1701 * Writes the WikiText of a page into the 1702 * page repository. If the <code>jspwiki.properties</code> file contains 1703 * the property <code>jspwiki.approver.workflow.saveWikiPage</code> and 1704 * its value resolves to a valid user, {@link org.apache.wiki.auth.authorize.Group} 1705 * or {@link org.apache.wiki.auth.authorize.Role}, this method will 1706 * place a {@link org.apache.wiki.workflow.Decision} in the approver's 1707 * workflow inbox and throw a {@link org.apache.wiki.workflow.DecisionRequiredException}. 1708 * If the submitting user is authenticated and the page save is rejected, 1709 * a notification will be placed in the user's decision queue. 1710 * 1711 * @since 2.1.28 1712 * @param context The current WikiContext 1713 * @param text The Wiki markup for the page. 1714 * @throws WikiException if the save operation encounters an error during the 1715 * save operation. If the page-save operation requires approval, the exception will 1716 * be of type {@link org.apache.wiki.workflow.DecisionRequiredException}. Individual 1717 * PageFilters, such as the {@link org.apache.wiki.filters.SpamFilter} may also 1718 * throw a {@link org.apache.wiki.api.exceptions.RedirectException}. 1719 */ 1720 public void saveText( WikiContext context, String text ) 1721 throws WikiException 1722 { 1723 // Check if page data actually changed; bail if not 1724 WikiPage page = context.getPage(); 1725 String oldText = getPureText( page ); 1726 String proposedText = TextUtil.normalizePostData( text ); 1727 if ( oldText != null && oldText.equals( proposedText ) ) 1728 { 1729 return; 1730 } 1731 1732 // Check if creation of empty pages is allowed; bail if not 1733 boolean allowEmpty = TextUtil.getBooleanProperty( m_properties, 1734 PROP_ALLOW_CREATION_OF_EMPTY_PAGES, 1735 false ); 1736 if ( !allowEmpty && !pageExists( page ) && text.trim().equals( "" ) ) 1737 { 1738 return; 1739 } 1740 1741 // Create approval workflow for page save; add the diffed, proposed 1742 // and old text versions as Facts for the approver (if approval is required) 1743 // If submitter is authenticated, any reject messages will appear in his/her workflow inbox. 1744 WorkflowBuilder builder = WorkflowBuilder.getBuilder( this ); 1745 Principal submitter = context.getCurrentUser(); 1746 Task prepTask = new PageManager.PreSaveWikiPageTask( context, proposedText ); 1747 Task completionTask = new PageManager.SaveWikiPageTask(); 1748 String diffText = m_differenceManager.makeDiff( context, oldText, proposedText ); 1749 boolean isAuthenticated = context.getWikiSession().isAuthenticated(); 1750 Fact[] facts = new Fact[5]; 1751 facts[0] = new Fact( PageManager.FACT_PAGE_NAME, page.getName() ); 1752 facts[1] = new Fact( PageManager.FACT_DIFF_TEXT, diffText ); 1753 facts[2] = new Fact( PageManager.FACT_PROPOSED_TEXT, proposedText ); 1754 facts[3] = new Fact( PageManager.FACT_CURRENT_TEXT, oldText); 1755 facts[4] = new Fact( PageManager.FACT_IS_AUTHENTICATED, Boolean.valueOf( isAuthenticated ) ); 1756 String rejectKey = isAuthenticated ? PageManager.SAVE_REJECT_MESSAGE_KEY : null; 1757 Workflow workflow = builder.buildApprovalWorkflow( submitter, 1758 PageManager.SAVE_APPROVER, 1759 prepTask, 1760 PageManager.SAVE_DECISION_MESSAGE_KEY, 1761 facts, 1762 completionTask, 1763 rejectKey ); 1764 m_workflowMgr.start(workflow); 1765 1766 // Let callers know if the page-save requires approval 1767 if ( workflow.getCurrentStep() instanceof Decision ) 1768 { 1769 throw new DecisionRequiredException( "The page contents must be approved before they become active." ); 1770 } 1771 } 1772 1773 /** 1774 * Returns the number of pages in this Wiki 1775 * @return The total number of pages. 1776 */ 1777 public int getPageCount() 1778 { 1779 return m_pageManager.getTotalPageCount(); 1780 } 1781 1782 /** 1783 * Returns the provider name. 1784 * @return The full class name of the current page provider. 1785 */ 1786 1787 public String getCurrentProvider() 1788 { 1789 return m_pageManager.getProvider().getClass().getName(); 1790 } 1791 1792 /** 1793 * Return information about current provider. This method just calls 1794 * the corresponding PageManager method, which in turn calls the 1795 * provider method. 1796 * 1797 * @return A textual description of the current provider. 1798 * @since 1.6.4 1799 */ 1800 public String getCurrentProviderInfo() 1801 { 1802 return m_pageManager.getProviderDescription(); 1803 } 1804 1805 /** 1806 * Returns a Collection of WikiPages, sorted in time 1807 * order of last change (i.e. first object is the most 1808 * recently changed). This method also includes attachments. 1809 * 1810 * @return Collection of WikiPage objects. In reality, the returned 1811 * collection is a Set, but due to API compatibility reasons, 1812 * we're not changing the signature soon... 1813 */ 1814 1815 // FIXME: Should really get a Date object and do proper comparisons. 1816 // This is terribly wasteful. 1817 @SuppressWarnings("unchecked") 1818 public Collection getRecentChanges() 1819 { 1820 try 1821 { 1822 Collection<WikiPage> pages = m_pageManager.getAllPages(); 1823 Collection<Attachment> atts = m_attachmentManager.getAllAttachments(); 1824 1825 TreeSet<WikiPage> sortedPages = new TreeSet<WikiPage>( new PageTimeComparator() ); 1826 1827 sortedPages.addAll( pages ); 1828 sortedPages.addAll( atts ); 1829 1830 return sortedPages; 1831 } 1832 catch( ProviderException e ) 1833 { 1834 log.error( "Unable to fetch all pages: ",e); 1835 return null; 1836 } 1837 } 1838 1839 /** 1840 * Parses an incoming search request, then 1841 * does a search. 1842 * <P> 1843 * The query is dependent on the actual chosen search provider - each one of them has 1844 * a language of its own. 1845 * 1846 * @param query The query string 1847 * @param wikiContext the context within which to run the search 1848 * @return A Collection of SearchResult objects. 1849 * @throws ProviderException If the searching failed 1850 * @throws IOException If the searching failed 1851 */ 1852 1853 // 1854 // FIXME: Should also have attributes attached. 1855 // 1856 public Collection findPages( String query, WikiContext wikiContext ) 1857 throws ProviderException, IOException 1858 { 1859 Collection results = m_searchManager.findPages( query, wikiContext ); 1860 1861 return results; 1862 } 1863 1864 /** 1865 * Finds the corresponding WikiPage object based on the page name. It always finds 1866 * the latest version of a page. 1867 * 1868 * @param pagereq The name of the page to look for. 1869 * @return A WikiPage object, or null, if the page by the name could not be found. 1870 */ 1871 1872 public WikiPage getPage( String pagereq ) 1873 { 1874 return getPage( pagereq, WikiProvider.LATEST_VERSION ); 1875 } 1876 1877 /** 1878 * Finds the corresponding WikiPage object base on the page name and version. 1879 * 1880 * @param pagereq The name of the page to look for. 1881 * @param version The version number to look for. May be WikiProvider.LATEST_VERSION, 1882 * in which case it will look for the latest version (and this method then becomes 1883 * the equivalent of getPage(String). 1884 * 1885 * @return A WikiPage object, or null, if the page could not be found; or if there 1886 * is no such version of the page. 1887 * @since 1.6.7. 1888 */ 1889 1890 public WikiPage getPage( String pagereq, int version ) 1891 { 1892 try 1893 { 1894 WikiPage p = m_pageManager.getPageInfo( pagereq, version ); 1895 1896 if( p == null ) 1897 { 1898 p = m_attachmentManager.getAttachmentInfo( (WikiContext)null, pagereq ); 1899 } 1900 1901 return p; 1902 } 1903 catch( ProviderException e ) 1904 { 1905 log.error( "Unable to fetch page info",e); 1906 return null; 1907 } 1908 } 1909 1910 1911 /** 1912 * Returns a Collection of WikiPages containing the 1913 * version history of a page. 1914 * 1915 * @param page Name of the page to look for 1916 * @return an ordered List of WikiPages, each corresponding to a different 1917 * revision of the page. 1918 */ 1919 1920 public List getVersionHistory( String page ) 1921 { 1922 List c = null; 1923 1924 try 1925 { 1926 c = m_pageManager.getVersionHistory( page ); 1927 1928 if( c == null ) 1929 { 1930 c = m_attachmentManager.getVersionHistory( page ); 1931 } 1932 } 1933 catch( ProviderException e ) 1934 { 1935 log.error( "FIXME", e ); 1936 } 1937 1938 return c; 1939 } 1940 1941 /** 1942 * Returns a diff of two versions of a page. 1943 * <p> 1944 * Note that the API was changed in 2.6 to provide a WikiContext object! 1945 * 1946 * @param context The WikiContext of the page you wish to get a diff from 1947 * @param version1 Version number of the old page. If 1948 * WikiPageProvider.LATEST_VERSION (-1), then uses current page. 1949 * @param version2 Version number of the new page. If 1950 * WikiPageProvider.LATEST_VERSION (-1), then uses current page. 1951 * 1952 * @return A HTML-ized difference between two pages. If there is no difference, 1953 * returns an empty string. 1954 */ 1955 public String getDiff( WikiContext context, int version1, int version2 ) 1956 { 1957 String page = context.getPage().getName(); 1958 String page1 = getPureText( page, version1 ); 1959 String page2 = getPureText( page, version2 ); 1960 1961 // Kludge to make diffs for new pages to work this way. 1962 1963 if( version1 == WikiPageProvider.LATEST_VERSION ) 1964 { 1965 page1 = ""; 1966 } 1967 1968 String diff = m_differenceManager.makeDiff( context, page1, page2 ); 1969 1970 return diff; 1971 } 1972 1973 /** 1974 * Returns this object's ReferenceManager. 1975 * @return The current ReferenceManager instance. 1976 * 1977 * @since 1.6.1 1978 */ 1979 public ReferenceManager getReferenceManager() 1980 { 1981 return m_referenceManager; 1982 } 1983 1984 /** 1985 * Returns the current rendering manager for this wiki application. 1986 * 1987 * @since 2.3.27 1988 * @return A RenderingManager object. 1989 */ 1990 public RenderingManager getRenderingManager() 1991 { 1992 return m_renderingManager; 1993 } 1994 1995 /** 1996 * Returns the current plugin manager. 1997 * 1998 * In 2.10 the PluginManager will be returned instead of the generic 1999 * 2000 * @since 1.6.1 2001 * @return The current PluginManager instance 2002 */ 2003 @SuppressWarnings("unchecked") 2004 public < T extends PluginManager > T getPluginManager() 2005 { 2006 return (T)m_pluginManager; 2007 } 2008 2009 /** 2010 * Returns the current variable manager. 2011 * @return The current VariableManager. 2012 */ 2013 2014 public VariableManager getVariableManager() 2015 { 2016 return m_variableManager; 2017 } 2018 2019 /** 2020 * Shortcut to getVariableManager().getValue(). However, this method does not 2021 * throw a NoSuchVariableException, but returns null in case the variable does 2022 * not exist. 2023 * 2024 * @param context WikiContext to look the variable in 2025 * @param name Name of the variable to look for 2026 * @return Variable value, or null, if there is no such variable. 2027 * @since 2.2 2028 */ 2029 public String getVariable( WikiContext context, String name ) 2030 { 2031 try 2032 { 2033 return m_variableManager.getValue( context, name ); 2034 } 2035 catch( NoSuchVariableException e ) 2036 { 2037 return null; 2038 } 2039 } 2040 2041 /** 2042 * Returns the current PageManager which is responsible for storing 2043 * and managing WikiPages. 2044 * 2045 * @return The current PageManager instance. 2046 */ 2047 public PageManager getPageManager() 2048 { 2049 return m_pageManager; 2050 } 2051 2052 /** 2053 * Returns the CommandResolver for this wiki engine. 2054 * @return the resolver 2055 */ 2056 public CommandResolver getCommandResolver() 2057 { 2058 return m_commandResolver; 2059 } 2060 2061 /** 2062 * Returns the current AttachmentManager, which is responsible for 2063 * storing and managing attachments. 2064 * 2065 * @since 1.9.31. 2066 * @return The current AttachmentManager instance 2067 */ 2068 public AttachmentManager getAttachmentManager() 2069 { 2070 return m_attachmentManager; 2071 } 2072 2073 /** 2074 * Returns the currently used authorization manager. 2075 * 2076 * @return The current AuthorizationManager instance 2077 */ 2078 public AuthorizationManager getAuthorizationManager() 2079 { 2080 return m_authorizationManager; 2081 } 2082 2083 /** 2084 * Returns the currently used authentication manager. 2085 * 2086 * @return The current AuthenticationManager instance. 2087 */ 2088 public AuthenticationManager getAuthenticationManager() 2089 { 2090 return m_authenticationManager; 2091 } 2092 2093 /** 2094 * Returns the manager responsible for the filters. 2095 * @since 2.1.88 2096 * @return The current FilterManager instance 2097 */ 2098 @SuppressWarnings("unchecked") 2099 public < T extends FilterManager > T getFilterManager() 2100 { 2101 return (T)m_filterManager; 2102 } 2103 2104 /** 2105 * Returns the manager responsible for searching the Wiki. 2106 * @since 2.2.21 2107 * @return The current SearchManager instance 2108 */ 2109 public SearchManager getSearchManager() 2110 { 2111 return m_searchManager; 2112 } 2113 2114 /** 2115 * Returns the progress manager we're using 2116 * @return A ProgressManager 2117 * @since 2.6 2118 */ 2119 public ProgressManager getProgressManager() 2120 { 2121 return m_progressManager; 2122 } 2123 2124 /** 2125 * Figure out to which page we are really going to. Considers 2126 * special page names from the jspwiki.properties, and possible aliases. 2127 * This method delgates requests to 2128 * {@link org.apache.wiki.WikiContext#getRedirectURL()}. 2129 * @param context The Wiki Context in which the request is being made. 2130 * @return A complete URL to the new page to redirect to 2131 * @since 2.2 2132 */ 2133 2134 public String getRedirectURL( WikiContext context ) 2135 { 2136 return context.getRedirectURL(); 2137 } 2138 2139 /** 2140 * Shortcut to create a WikiContext from a supplied HTTP request, 2141 * using a default wiki context. 2142 * @param request the HTTP request 2143 * @param requestContext the default context to use 2144 * @return a new WikiContext object. 2145 * 2146 * @see org.apache.wiki.ui.CommandResolver 2147 * @see org.apache.wiki.ui.Command 2148 * @since 2.1.15. 2149 */ 2150 // FIXME: We need to have a version which takes a fixed page 2151 // name as well, or check it elsewhere. 2152 public WikiContext createContext( HttpServletRequest request, 2153 String requestContext ) 2154 { 2155 if( !m_isConfigured ) 2156 { 2157 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."); 2158 } 2159 2160 // Build the wiki context 2161 Command command = m_commandResolver.findCommand( request, requestContext ); 2162 return new WikiContext( this, request, command ); 2163 } 2164 2165 /** 2166 * Deletes a page or an attachment completely, including all versions. If the page 2167 * does not exist, does nothing. 2168 * 2169 * @param pageName The name of the page. 2170 * @throws ProviderException If something goes wrong. 2171 */ 2172 public void deletePage( String pageName ) 2173 throws ProviderException 2174 { 2175 WikiPage p = getPage( pageName ); 2176 2177 if( p != null ) 2178 { 2179 if( p instanceof Attachment ) 2180 { 2181 m_attachmentManager.deleteAttachment( (Attachment) p ); 2182 } 2183 else 2184 { 2185 if (m_attachmentManager.hasAttachments( p )) 2186 { 2187 Collection attachments = m_attachmentManager.listAttachments( p ); 2188 for( Iterator atti = attachments.iterator(); atti.hasNext(); ) 2189 { 2190 m_attachmentManager.deleteAttachment( (Attachment)(atti.next()) ); 2191 } 2192 } 2193 m_pageManager.deletePage( p ); 2194 firePageEvent( WikiPageEvent.PAGE_DELETED, pageName ); 2195 } 2196 } 2197 } 2198 2199 /** 2200 * Deletes a specific version of a page or an attachment. 2201 * 2202 * @param page The page object. 2203 * @throws ProviderException If something goes wrong. 2204 */ 2205 public void deleteVersion( WikiPage page ) 2206 throws ProviderException 2207 { 2208 if( page instanceof Attachment ) 2209 { 2210 m_attachmentManager.deleteVersion( (Attachment) page ); 2211 } 2212 else 2213 { 2214 m_pageManager.deleteVersion( page ); 2215 } 2216 } 2217 2218 /** 2219 * Returns the URL of the global RSS file. May be null, if the 2220 * RSS file generation is not operational. 2221 * @since 1.7.10 2222 * @return The global RSS url 2223 */ 2224 public String getGlobalRSSURL() 2225 { 2226 if( m_rssGenerator != null && m_rssGenerator.isEnabled() ) 2227 { 2228 return getBaseURL()+m_rssFile; 2229 } 2230 2231 return null; 2232 } 2233 2234 /** 2235 * Returns the root path. The root path is where the WikiEngine is 2236 * located in the file system. 2237 * 2238 * @since 2.2 2239 * @return A path to where the Wiki is installed in the local filesystem. 2240 */ 2241 public String getRootPath() 2242 { 2243 return m_rootPath; 2244 } 2245 2246 /** 2247 * @since 2.2.6 2248 * @return the URL constructor 2249 */ 2250 public URLConstructor getURLConstructor() 2251 { 2252 return m_urlConstructor; 2253 } 2254 2255 /** 2256 * Returns the RSSGenerator. If the property <code>jspwiki.rss.generate</code> 2257 * has not been set to <code>true</code>, this method will return <code>null</code>, 2258 * <em>and callers should check for this value.</em> 2259 * @since 2.1.165 2260 * @return the RSS generator 2261 */ 2262 public RSSGenerator getRSSGenerator() 2263 { 2264 return m_rssGenerator; 2265 } 2266 2267 /** 2268 * Renames, or moves, a wiki page. Can also alter referring wiki 2269 * links to point to the renamed page. 2270 * 2271 * @param context The context during which this rename takes 2272 * place. 2273 * @param renameFrom Name of the source page. 2274 * @param renameTo Name of the destination page. 2275 * @param changeReferrers If true, then changes any referring links 2276 * to point to the renamed page. 2277 * 2278 * @return The name of the page that the source was renamed to. 2279 * 2280 * @throws WikiException In the case of an error, such as the destination 2281 * page already existing. 2282 */ 2283 public String renamePage( WikiContext context, 2284 String renameFrom, 2285 String renameTo, 2286 boolean changeReferrers) 2287 throws WikiException 2288 { 2289 String newPageName = m_pageRenamer.renamePage(context, renameFrom, renameTo, changeReferrers); 2290 firePageRenameEvent(renameFrom, newPageName); 2291 return newPageName; 2292 } 2293 2294 /** 2295 * Returns the PageRenamer employed by this WikiEngine. 2296 * @since 2.5.141 2297 * @return The current PageRenamer instance. 2298 */ 2299 public PageRenamer getPageRenamer() 2300 { 2301 return m_pageRenamer; 2302 } 2303 2304 /** 2305 * Returns the UserManager employed by this WikiEngine. 2306 * @since 2.3 2307 * @return The current UserManager instance. 2308 */ 2309 public UserManager getUserManager() 2310 { 2311 return m_userManager; 2312 } 2313 2314 /** 2315 * Returns the GroupManager employed by this WikiEngine. 2316 * @since 2.3 2317 * @return The current GroupManager instance 2318 */ 2319 public GroupManager getGroupManager() 2320 { 2321 return m_groupManager; 2322 } 2323 2324 /** 2325 * Returns the current {@link AdminBeanManager}. 2326 * 2327 * @return The current {@link AdminBeanManager}. 2328 * @since 2.6 2329 */ 2330 public AdminBeanManager getAdminBeanManager() { 2331 return m_adminBeanManager; 2332 } 2333 2334 /** 2335 * Returns the AclManager employed by this WikiEngine. 2336 * The AclManager is lazily initialized. 2337 * <p> 2338 * The AclManager implementing class may be set by the 2339 * System property {@link #PROP_ACL_MANAGER_IMPL}. 2340 * </p> 2341 * 2342 * @since 2.3 2343 * @return The current AclManager. 2344 */ 2345 public AclManager getAclManager() 2346 { 2347 if( m_aclManager == null ) 2348 { 2349 try 2350 { 2351 String s = m_properties.getProperty( PROP_ACL_MANAGER_IMPL, 2352 DefaultAclManager.class.getName() ); 2353 m_aclManager = (AclManager)ClassUtil.getMappedObject(s); // TODO: I am not sure whether this is the right call 2354 m_aclManager.initialize( this, m_properties ); 2355 } 2356 catch ( WikiException we ) 2357 { 2358 log.fatal( "unable to instantiate class for AclManager: " + we.getMessage() ); 2359 throw new InternalWikiException("Cannot instantiate AclManager, please check logs."); 2360 } 2361 } 2362 return m_aclManager; 2363 } 2364 2365 /** 2366 * Returns the DifferenceManager so that texts can be compared. 2367 * @return the difference manager 2368 */ 2369 public DifferenceManager getDifferenceManager() 2370 { 2371 return m_differenceManager; 2372 } 2373 2374 /** 2375 * Returns the current EditorManager instance. 2376 * 2377 * @return The current EditorManager. 2378 */ 2379 public EditorManager getEditorManager() 2380 { 2381 return m_editorManager; 2382 } 2383 2384 /** 2385 * Returns the current i18n manager. 2386 * 2387 * @return The current Intertan... Interante... Internatatializ... Whatever. 2388 */ 2389 public InternationalizationManager getInternationalizationManager() 2390 { 2391 return m_internationalizationManager; 2392 } 2393 2394 /** 2395 * Registers a WikiEventListener with this instance. 2396 * @param listener the event listener 2397 */ 2398 public final synchronized void addWikiEventListener( WikiEventListener listener ) 2399 { 2400 WikiEventManager.addWikiEventListener( this, listener ); 2401 } 2402 2403 /** 2404 * Un-registers a WikiEventListener with this instance. 2405 * @param listener the event listener 2406 */ 2407 public final synchronized void removeWikiEventListener( WikiEventListener listener ) 2408 { 2409 WikiEventManager.removeWikiEventListener( this, listener ); 2410 } 2411 2412 /** 2413 * Fires a WikiEngineEvent to all registered listeners. 2414 * @param type the event type 2415 */ 2416 protected final void fireEvent( int type ) 2417 { 2418 if ( WikiEventManager.isListening(this) ) 2419 { 2420 WikiEventManager.fireEvent(this,new WikiEngineEvent(this,type)); 2421 } 2422 } 2423 2424 /** 2425 * Fires a WikiPageEvent to all registered listeners. 2426 * @param type the event type 2427 */ 2428 protected final void firePageEvent( int type, String pageName ) 2429 { 2430 if ( WikiEventManager.isListening(this) ) 2431 { 2432 WikiEventManager.fireEvent(this,new WikiPageEvent(this,type,pageName)); 2433 } 2434 } 2435 2436 /** 2437 * Fires a WikiPageRenameEvent to all registered listeners. 2438 * @param oldName the former page name 2439 * @param newName the new page name 2440 */ 2441 protected final void firePageRenameEvent(String oldName, String newName ) 2442 { 2443 if ( WikiEventManager.isListening(this) ) 2444 { 2445 WikiEventManager.fireEvent(this,new WikiPageRenameEvent(this,oldName,newName)); 2446 } 2447 } 2448 2449 /** 2450 * Adds an attribute to the engine for the duration of this engine. The 2451 * value is not persisted. 2452 * 2453 * @since 2.4.91 2454 * @param key the attribute name 2455 * @param value the value 2456 */ 2457 public void setAttribute( String key, Object value ) 2458 { 2459 m_attributes.put( key, value ); 2460 } 2461 2462 /** 2463 * Gets an attribute from the engine. 2464 * 2465 * @param key the attribute name 2466 * @return the value 2467 */ 2468 public Object getAttribute( String key ) 2469 { 2470 return m_attributes.get( key ); 2471 } 2472 2473 /** 2474 * Removes an attribute. 2475 * 2476 * @param key The key of the attribute to remove. 2477 * @return The previous attribute, if it existed. 2478 */ 2479 public Object removeAttribute( String key ) 2480 { 2481 return m_attributes.remove( key ); 2482 } 2483 2484 /** 2485 * Returns a WatchDog for current thread. 2486 * 2487 * @return The current thread WatchDog. 2488 * @since 2.4.92 2489 */ 2490 public WatchDog getCurrentWatchDog() 2491 { 2492 return WatchDog.getCurrentWatchDog(this); 2493 } 2494 2495 /** 2496 * Initialize the page name comparator. 2497 */ 2498 private void initPageSorter( Properties props ) 2499 { 2500 m_pageSorter = new PageSorter(); 2501 m_pageSorter.initialize( props ); 2502 } 2503 2504 /** 2505 * Get this engine's page name comparator. 2506 * 2507 * @return the PageSorter used to sort pages by name in this engine 2508 */ 2509 public PageSorter getPageSorter() 2510 { 2511 return m_pageSorter; 2512 } 2513}