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