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