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 if( StringUtils.isBlank( m_workDir ) ) { 352 m_workDir = System.getProperty( "java.io.tmpdir", "." ) + File.separator + Release.APPNAME + "-" + m_appid; 353 } 354 355 final File f = new File( m_workDir ); 356 try { 357 f.mkdirs(); 358 } catch( final SecurityException e ) { 359 LOG.fatal( "Unable to find or create the working directory: {}", m_workDir, e ); 360 throw new WikiException( "Unable to find or create the working dir: " + m_workDir, e ); 361 } 362 363 // A bunch of sanity checks 364 checkWorkingDirectory( !f.exists(), "Work directory does not exist: " + m_workDir ); 365 checkWorkingDirectory( !f.canRead(), "No permission to read work directory: " + m_workDir ); 366 checkWorkingDirectory( !f.canWrite(), "No permission to write to work directory: " + m_workDir ); 367 checkWorkingDirectory( !f.isDirectory(), "jspwiki.workDir does not point to a directory: " + m_workDir ); 368 369 LOG.info( "JSPWiki working directory is '{}'", m_workDir ); 370 } 371 372 void checkWorkingDirectory( final boolean condition, final String errMsg ) throws WikiException { 373 if( condition ) { 374 throw new WikiException( errMsg ); 375 } 376 } 377 378 void initExtraComponents( final Map< String, String > extraComponents ) { 379 for( final Map.Entry< String, String > extraComponent : extraComponents.entrySet() ) { 380 try { 381 LOG.info( "Registering on WikiEngine {} as {}", extraComponent.getKey(), extraComponent.getValue() ); 382 initComponent( extraComponent.getKey(), Class.forName( extraComponent.getValue() ) ); 383 } catch( final Exception e ) { 384 LOG.error( "Unable to start {}", extraComponent.getKey(), e ); 385 } 386 } 387 } 388 389 < T > void initComponent( final Class< T > componentClass, final Object... initArgs ) throws Exception { 390 initComponent( componentClass.getName(), componentClass, initArgs ); 391 } 392 393 < T > void initComponent( final String componentInitClass, final Class< T > componentClass, final Object... initArgs ) throws Exception { 394 final T component; 395 if( initArgs == null || initArgs.length == 0 ) { 396 component = ClassUtil.getMappedObject( componentInitClass ); 397 } else { 398 component = ClassUtil.getMappedObject( componentInitClass, initArgs ); 399 } 400 managers.put( componentClass, component ); 401 if( Initializable.class.isAssignableFrom( component.getClass() ) ) { 402 ( ( Initializable )component ).initialize( this, m_properties ); 403 } 404 } 405 406 /** {@inheritDoc} */ 407 @Override 408 @SuppressWarnings( "unchecked" ) 409 public < T > T getManager( final Class< T > manager ) { 410 return ( T )managers.entrySet().stream() 411 .filter( e -> manager.isAssignableFrom( e.getKey() ) ) 412 .map( Map.Entry::getValue ) 413 .findFirst().orElse( null ); 414 } 415 416 /** {@inheritDoc} */ 417 @Override 418 @SuppressWarnings( "unchecked" ) 419 public < T > List< T > getManagers( final Class< T > manager ) { 420 return ( List< T > )managers.entrySet().stream() 421 .filter( e -> manager.isAssignableFrom( e.getKey() ) ) 422 .map( Map.Entry::getValue ) 423 .collect( Collectors.toList() ); 424 } 425 426 /** {@inheritDoc} */ 427 @Override 428 public boolean isConfigured() { 429 return m_isConfigured; 430 } 431 432 /** 433 * Checks if the template directory specified in the wiki's properties actually exists. If it doesn't, then {@code m_templateDir} is 434 * set to {@link #DEFAULT_TEMPLATE_NAME}. 435 * <p> 436 * This checks the existence of the <tt>ViewTemplate.jsp</tt> file, which exists in every template using {@code m_servletContext.getRealPath("/")}. 437 * <p> 438 * {@code m_servletContext.getRealPath("/")} can return {@code null} on certain servers/conditions (f.ex, packed wars), an extra check 439 * against {@code m_servletContext.getResource} is made. 440 */ 441 void enforceValidTemplateDirectory() { 442 if( m_servletContext != null ) { 443 final String viewTemplate = "templates" + File.separator + getTemplateDir() + File.separator + "ViewTemplate.jsp"; 444 boolean exists = new File( m_servletContext.getRealPath( "/" ) + viewTemplate ).exists(); 445 if( !exists ) { 446 try { 447 final URL url = m_servletContext.getResource( viewTemplate ); 448 exists = url != null && StringUtils.isNotEmpty( url.getFile() ); 449 } catch( final MalformedURLException e ) { 450 LOG.warn( "template not found with viewTemplate {}", viewTemplate ); 451 } 452 } 453 if( !exists ) { 454 LOG.warn( "{} template not found, updating WikiEngine's default template to {}", getTemplateDir(), DEFAULT_TEMPLATE_NAME ); 455 m_templateDir = DEFAULT_TEMPLATE_NAME; 456 } 457 } 458 } 459 460 /** 461 * Initializes the reference manager. Scans all existing WikiPages for 462 * internal links and adds them to the ReferenceManager object. 463 * 464 * @throws WikiException If the reference manager initialization fails. 465 */ 466 public void initReferenceManager() throws WikiException { 467 try { 468 // Build a new manager with default key lists. 469 if( getManager( ReferenceManager.class ) == null ) { 470 final ArrayList< Page > pages = new ArrayList<>(); 471 pages.addAll( getManager( PageManager.class ).getAllPages() ); 472 pages.addAll( getManager( AttachmentManager.class ).getAllAttachments() ); 473 initComponent( ReferenceManager.class, this ); 474 475 getManager( ReferenceManager.class ).initialize( pages ); 476 } 477 478 } catch( final ProviderException e ) { 479 LOG.fatal( "PageProvider is unable to list pages: ", e ); 480 } catch( final Exception e ) { 481 throw new WikiException( "Could not instantiate ReferenceManager: " + e.getMessage(), e ); 482 } 483 } 484 485 /** {@inheritDoc} */ 486 @Override 487 public Properties getWikiProperties() { 488 return m_properties; 489 } 490 491 /** {@inheritDoc} */ 492 @Override 493 public String getWorkDir() { 494 return m_workDir; 495 } 496 497 /** {@inheritDoc} */ 498 @Override 499 public String getTemplateDir() { 500 return m_templateDir; 501 } 502 503 /** {@inheritDoc} */ 504 @Override 505 public Date getStartTime() { 506 return ( Date )m_startTime.clone(); 507 } 508 509 /** {@inheritDoc} */ 510 @Override 511 public String getBaseURL() { 512 return m_servletContext.getContextPath(); 513 } 514 515 /** {@inheritDoc} */ 516 @Override 517 public String getGlobalRSSURL() { 518 final RSSGenerator rssGenerator = getManager( RSSGenerator.class ); 519 if( rssGenerator != null && rssGenerator.isEnabled() ) { 520 return getBaseURL() + "/" + rssGenerator.getRssFile(); 521 } 522 523 return null; 524 } 525 526 /** {@inheritDoc} */ 527 @Override 528 public String getInterWikiURL( final String wikiName ) { 529 return TextUtil.getStringProperty( m_properties,PROP_INTERWIKIREF + wikiName,null ); 530 } 531 532 /** {@inheritDoc} */ 533 @Override 534 public String getURL( final String context, String pageName, final String params ) { 535 if( pageName == null ) { 536 pageName = getFrontPage(); 537 } 538 final URLConstructor urlConstructor = getManager( URLConstructor.class ); 539 return urlConstructor.makeURL( context, pageName, params ); 540 } 541 542 /** {@inheritDoc} */ 543 @Override 544 public String getFrontPage() { 545 return m_frontPage; 546 } 547 548 /** {@inheritDoc} */ 549 @Override 550 public ServletContext getServletContext() { 551 return m_servletContext; 552 } 553 554 /** {@inheritDoc} */ 555 @Override 556 public Collection< String > getAllInterWikiLinks() { 557 final ArrayList< String > list = new ArrayList<>(); 558 for( final Enumeration< ? > i = m_properties.propertyNames(); i.hasMoreElements(); ) { 559 final String prop = ( String )i.nextElement(); 560 if( prop.startsWith( PROP_INTERWIKIREF ) ) { 561 list.add( prop.substring( prop.lastIndexOf( "." ) + 1 ) ); 562 } 563 } 564 565 return list; 566 } 567 568 /** {@inheritDoc} */ 569 @Override 570 public Collection< String > getAllInlinedImagePatterns() { 571 final ArrayList< String > ptrnlist = new ArrayList<>(); 572 for( final Enumeration< ? > e = m_properties.propertyNames(); e.hasMoreElements(); ) { 573 final String name = ( String )e.nextElement(); 574 if( name.startsWith( PROP_INLINEIMAGEPTRN ) ) { 575 ptrnlist.add( TextUtil.getStringProperty( m_properties, name, null ) ); 576 } 577 } 578 579 if( ptrnlist.isEmpty() ) { 580 ptrnlist.add( DEFAULT_INLINEPATTERN ); 581 } 582 583 return ptrnlist; 584 } 585 586 /** {@inheritDoc} */ 587 @Override 588 public String getSpecialPageReference( final String original ) { 589 return getManager( CommandResolver.class ).getSpecialPageReference( original ); 590 } 591 592 /** {@inheritDoc} */ 593 @Override 594 public String getApplicationName() { 595 final String appName = TextUtil.getStringProperty( m_properties, PROP_APPNAME, Release.APPNAME ); 596 return TextUtil.cleanString( appName, TextUtil.PUNCTUATION_CHARS_ALLOWED ); 597 } 598 599 /** {@inheritDoc} */ 600 @Override 601 public String getFinalPageName( final String page ) throws ProviderException { 602 return getManager( CommandResolver.class ).getFinalPageName( page ); 603 } 604 605 /** {@inheritDoc} */ 606 @Override 607 public String encodeName( final String pagename ) { 608 try { 609 return URLEncoder.encode( pagename, m_useUTF8 ? StandardCharsets.UTF_8.name() : StandardCharsets.ISO_8859_1.name() ); 610 } catch( final UnsupportedEncodingException e ) { 611 throw new InternalWikiException( "ISO-8859-1 not a supported encoding!?! Your platform is borked." , e); 612 } 613 } 614 615 /** {@inheritDoc} */ 616 @Override 617 public String decodeName( final String pagerequest ) { 618 try { 619 return URLDecoder.decode( pagerequest, m_useUTF8 ? StandardCharsets.UTF_8.name() : StandardCharsets.ISO_8859_1.name() ); 620 } catch( final UnsupportedEncodingException e ) { 621 throw new InternalWikiException("ISO-8859-1 not a supported encoding!?! Your platform is borked.", e); 622 } 623 } 624 625 /** {@inheritDoc} */ 626 @Override 627 public Charset getContentEncoding() { 628 if( m_useUTF8 ) { 629 return StandardCharsets.UTF_8; 630 } 631 return StandardCharsets.ISO_8859_1; 632 } 633 634 /** 635 * {@inheritDoc} 636 * <p>It is called by {@link WikiServlet#destroy()}. When this method is called, it fires a "shutdown" WikiEngineEvent to 637 * all registered listeners. 638 */ 639 @Override 640 public void shutdown() { 641 fireEvent( WikiEngineEvent.SHUTDOWN ); 642 getManager( CachingManager.class ).shutdown(); 643 getManager( FilterManager.class ).destroy(); 644 WikiEventManager.shutdown(); 645 } 646 647 /** 648 * Returns the current TemplateManager. 649 * 650 * @return A TemplateManager instance. 651 * @deprecated use {@code getManager( TemplateManager.class )} instead. 652 */ 653 @Deprecated 654 public TemplateManager getTemplateManager() { 655 return getManager( TemplateManager.class ); 656 } 657 658 /** 659 * Returns the {@link org.apache.wiki.workflow.WorkflowManager} associated with this WikiEngine. If the WikiEngine has not been 660 * initialized, this method will return <code>null</code>. 661 * 662 * @return the task queue 663 * @deprecated use {@code getManager( WorkflowManager.class )} instead. 664 */ 665 @Deprecated 666 public WorkflowManager getWorkflowManager() { 667 return getManager( WorkflowManager.class ); 668 } 669 670 /** 671 * Returns this object's ReferenceManager. 672 * 673 * @return The current ReferenceManager instance. 674 * @since 1.6.1 675 * @deprecated use {@code getManager( ReferenceManager.class )} instead. 676 */ 677 @Deprecated 678 public ReferenceManager getReferenceManager() { 679 return getManager( ReferenceManager.class ); 680 } 681 682 /** 683 * Returns the current rendering manager for this wiki application. 684 * 685 * @since 2.3.27 686 * @return A RenderingManager object. 687 * @deprecated use {@code getManager( RenderingManager.class )} instead. 688 */ 689 @Deprecated 690 public RenderingManager getRenderingManager() { 691 return getManager( RenderingManager.class ); 692 } 693 694 /** 695 * Returns the current plugin manager. 696 * 697 * @since 1.6.1 698 * @return The current PluginManager instance 699 * @deprecated use {@code getManager( PluginManager.class )} instead. 700 */ 701 @Deprecated 702 public PluginManager getPluginManager() { 703 return getManager( PluginManager.class ); 704 } 705 706 /** 707 * Returns the current variable manager. 708 * 709 * @return The current VariableManager. 710 * @deprecated use {@code getManager( VariableManager.class )} instead. 711 */ 712 @Deprecated 713 public VariableManager getVariableManager() { 714 return getManager( VariableManager.class ); 715 } 716 717 /** 718 * Returns the current PageManager which is responsible for storing and managing WikiPages. 719 * 720 * @return The current PageManager instance. 721 * @deprecated use {@code getManager( PageManager.class )} instead. 722 */ 723 @Deprecated 724 public PageManager getPageManager() { 725 return getManager( PageManager.class ); 726 } 727 728 /** 729 * Returns the CommandResolver for this wiki engine. 730 * 731 * @return the resolver 732 * @deprecated use {@code getManager( CommandResolver.class )} instead. 733 */ 734 @Deprecated 735 public CommandResolver getCommandResolver() { 736 return getManager( CommandResolver.class ); 737 } 738 739 /** 740 * Returns the current AttachmentManager, which is responsible for storing and managing attachments. 741 * 742 * @since 1.9.31. 743 * @return The current AttachmentManager instance 744 * @deprecated use {@code getManager( AttachmentManager.class )} instead. 745 */ 746 @Deprecated 747 public AttachmentManager getAttachmentManager() { 748 return getManager( AttachmentManager.class ); 749 } 750 751 /** 752 * Returns the currently used authorization manager. 753 * 754 * @return The current AuthorizationManager instance. 755 * @deprecated use {@code getManager( AuthorizationManager.class )} instead. 756 */ 757 @Deprecated 758 public AuthorizationManager getAuthorizationManager() { 759 return getManager( AuthorizationManager.class ); 760 } 761 762 /** 763 * Returns the currently used authentication manager. 764 * 765 * @return The current AuthenticationManager instance. 766 * @deprecated use {@code getManager( AuthenticationManager.class )} instead. 767 */ 768 @Deprecated 769 public AuthenticationManager getAuthenticationManager() { 770 return getManager( AuthenticationManager.class ); 771 } 772 773 /** 774 * Returns the manager responsible for the filters. 775 * 776 * @since 2.1.88 777 * @return The current FilterManager instance. 778 * @deprecated use {@code getManager( FilterManager.class )} instead. 779 */ 780 @Deprecated 781 public FilterManager getFilterManager() { 782 return getManager( FilterManager.class ); 783 } 784 785 /** 786 * Returns the manager responsible for searching the Wiki. 787 * 788 * @since 2.2.21 789 * @return The current SearchManager instance. 790 * @deprecated use {@code getManager( SearchManager.class )} instead. 791 */ 792 @Deprecated 793 public SearchManager getSearchManager() { 794 return getManager( SearchManager.class ); 795 } 796 797 /** 798 * Returns the progress manager we're using 799 * 800 * @return A ProgressManager. 801 * @since 2.6 802 * @deprecated use {@code getManager( ProgressManager.class )} instead. 803 */ 804 @Deprecated 805 public ProgressManager getProgressManager() { 806 return getManager( ProgressManager.class ); 807 } 808 809 /** {@inheritDoc} */ 810 @Override 811 public String getRootPath() { 812 return m_rootPath; 813 } 814 815 /** 816 * @since 2.2.6 817 * @return the URL constructor. 818 * @deprecated use {@code getManager( URLConstructor.class )} instead. 819 */ 820 @Deprecated 821 public URLConstructor getURLConstructor() { 822 return getManager( URLConstructor.class ); 823 } 824 825 /** 826 * Returns the RSSGenerator. If the property <code>jspwiki.rss.generate</code> has not been set to <code>true</code>, this method 827 * will return <code>null</code>, <em>and callers should check for this value.</em> 828 * 829 * @since 2.1.165 830 * @return the RSS generator 831 * @deprecated use {@code getManager( RSSGenerator.class )} instead. 832 */ 833 @Deprecated 834 public RSSGenerator getRSSGenerator() { 835 return getManager( RSSGenerator.class ); 836 } 837 838 /** 839 * Returns the PageRenamer employed by this WikiEngine. 840 * 841 * @since 2.5.141 842 * @return The current PageRenamer instance. 843 * @deprecated use {@code getManager( PageRenamer.class )} instead. 844 */ 845 @Deprecated 846 public PageRenamer getPageRenamer() { 847 return getManager( PageRenamer.class ); 848 } 849 850 /** 851 * Returns the UserManager employed by this WikiEngine. 852 * 853 * @since 2.3 854 * @return The current UserManager instance. 855 * @deprecated use {@code getManager( UserManager.class )} instead. 856 */ 857 @Deprecated 858 public UserManager getUserManager() { 859 return getManager( UserManager.class ); 860 } 861 862 /** 863 * Returns the TasksManager employed by this WikiEngine. 864 * 865 * @return The current TasksManager instance. 866 * @deprecated use {@code getManager( TaskManager.class )} instead. 867 */ 868 @Deprecated 869 public TasksManager getTasksManager() { 870 return getManager( TasksManager.class ); 871 } 872 873 /** 874 * Returns the GroupManager employed by this WikiEngine. 875 * 876 * @since 2.3 877 * @return The current GroupManager instance. 878 * @deprecated use {@code getManager( GroupManager.class )} instead. 879 */ 880 @Deprecated 881 public GroupManager getGroupManager() { 882 return getManager( GroupManager.class ); 883 } 884 885 /** 886 * Returns the current {@link AdminBeanManager}. 887 * 888 * @return The current {@link AdminBeanManager}. 889 * @since 2.6 890 * @deprecated use {@code getManager( AdminBeanManager.class )} instead. 891 */ 892 @Deprecated 893 public AdminBeanManager getAdminBeanManager() { 894 return getManager( AdminBeanManager.class ); 895 } 896 897 /** 898 * Returns the AclManager employed by this WikiEngine. The AclManager is lazily initialized. 899 * <p> 900 * The AclManager implementing class may be set by the System property {@link #PROP_ACL_MANAGER_IMPL}. 901 * </p> 902 * 903 * @since 2.3 904 * @return The current AclManager. 905 * @deprecated use {@code getManager( AclManager.class )} instead. 906 */ 907 @Deprecated 908 public AclManager getAclManager() { 909 return getManager( AclManager.class ); 910 } 911 912 /** 913 * Returns the DifferenceManager so that texts can be compared. 914 * 915 * @return the difference manager. 916 * @deprecated use {@code getManager( DifferenceManager.class )} instead. 917 */ 918 @Deprecated 919 public DifferenceManager getDifferenceManager() { 920 return getManager( DifferenceManager.class ); 921 } 922 923 /** 924 * Returns the current EditorManager instance. 925 * 926 * @return The current EditorManager. 927 * @deprecated use {@code getManager( EditorManager.class )} instead. 928 */ 929 @Deprecated 930 public EditorManager getEditorManager() { 931 return getManager( EditorManager.class ); 932 } 933 934 /** 935 * Returns the current i18n manager. 936 * 937 * @return The current Intertan... Interante... Internatatializ... Whatever. 938 * @deprecated use {@code getManager( InternationalizationManager.class )} instead. 939 */ 940 @Deprecated 941 public InternationalizationManager getInternationalizationManager() { 942 return getManager( InternationalizationManager.class ); 943 } 944 945 /** {@inheritDoc} */ 946 @Override 947 public final synchronized void addWikiEventListener( final WikiEventListener listener ) { 948 WikiEventManager.addWikiEventListener( this, listener ); 949 } 950 951 /** {@inheritDoc} */ 952 @Override 953 public final synchronized void removeWikiEventListener( final WikiEventListener listener ) { 954 WikiEventManager.removeWikiEventListener( this, listener ); 955 } 956 957 /** 958 * Fires a WikiEngineEvent to all registered listeners. 959 * 960 * @param type the event type 961 */ 962 protected final void fireEvent( final int type ) { 963 if( WikiEventManager.isListening(this ) ) { 964 WikiEventManager.fireEvent( this, new WikiEngineEvent(this, type ) ); 965 } 966 } 967 968 /** 969 * Fires a WikiPageEvent to all registered listeners. 970 * 971 * @param type the event type 972 */ 973 protected final void firePageEvent( final int type, final String pageName ) { 974 if( WikiEventManager.isListening(this ) ) { 975 WikiEventManager.fireEvent(this,new WikiPageEvent(this, type, pageName ) ); 976 } 977 } 978 979 /** {@inheritDoc} */ 980 @Override 981 public void setAttribute( final String key, final Object value ) { 982 m_attributes.put( key, value ); 983 } 984 985 /** {@inheritDoc} */ 986 @Override 987 @SuppressWarnings( "unchecked" ) 988 public < T > T getAttribute( final String key ) { 989 return ( T )m_attributes.get( key ); 990 } 991 992 /** {@inheritDoc} */ 993 @Override 994 @SuppressWarnings( "unchecked" ) 995 public < T > T removeAttribute( final String key ) { 996 return ( T )m_attributes.remove( key ); 997 } 998 999}