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 org.apache.commons.lang3.StringUtils; 022import org.apache.logging.log4j.LogManager; 023import org.apache.logging.log4j.Logger; 024import org.apache.wiki.api.Release; 025import org.apache.wiki.api.core.Engine; 026import org.apache.wiki.api.core.Page; 027import org.apache.wiki.api.engine.Initializable; 028import org.apache.wiki.api.exceptions.ProviderException; 029import org.apache.wiki.api.exceptions.WikiException; 030import org.apache.wiki.attachment.AttachmentManager; 031import org.apache.wiki.auth.AuthenticationManager; 032import org.apache.wiki.auth.AuthorizationManager; 033import org.apache.wiki.auth.UserManager; 034import org.apache.wiki.auth.acl.AclManager; 035import org.apache.wiki.auth.authorize.GroupManager; 036import org.apache.wiki.cache.CachingManager; 037import org.apache.wiki.content.PageRenamer; 038import org.apache.wiki.diff.DifferenceManager; 039import org.apache.wiki.event.WikiEngineEvent; 040import org.apache.wiki.event.WikiEventListener; 041import org.apache.wiki.event.WikiEventManager; 042import org.apache.wiki.event.WikiPageEvent; 043import org.apache.wiki.filters.FilterManager; 044import org.apache.wiki.i18n.InternationalizationManager; 045import org.apache.wiki.pages.PageManager; 046import org.apache.wiki.plugin.PluginManager; 047import org.apache.wiki.references.ReferenceManager; 048import org.apache.wiki.render.RenderingManager; 049import org.apache.wiki.rss.RSSGenerator; 050import org.apache.wiki.search.SearchManager; 051import org.apache.wiki.tasks.TasksManager; 052import org.apache.wiki.ui.CommandResolver; 053import org.apache.wiki.ui.EditorManager; 054import org.apache.wiki.ui.TemplateManager; 055import org.apache.wiki.ui.admin.AdminBeanManager; 056import org.apache.wiki.ui.progress.ProgressManager; 057import org.apache.wiki.url.URLConstructor; 058import org.apache.wiki.util.ClassUtil; 059import org.apache.wiki.util.PropertyReader; 060import org.apache.wiki.util.TextUtil; 061import org.apache.wiki.variables.VariableManager; 062import org.apache.wiki.workflow.WorkflowManager; 063 064import javax.servlet.ServletConfig; 065import javax.servlet.ServletContext; 066import java.io.File; 067import java.io.UnsupportedEncodingException; 068import java.net.MalformedURLException; 069import java.net.URL; 070import java.net.URLDecoder; 071import java.net.URLEncoder; 072import java.nio.charset.Charset; 073import java.nio.charset.StandardCharsets; 074import java.util.ArrayList; 075import java.util.Collection; 076import java.util.Date; 077import java.util.Enumeration; 078import java.util.List; 079import java.util.Locale; 080import java.util.Map; 081import java.util.Properties; 082import java.util.TimeZone; 083import java.util.concurrent.ConcurrentHashMap; 084import java.util.stream.Collectors; 085 086 087/** 088 * Main implementation for {@link Engine}. 089 * 090 * <P> 091 * Using this class: Always get yourself an instance from JSP page by using the {@code WikiEngine.getInstance(..)} method. Never create 092 * a new WikiEngine() from scratch, unless you're writing tests. 093 * 094 * <p> 095 * {@inheritDoc} 096 */ 097public class WikiEngine implements Engine { 098 099 private static final String ATTR_WIKIENGINE = "org.apache.wiki.WikiEngine"; 100 private static final Logger LOG = LogManager.getLogger( WikiEngine.class ); 101 102 /** Stores properties. */ 103 private Properties m_properties; 104 105 /** Should the user info be saved with the page data as well? */ 106 private boolean m_saveUserInfo = true; 107 108 /** If true, uses UTF8 encoding for all data */ 109 private boolean m_useUTF8 = true; 110 111 /** Store the file path to the basic URL. When we're not running as a servlet, it defaults to the user's current directory. */ 112 private String m_rootPath = System.getProperty( "user.dir" ); 113 114 /** Store the ServletContext that we're in. This may be null if WikiEngine is not running inside a servlet container (i.e. when testing). */ 115 private ServletContext m_servletContext; 116 117 /** Stores the template path. This is relative to "templates". */ 118 private String m_templateDir; 119 120 /** The default front page name. Defaults to "Main". */ 121 private String m_frontPage; 122 123 /** The time when this engine was started. */ 124 private Date m_startTime; 125 126 /** The location where the work directory is. */ 127 private String m_workDir; 128 129 /** Each engine has their own application id. */ 130 private String m_appid = ""; 131 132 /** engine is up and running or not */ 133 private boolean m_isConfigured; 134 135 /** Stores wikiengine attributes. */ 136 private final Map< String, Object > m_attributes = new ConcurrentHashMap<>(); 137 138 /** Stores WikiEngine's associated managers. */ 139 protected final Map< Class< ? >, Object > managers = new ConcurrentHashMap<>(); 140 141 /** 142 * Gets a WikiEngine related to this servlet. Since this method is only called from JSP pages (and JspInit()) to be specific, 143 * we throw a RuntimeException if things don't work. 144 * 145 * @param config The ServletConfig object for this servlet. 146 * @return A WikiEngine instance. 147 * @throws InternalWikiException in case something fails. This is a RuntimeException, so be prepared for it. 148 */ 149 public static synchronized WikiEngine getInstance( final ServletConfig config ) throws InternalWikiException { 150 return getInstance( config.getServletContext(), null ); 151 } 152 153 /** 154 * Gets a WikiEngine related to the servlet. Works like getInstance(ServletConfig), but does not force the Properties object. 155 * This method is just an optional way of initializing a WikiEngine for embedded JSPWiki applications; normally, you 156 * should use getInstance(ServletConfig). 157 * 158 * @param config The ServletConfig of the webapp servlet/JSP calling this method. 159 * @param props A set of properties, or null, if we are to load JSPWiki's default jspwiki.properties (this is the usual case). 160 * 161 * @return One well-behaving WikiEngine instance. 162 */ 163 public static synchronized WikiEngine getInstance( final ServletConfig config, final Properties props ) { 164 return getInstance( config.getServletContext(), props ); 165 } 166 167 /** 168 * Gets a WikiEngine related to the servlet. Works just like getInstance( ServletConfig ) 169 * 170 * @param context The ServletContext of the webapp servlet/JSP calling this method. 171 * @param props A set of properties, or null, if we are to load JSPWiki's default jspwiki.properties (this is the usual case). 172 * @return One fully functional, properly behaving WikiEngine. 173 * @throws InternalWikiException If the WikiEngine instantiation fails. 174 */ 175 public static synchronized WikiEngine getInstance( final ServletContext context, Properties props ) throws InternalWikiException { 176 WikiEngine engine = ( WikiEngine )context.getAttribute( ATTR_WIKIENGINE ); 177 if( engine == null ) { 178 final String appid = Integer.toString( context.hashCode() ); 179 context.log( " Assigning new engine to " + appid ); 180 try { 181 if( props == null ) { 182 props = PropertyReader.loadWebAppProps( context ); 183 } 184 185 engine = new WikiEngine( context, appid ); 186 try { 187 // Note: May be null, if JSPWiki has been deployed in a WAR file. 188 engine.start( props ); 189 LOG.info( "Root path for this Wiki is: '{}'", engine.getRootPath() ); 190 } catch( final Exception e ) { 191 final String msg = Release.APPNAME + ": Unable to load and setup properties from jspwiki.properties. " + e.getMessage(); 192 context.log( msg ); 193 LOG.error( msg, e ); 194 throw new WikiException( msg, e ); 195 } 196 context.setAttribute( ATTR_WIKIENGINE, engine ); 197 } catch( final Exception e ) { 198 context.log( "ERROR: Failed to create a Wiki engine: " + e.getMessage() ); 199 LOG.error( "ERROR: Failed to create a Wiki engine, stacktrace follows ", e ); 200 throw new InternalWikiException( "No wiki engine, check logs.", e ); 201 } 202 } 203 return engine; 204 } 205 206 /** 207 * Instantiate the WikiEngine using a given set of properties. Use this constructor for testing purposes only. 208 * 209 * @param properties A set of properties to use to initialize this WikiEngine. 210 * @throws WikiException If the initialization fails. 211 */ 212 public WikiEngine( final Properties properties ) throws WikiException { 213 start( properties ); 214 } 215 216 /** 217 * Instantiate using this method when you're running as a servlet and WikiEngine will figure out where to look for the property file. 218 * Do not use this method - use WikiEngine.getInstance() instead. 219 * 220 * @param context A ServletContext. 221 * @param appid An Application ID. This application is a unique random string which is used to recognize this WikiEngine. 222 * @throws WikiException If the WikiEngine construction fails. 223 */ 224 protected WikiEngine( final ServletContext context, final String appid ) throws WikiException { 225 m_servletContext = context; 226 m_appid = appid; 227 228 // Stash the WikiEngine in the servlet context 229 if ( context != null ) { 230 context.setAttribute( ATTR_WIKIENGINE, this ); 231 m_rootPath = context.getRealPath( "/" ); 232 } 233 } 234 235 /** 236 * Does all the real initialization. 237 */ 238 @Override 239 public void initialize( final Properties props ) throws WikiException { 240 m_startTime = new Date(); 241 m_properties = props; 242 243 LOG.info( "*******************************************" ); 244 LOG.info( "{} {} starting. Whee!", Release.APPNAME, Release.getVersionString() ); 245 LOG.debug( "Java version: {}", System.getProperty( "java.runtime.version" ) ); 246 LOG.debug( "Java vendor: {}", System.getProperty( "java.vm.vendor" ) ); 247 LOG.debug( "OS: {} {} {}", System.getProperty( "os.name" ), System.getProperty( "os.version" ), System.getProperty( "os.arch" ) ); 248 LOG.debug( "Default server locale: {}", Locale.getDefault() ); 249 LOG.debug( "Default server timezone: {}", TimeZone.getDefault().getDisplayName( true, TimeZone.LONG ) ); 250 251 if( m_servletContext != null ) { 252 LOG.info( "Servlet container: {}", m_servletContext.getServerInfo() ); 253 if( m_servletContext.getMajorVersion() < 3 || ( m_servletContext.getMajorVersion() == 3 && m_servletContext.getMinorVersion() < 1 ) ) { 254 throw new InternalWikiException( "JSPWiki requires a container which supports at least version 3.1 of Servlet specification" ); 255 } 256 } 257 258 fireEvent( WikiEngineEvent.INITIALIZING ); // begin initialization 259 260 LOG.debug( "Configuring WikiEngine..." ); 261 262 createAndFindWorkingDirectory( props ); 263 264 m_useUTF8 = StandardCharsets.UTF_8.name().equals( TextUtil.getStringProperty( props, PROP_ENCODING, StandardCharsets.ISO_8859_1.name() ) ); 265 m_saveUserInfo = TextUtil.getBooleanProperty( props, PROP_STOREUSERNAME, m_saveUserInfo ); 266 m_frontPage = TextUtil.getStringProperty( props, PROP_FRONTPAGE, "Main" ); 267 m_templateDir = TextUtil.getStringProperty( props, PROP_TEMPLATEDIR, "default" ); 268 enforceValidTemplateDirectory(); 269 270 // 271 // Initialize the important modules. Any exception thrown by the managers means that we will not start up. 272 // 273 try { 274 final String aclClassName = m_properties.getProperty( PROP_ACL_MANAGER_IMPL, ClassUtil.getMappedClass( AclManager.class.getName() ).getName() ); 275 final String urlConstructorClassName = TextUtil.getStringProperty( props, PROP_URLCONSTRUCTOR, "DefaultURLConstructor" ); 276 final Class< URLConstructor > urlclass = ClassUtil.findClass( "org.apache.wiki.url", urlConstructorClassName ); 277 278 initComponent( CommandResolver.class, this, props ); 279 initComponent( urlclass.getName(), URLConstructor.class ); 280 initComponent( CachingManager.class, this, props ); 281 initComponent( PageManager.class, this, props ); 282 initComponent( PluginManager.class, this, props ); 283 initComponent( DifferenceManager.class, this, props ); 284 initComponent( AttachmentManager.class, this, props ); 285 initComponent( VariableManager.class, props ); 286 initComponent( SearchManager.class, this, props ); 287 initComponent( AuthenticationManager.class ); 288 initComponent( AuthorizationManager.class ); 289 initComponent( UserManager.class ); 290 initComponent( GroupManager.class ); 291 initComponent( EditorManager.class, this ); 292 initComponent( ProgressManager.class, this ); 293 initComponent( aclClassName, AclManager.class ); 294 initComponent( WorkflowManager.class ); 295 initComponent( TasksManager.class ); 296 initComponent( InternationalizationManager.class, this ); 297 initComponent( TemplateManager.class, this, props ); 298 initComponent( FilterManager.class, this, props ); 299 initComponent( AdminBeanManager.class, this ); 300 initComponent( PageRenamer.class, this, props ); 301 302 // RenderingManager depends on FilterManager events. 303 initComponent( RenderingManager.class ); 304 305 // ReferenceManager has the side effect of loading all pages. Therefore, after this point, all page attributes are available. 306 // initReferenceManager is indirectly using m_filterManager, so it has to be called after it was initialized. 307 initReferenceManager(); 308 309 // Hook the different manager routines into the system. 310 getManager( FilterManager.class ).addPageFilter( getManager( ReferenceManager.class ), -1001 ); 311 getManager( FilterManager.class ).addPageFilter( getManager( SearchManager.class ), -1002 ); 312 } catch( final RuntimeException e ) { 313 // RuntimeExceptions may occur here, even if they shouldn't. 314 LOG.fatal( "Failed to start managers.", e ); 315 throw new WikiException( "Failed to start managers: " + e.getMessage(), e ); 316 } catch( final ClassNotFoundException e ) { 317 LOG.fatal( "JSPWiki could not start, URLConstructor was not found: {}", e.getMessage(), e ); 318 throw new WikiException( e.getMessage(), e ); 319 } catch( final InstantiationException e ) { 320 LOG.fatal( "JSPWiki could not start, URLConstructor could not be instantiated: {}", e.getMessage(), e ); 321 throw new WikiException( e.getMessage(), e ); 322 } catch( final IllegalAccessException e ) { 323 LOG.fatal( "JSPWiki could not start, URLConstructor cannot be accessed: {}", e.getMessage(), e ); 324 throw new WikiException( e.getMessage(), e ); 325 } catch( final Exception e ) { 326 // Final catch-all for everything 327 LOG.fatal( "JSPWiki could not start, due to an unknown exception when starting.", e ); 328 throw new WikiException( "Failed to start. Caused by: " + e.getMessage() + "; please check log files for better information.", e ); 329 } 330 331 // Initialize the good-to-have-but-not-fatal modules. 332 try { 333 if( TextUtil.getBooleanProperty( props, RSSGenerator.PROP_GENERATE_RSS,false ) ) { 334 initComponent( RSSGenerator.class, this, props ); 335 } 336 } catch( final Exception e ) { 337 LOG.error( "Unable to start RSS generator - JSPWiki will still work, but there will be no RSS feed.", e ); 338 } 339 340 final Map< String, String > extraComponents = ClassUtil.getExtraClassMappings(); 341 initExtraComponents( extraComponents ); 342 343 fireEvent( WikiEngineEvent.INITIALIZED ); // initialization complete 344 345 LOG.info( "WikiEngine configured." ); 346 m_isConfigured = true; 347 } 348 349 void createAndFindWorkingDirectory( final Properties props ) throws WikiException { 350 m_workDir = TextUtil.getStringProperty( props, PROP_WORKDIR, null ); 351 352 final File f = new File( m_workDir ); 353 try { 354 f.mkdirs(); 355 } catch( final SecurityException e ) { 356 LOG.fatal( "Unable to find or create the working directory: {}", m_workDir, e ); 357 throw new WikiException( "Unable to find or create the working dir: " + m_workDir, e ); 358 } 359 360 // A bunch of sanity checks 361 checkWorkingDirectory( !f.exists(), "Work directory does not exist: " + m_workDir ); 362 checkWorkingDirectory( !f.canRead(), "No permission to read work directory: " + m_workDir ); 363 checkWorkingDirectory( !f.canWrite(), "No permission to write to work directory: " + m_workDir ); 364 checkWorkingDirectory( !f.isDirectory(), "jspwiki.workDir does not point to a directory: " + m_workDir ); 365 366 LOG.info( "JSPWiki working directory is '{}'", m_workDir ); 367 } 368 369 void checkWorkingDirectory( final boolean condition, final String errMsg ) throws WikiException { 370 if( condition ) { 371 throw new WikiException( errMsg ); 372 } 373 } 374 375 void initExtraComponents( final Map< String, String > extraComponents ) { 376 for( final Map.Entry< String, String > extraComponent : extraComponents.entrySet() ) { 377 try { 378 LOG.info( "Registering on WikiEngine {} as {}", extraComponent.getKey(), extraComponent.getValue() ); 379 initComponent( extraComponent.getKey(), Class.forName( extraComponent.getValue() ) ); 380 } catch( final Exception e ) { 381 LOG.error( "Unable to start {}", extraComponent.getKey(), e ); 382 } 383 } 384 } 385 386 < T > void initComponent( final Class< T > componentClass, final Object... initArgs ) throws Exception { 387 initComponent( componentClass.getName(), componentClass, initArgs ); 388 } 389 390 < T > void initComponent( final String componentInitClass, final Class< T > componentClass, final Object... initArgs ) throws Exception { 391 final T component; 392 if( initArgs == null || initArgs.length == 0 ) { 393 component = ClassUtil.getMappedObject( componentInitClass ); 394 } else { 395 component = ClassUtil.getMappedObject( componentInitClass, initArgs ); 396 } 397 managers.put( componentClass, component ); 398 if( Initializable.class.isAssignableFrom( component.getClass() ) ) { 399 ( ( Initializable )component ).initialize( this, m_properties ); 400 } 401 } 402 403 /** {@inheritDoc} */ 404 @Override 405 @SuppressWarnings( "unchecked" ) 406 public < T > T getManager( final Class< T > manager ) { 407 return ( T )managers.entrySet().stream() 408 .filter( e -> manager.isAssignableFrom( e.getKey() ) ) 409 .map( Map.Entry::getValue ) 410 .findFirst().orElse( null ); 411 } 412 413 /** {@inheritDoc} */ 414 @Override 415 @SuppressWarnings( "unchecked" ) 416 public < T > List< T > getManagers( final Class< T > manager ) { 417 return ( List< T > )managers.entrySet().stream() 418 .filter( e -> manager.isAssignableFrom( e.getKey() ) ) 419 .map( Map.Entry::getValue ) 420 .collect( Collectors.toList() ); 421 } 422 423 /** {@inheritDoc} */ 424 @Override 425 public boolean isConfigured() { 426 return m_isConfigured; 427 } 428 429 /** 430 * Checks if the template directory specified in the wiki's properties actually exists. If it doesn't, then {@code m_templateDir} is 431 * set to {@link #DEFAULT_TEMPLATE_NAME}. 432 * <p> 433 * This checks the existence of the <tt>ViewTemplate.jsp</tt> file, which exists in every template using {@code m_servletContext.getRealPath("/")}. 434 * <p> 435 * {@code m_servletContext.getRealPath("/")} can return {@code null} on certain servers/conditions (f.ex, packed wars), an extra check 436 * against {@code m_servletContext.getResource} is made. 437 */ 438 void enforceValidTemplateDirectory() { 439 if( m_servletContext != null ) { 440 final String viewTemplate = "templates" + File.separator + getTemplateDir() + File.separator + "ViewTemplate.jsp"; 441 boolean exists = new File( m_servletContext.getRealPath( "/" ) + viewTemplate ).exists(); 442 if( !exists ) { 443 try { 444 final URL url = m_servletContext.getResource( viewTemplate ); 445 exists = url != null && StringUtils.isNotEmpty( url.getFile() ); 446 } catch( final MalformedURLException e ) { 447 LOG.warn( "template not found with viewTemplate {}", viewTemplate ); 448 } 449 } 450 if( !exists ) { 451 LOG.warn( "{} template not found, updating WikiEngine's default template to {}", getTemplateDir(), DEFAULT_TEMPLATE_NAME ); 452 m_templateDir = DEFAULT_TEMPLATE_NAME; 453 } 454 } 455 } 456 457 /** 458 * Initializes the reference manager. Scans all existing WikiPages for 459 * internal links and adds them to the ReferenceManager object. 460 * 461 * @throws WikiException If the reference manager initialization fails. 462 */ 463 public void initReferenceManager() throws WikiException { 464 try { 465 // Build a new manager with default key lists. 466 if( getManager( ReferenceManager.class ) == null ) { 467 final ArrayList< Page > pages = new ArrayList<>(); 468 pages.addAll( getManager( PageManager.class ).getAllPages() ); 469 pages.addAll( getManager( AttachmentManager.class ).getAllAttachments() ); 470 final String refMgrClassName = m_properties.getProperty( PROP_REF_MANAGER_IMPL, ClassUtil.getMappedClass( ReferenceManager.class.getName() ).getName() ); 471 472 initComponent( refMgrClassName, ReferenceManager.class, this ); 473 474 getManager( ReferenceManager.class ).initialize( pages ); 475 } 476 477 } catch( final ProviderException e ) { 478 LOG.fatal( "PageProvider is unable to list pages: ", e ); 479 } catch( final Exception e ) { 480 throw new WikiException( "Could not instantiate ReferenceManager: " + e.getMessage(), e ); 481 } 482 } 483 484 /** {@inheritDoc} */ 485 @Override 486 public Properties getWikiProperties() { 487 return m_properties; 488 } 489 490 /** {@inheritDoc} */ 491 @Override 492 public String getWorkDir() { 493 return m_workDir; 494 } 495 496 /** {@inheritDoc} */ 497 @Override 498 public String getTemplateDir() { 499 return m_templateDir; 500 } 501 502 /** {@inheritDoc} */ 503 @Override 504 public Date getStartTime() { 505 return ( Date )m_startTime.clone(); 506 } 507 508 /** {@inheritDoc} */ 509 @Override 510 public String getBaseURL() { 511 return m_servletContext.getContextPath(); 512 } 513 514 /** {@inheritDoc} */ 515 @Override 516 public String getGlobalRSSURL() { 517 final RSSGenerator rssGenerator = getManager( RSSGenerator.class ); 518 if( rssGenerator != null && rssGenerator.isEnabled() ) { 519 return getBaseURL() + "/" + rssGenerator.getRssFile(); 520 } 521 522 return null; 523 } 524 525 /** {@inheritDoc} */ 526 @Override 527 public String getInterWikiURL( final String wikiName ) { 528 return TextUtil.getStringProperty( m_properties,PROP_INTERWIKIREF + wikiName,null ); 529 } 530 531 /** {@inheritDoc} */ 532 @Override 533 public String getURL( final String context, String pageName, final String params ) { 534 if( pageName == null ) { 535 pageName = getFrontPage(); 536 } 537 final URLConstructor urlConstructor = getManager( URLConstructor.class ); 538 return urlConstructor.makeURL( context, pageName, params ); 539 } 540 541 /** {@inheritDoc} */ 542 @Override 543 public String getFrontPage() { 544 return m_frontPage; 545 } 546 547 /** {@inheritDoc} */ 548 @Override 549 public ServletContext getServletContext() { 550 return m_servletContext; 551 } 552 553 /** {@inheritDoc} */ 554 @Override 555 public Collection< String > getAllInterWikiLinks() { 556 final ArrayList< String > list = new ArrayList<>(); 557 for( final Enumeration< ? > i = m_properties.propertyNames(); i.hasMoreElements(); ) { 558 final String prop = ( String )i.nextElement(); 559 if( prop.startsWith( PROP_INTERWIKIREF ) ) { 560 list.add( prop.substring( prop.lastIndexOf( "." ) + 1 ) ); 561 } 562 } 563 564 return list; 565 } 566 567 /** {@inheritDoc} */ 568 @Override 569 public Collection< String > getAllInlinedImagePatterns() { 570 final ArrayList< String > ptrnlist = new ArrayList<>(); 571 for( final Enumeration< ? > e = m_properties.propertyNames(); e.hasMoreElements(); ) { 572 final String name = ( String )e.nextElement(); 573 if( name.startsWith( PROP_INLINEIMAGEPTRN ) ) { 574 ptrnlist.add( TextUtil.getStringProperty( m_properties, name, null ) ); 575 } 576 } 577 578 if( ptrnlist.isEmpty() ) { 579 ptrnlist.add( DEFAULT_INLINEPATTERN ); 580 } 581 582 return ptrnlist; 583 } 584 585 /** {@inheritDoc} */ 586 @Override 587 public String getSpecialPageReference( final String original ) { 588 return getManager( CommandResolver.class ).getSpecialPageReference( original ); 589 } 590 591 /** {@inheritDoc} */ 592 @Override 593 public String getApplicationName() { 594 final String appName = TextUtil.getStringProperty( m_properties, PROP_APPNAME, Release.APPNAME ); 595 return TextUtil.cleanString( appName, TextUtil.PUNCTUATION_CHARS_ALLOWED ); 596 } 597 598 /** {@inheritDoc} */ 599 @Override 600 public String getFinalPageName( final String page ) throws ProviderException { 601 return getManager( CommandResolver.class ).getFinalPageName( page ); 602 } 603 604 /** {@inheritDoc} */ 605 @Override 606 public String encodeName( final String pagename ) { 607 try { 608 return URLEncoder.encode( pagename, m_useUTF8 ? StandardCharsets.UTF_8.name() : StandardCharsets.ISO_8859_1.name() ); 609 } catch( final UnsupportedEncodingException e ) { 610 throw new InternalWikiException( "ISO-8859-1 not a supported encoding!?! Your platform is borked." , e); 611 } 612 } 613 614 /** {@inheritDoc} */ 615 @Override 616 public String decodeName( final String pagerequest ) { 617 try { 618 return URLDecoder.decode( pagerequest, m_useUTF8 ? StandardCharsets.UTF_8.name() : StandardCharsets.ISO_8859_1.name() ); 619 } catch( final UnsupportedEncodingException e ) { 620 throw new InternalWikiException("ISO-8859-1 not a supported encoding!?! Your platform is borked.", e); 621 } 622 } 623 624 /** {@inheritDoc} */ 625 @Override 626 public Charset getContentEncoding() { 627 if( m_useUTF8 ) { 628 return StandardCharsets.UTF_8; 629 } 630 return StandardCharsets.ISO_8859_1; 631 } 632 633 /** 634 * {@inheritDoc} 635 * <p>It is called by {@link WikiServlet#destroy()}. When this method is called, it fires a "shutdown" WikiEngineEvent to 636 * all registered listeners. 637 */ 638 @Override 639 public void shutdown() { 640 fireEvent( WikiEngineEvent.SHUTDOWN ); 641 getManager( CachingManager.class ).shutdown(); 642 getManager( FilterManager.class ).destroy(); 643 WikiEventManager.shutdown(); 644 } 645 646 /** 647 * Returns the current TemplateManager. 648 * 649 * @return A TemplateManager instance. 650 * @deprecated use {@code getManager( TemplateManager.class )} instead. 651 */ 652 @Deprecated 653 public TemplateManager getTemplateManager() { 654 return getManager( TemplateManager.class ); 655 } 656 657 /** 658 * Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this WikiEngine. If the WikiEngine has not been 659 * initialized, this method will return <code>null</code>. 660 * 661 * @return the task queue 662 * @deprecated use {@code getManager( WorkflowManager.class )} instead. 663 */ 664 @Deprecated 665 public WorkflowManager getWorkflowManager() { 666 return getManager( WorkflowManager.class ); 667 } 668 669 /** 670 * Returns this object's ReferenceManager. 671 * 672 * @return The current ReferenceManager instance. 673 * @since 1.6.1 674 * @deprecated use {@code getManager( ReferenceManager.class )} instead. 675 */ 676 @Deprecated 677 public ReferenceManager getReferenceManager() { 678 return getManager( ReferenceManager.class ); 679 } 680 681 /** 682 * Returns the current rendering manager for this wiki application. 683 * 684 * @since 2.3.27 685 * @return A RenderingManager object. 686 * @deprecated use {@code getManager( RenderingManager.class )} instead. 687 */ 688 @Deprecated 689 public RenderingManager getRenderingManager() { 690 return getManager( RenderingManager.class ); 691 } 692 693 /** 694 * Returns the current plugin manager. 695 * 696 * @since 1.6.1 697 * @return The current PluginManager instance 698 * @deprecated use {@code getManager( PluginManager.class )} instead. 699 */ 700 @Deprecated 701 public PluginManager getPluginManager() { 702 return getManager( PluginManager.class ); 703 } 704 705 /** 706 * Returns the current variable manager. 707 * 708 * @return The current VariableManager. 709 * @deprecated use {@code getManager( VariableManager.class )} instead. 710 */ 711 @Deprecated 712 public VariableManager getVariableManager() { 713 return getManager( VariableManager.class ); 714 } 715 716 /** 717 * Returns the current PageManager which is responsible for storing and managing WikiPages. 718 * 719 * @return The current PageManager instance. 720 * @deprecated use {@code getManager( PageManager.class )} instead. 721 */ 722 @Deprecated 723 public PageManager getPageManager() { 724 return getManager( PageManager.class ); 725 } 726 727 /** 728 * Returns the CommandResolver for this wiki engine. 729 * 730 * @return the resolver 731 * @deprecated use {@code getManager( CommandResolver.class )} instead. 732 */ 733 @Deprecated 734 public CommandResolver getCommandResolver() { 735 return getManager( CommandResolver.class ); 736 } 737 738 /** 739 * Returns the current AttachmentManager, which is responsible for storing and managing attachments. 740 * 741 * @since 1.9.31. 742 * @return The current AttachmentManager instance 743 * @deprecated use {@code getManager( AttachmentManager.class )} instead. 744 */ 745 @Deprecated 746 public AttachmentManager getAttachmentManager() { 747 return getManager( AttachmentManager.class ); 748 } 749 750 /** 751 * Returns the currently used authorization manager. 752 * 753 * @return The current AuthorizationManager instance. 754 * @deprecated use {@code getManager( AuthorizationManager.class )} instead. 755 */ 756 @Deprecated 757 public AuthorizationManager getAuthorizationManager() { 758 return getManager( AuthorizationManager.class ); 759 } 760 761 /** 762 * Returns the currently used authentication manager. 763 * 764 * @return The current AuthenticationManager instance. 765 * @deprecated use {@code getManager( AuthenticationManager.class )} instead. 766 */ 767 @Deprecated 768 public AuthenticationManager getAuthenticationManager() { 769 return getManager( AuthenticationManager.class ); 770 } 771 772 /** 773 * Returns the manager responsible for the filters. 774 * 775 * @since 2.1.88 776 * @return The current FilterManager instance. 777 * @deprecated use {@code getManager( FilterManager.class )} instead. 778 */ 779 @Deprecated 780 public FilterManager getFilterManager() { 781 return getManager( FilterManager.class ); 782 } 783 784 /** 785 * Returns the manager responsible for searching the Wiki. 786 * 787 * @since 2.2.21 788 * @return The current SearchManager instance. 789 * @deprecated use {@code getManager( SearchManager.class )} instead. 790 */ 791 @Deprecated 792 public SearchManager getSearchManager() { 793 return getManager( SearchManager.class ); 794 } 795 796 /** 797 * Returns the progress manager we're using 798 * 799 * @return A ProgressManager. 800 * @since 2.6 801 * @deprecated use {@code getManager( ProgressManager.class )} instead. 802 */ 803 @Deprecated 804 public ProgressManager getProgressManager() { 805 return getManager( ProgressManager.class ); 806 } 807 808 /** {@inheritDoc} */ 809 @Override 810 public String getRootPath() { 811 return m_rootPath; 812 } 813 814 /** 815 * @since 2.2.6 816 * @return the URL constructor. 817 * @deprecated use {@code getManager( URLConstructor.class )} instead. 818 */ 819 @Deprecated 820 public URLConstructor getURLConstructor() { 821 return getManager( URLConstructor.class ); 822 } 823 824 /** 825 * Returns the RSSGenerator. If the property <code>jspwiki.rss.generate</code> has not been set to <code>true</code>, this method 826 * will return <code>null</code>, <em>and callers should check for this value.</em> 827 * 828 * @since 2.1.165 829 * @return the RSS generator 830 * @deprecated use {@code getManager( RSSGenerator.class )} instead. 831 */ 832 @Deprecated 833 public RSSGenerator getRSSGenerator() { 834 return getManager( RSSGenerator.class ); 835 } 836 837 /** 838 * Returns the PageRenamer employed by this WikiEngine. 839 * 840 * @since 2.5.141 841 * @return The current PageRenamer instance. 842 * @deprecated use {@code getManager( PageRenamer.class )} instead. 843 */ 844 @Deprecated 845 public PageRenamer getPageRenamer() { 846 return getManager( PageRenamer.class ); 847 } 848 849 /** 850 * Returns the UserManager employed by this WikiEngine. 851 * 852 * @since 2.3 853 * @return The current UserManager instance. 854 * @deprecated use {@code getManager( UserManager.class )} instead. 855 */ 856 @Deprecated 857 public UserManager getUserManager() { 858 return getManager( UserManager.class ); 859 } 860 861 /** 862 * Returns the TasksManager employed by this WikiEngine. 863 * 864 * @return The current TasksManager instance. 865 * @deprecated use {@code getManager( TaskManager.class )} instead. 866 */ 867 @Deprecated 868 public TasksManager getTasksManager() { 869 return getManager( TasksManager.class ); 870 } 871 872 /** 873 * Returns the GroupManager employed by this WikiEngine. 874 * 875 * @since 2.3 876 * @return The current GroupManager instance. 877 * @deprecated use {@code getManager( GroupManager.class )} instead. 878 */ 879 @Deprecated 880 public GroupManager getGroupManager() { 881 return getManager( GroupManager.class ); 882 } 883 884 /** 885 * Returns the current {@link AdminBeanManager}. 886 * 887 * @return The current {@link AdminBeanManager}. 888 * @since 2.6 889 * @deprecated use {@code getManager( AdminBeanManager.class )} instead. 890 */ 891 @Deprecated 892 public AdminBeanManager getAdminBeanManager() { 893 return getManager( AdminBeanManager.class ); 894 } 895 896 /** 897 * Returns the AclManager employed by this WikiEngine. The AclManager is lazily initialized. 898 * <p> 899 * The AclManager implementing class may be set by the System property {@link #PROP_ACL_MANAGER_IMPL}. 900 * </p> 901 * 902 * @since 2.3 903 * @return The current AclManager. 904 * @deprecated use {@code getManager( AclManager.class )} instead. 905 */ 906 @Deprecated 907 public AclManager getAclManager() { 908 return getManager( AclManager.class ); 909 } 910 911 /** 912 * Returns the DifferenceManager so that texts can be compared. 913 * 914 * @return the difference manager. 915 * @deprecated use {@code getManager( DifferenceManager.class )} instead. 916 */ 917 @Deprecated 918 public DifferenceManager getDifferenceManager() { 919 return getManager( DifferenceManager.class ); 920 } 921 922 /** 923 * Returns the current EditorManager instance. 924 * 925 * @return The current EditorManager. 926 * @deprecated use {@code getManager( EditorManager.class )} instead. 927 */ 928 @Deprecated 929 public EditorManager getEditorManager() { 930 return getManager( EditorManager.class ); 931 } 932 933 /** 934 * Returns the current i18n manager. 935 * 936 * @return The current Intertan... Interante... Internatatializ... Whatever. 937 * @deprecated use {@code getManager( InternationalizationManager.class )} instead. 938 */ 939 @Deprecated 940 public InternationalizationManager getInternationalizationManager() { 941 return getManager( InternationalizationManager.class ); 942 } 943 944 /** {@inheritDoc} */ 945 @Override 946 public final synchronized void addWikiEventListener( final WikiEventListener listener ) { 947 WikiEventManager.addWikiEventListener( this, listener ); 948 } 949 950 /** {@inheritDoc} */ 951 @Override 952 public final synchronized void removeWikiEventListener( final WikiEventListener listener ) { 953 WikiEventManager.removeWikiEventListener( this, listener ); 954 } 955 956 /** 957 * Fires a WikiEngineEvent to all registered listeners. 958 * 959 * @param type the event type 960 */ 961 protected final void fireEvent( final int type ) { 962 if( WikiEventManager.isListening(this ) ) { 963 WikiEventManager.fireEvent( this, new WikiEngineEvent(this, type ) ); 964 } 965 } 966 967 /** 968 * Fires a WikiPageEvent to all registered listeners. 969 * 970 * @param type the event type 971 */ 972 protected final void firePageEvent( final int type, final String pageName ) { 973 if( WikiEventManager.isListening(this ) ) { 974 WikiEventManager.fireEvent(this,new WikiPageEvent(this, type, pageName ) ); 975 } 976 } 977 978 /** {@inheritDoc} */ 979 @Override 980 public void setAttribute( final String key, final Object value ) { 981 m_attributes.put( key, value ); 982 } 983 984 /** {@inheritDoc} */ 985 @Override 986 @SuppressWarnings( "unchecked" ) 987 public < T > T getAttribute( final String key ) { 988 return ( T )m_attributes.get( key ); 989 } 990 991 /** {@inheritDoc} */ 992 @Override 993 @SuppressWarnings( "unchecked" ) 994 public < T > T removeAttribute( final String key ) { 995 return ( T )m_attributes.remove( key ); 996 } 997 998}