JSPWikiPublicAPI

Objectives#

The main goal of the public api is to have a stable codebase that developers can use to extend JSPWiki. Changes in this API would imply a major release.

Starting with 2.11.0.M7, the public API is reachable at the org.apache.jspwiki:jspwiki-api:LATEST_JSPWIKI maven coordinates. Its contents are covered in the following sections.

Core API#

It's composed of the classes and interfaces in the org.apache.wiki.api.core, org.apache.wiki.api.engine, org.apache.wiki.api.exceptions and org.apache.wiki.api.spi packages, plus the org.apache.wiki.api.Release class. It models the core abstractions of JSPWiki:

The default implementation for these abstractions are:

warning note that these default implementations should never be instantiated/accessed directly or, generally speaking, appear in an extension code. The concrete implementation of the public API used by JSPWiki is selected through an SPI, so it is not impossible that a JSPWiki installation may be running with a different implementation.

To obtain instances from the public API you may use:

Providing custom core API implementations#

As noted before, the concrete implementation of the public API used by JSPWiki is selected through an SPI, so it is easy to provide custom implementations for the core API:

info note that for these SPIs to work, each of these implementations must be accompanied by its corresponding META-INF/services/$IMPLEMENTED_INTERFACE file whose content must also be the fully qualified class name of the implementation.

Registering custom managers in the WikiEngine#

It is possible to register custom "Engine parts" (managers or components or however they end up being called):

Please also note that

Plugins#

It's composed of the classes and interfaces in the org.apache.wiki.api.plugins package.

This part of the public API is covered in detail in the How to write a Plugin page.

Filters#

It's composed of the classes and interfaces in the org.apache.wiki.api.filter package.

This part of the public API is covered in detail in the How to write a Filter page.

Page and Attachment providers#

It's composed of the classes and interfaces in the org.apache.wiki.api.providers and org.apache.wiki.api.search package.

This part of the public API is covered in detail in the How to write a Page Provider page.

Engine lifecycle extensions#

Another SPI to allow custom components be aware of Engine's initialization and shutdown, without having to deep dive on Engine's internals. The interface to be implemented in this case is org.apache.wiki.api.engine.EngineLifecycleExtension, which is described in detail in the How to write an engine lifecycle extension page.

Event Listeners#

Yet another SPI to allow easy registering of custom wiki event listeners, without having to care on how to properly register it. The interface to be implemented in this case is org.apache.wiki.api.events.CustomWikiEventListener, which is described in detail in the How to write a custom wiki event listener page.

Logging#

Log4J2 is used to do all the logging inside JSPWiki, with all Log4J (and SLF4J) calls transparently routed to Log4J2. As such, existing 3rd party plugins, filters and providers will continue to log as expected, as Log4J calls will be routed to Log4J2, but the use of Log4J2 should be preferred onwards.

By default, JSPWiki will configure Log4J2 from the jspwiki[-custom].properties files, expecting log configuration to be there using Log4J2 properties syntax. jspwiki.use.external.logconfig=true can be set on jspwiki[-custom].properties files to bypass JSPWiki log re-configuration and rely directly on Log4J2 configuration mechanisms.

warning if you're using a JSPWiki customized .war, please ensure that neither Log4J nor any SLF4J implementation end up in your customized .war.

Testing#

Most, if not all, of the API you'll be working with will be interfaces, so the appropiate way for unit testing an extension is to mock them with a mocking library, like for example Mockito.

Said that, there's a maven artifact, not part of the public API, which holds JSPWiki end-to-end testing support classes. It should be added as a dependency following this configuration:

<dependency>
  <groupId>org.apache.jspwiki</groupId>
  <artifactId>jspwiki-main</artifactId>
  <type>test-jar</type>
  <version>LATEST_JSPWIKI</version>
  <scope>test</scope>
</dependency>

The most important class in this artifact is org.apache.wiki.TestEngine which is an Engine implementation suitable to be used while testing. It allows to mimic JSPWiki running behaviour and has a number of static build(..) methods which make really easy to have a TestEngine up and running:

package com.myorg.jspwiki.extensions;

import org.apache.wiki.TestEngine;
import org.apache.wiki.api.providers.PageProvider;
import org.apache.wiki.api.spi.Wiki;
import org.apache.wiki.pages.PageManager;
[...]

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
[...]

import static org.apache.wiki.TestEngine.with;

public class MyAwesomeTest {

    static TestEngine engine = TestEngine.build( with( "jspwiki.usePageCache", "false" ),
	    			        					 with( "jspwiki.pageProvider", "WikiPageAdapterProvider" ),
	    			        					 with( "jspwiki.attachmentProvider", "WikiAttachmentAdapterProvider" ),
		    		        					 with( "jspwiki.pageProvider.adapter.impl", "com.myorg.jspwiki.extensions.AwesomePageProvider" ),
		    			        				 with( "jspwiki.attachmentProvider.adapter.impl", "com.myorg.jspwiki.extensions.AwesomeAttachmentProvider" ) );

    @Test
    public void testPageProvider() throws Exception {
        final PageProvider pageProvider = engine.getManager( PageManager.class ).getProvider();
        Assertions.assertEquals( "com.myorg.jspwiki.extensions.AwesomePageProvider", pageProvider.getProviderInfo() );
        
        pageProvider.putPageText( Wiki.contents.page( engine, "page4" ), "some crazy text here" );
        Assertions.assertTrue( pageProvider.pageExists( "page4" ) );
    }
[...]	    							  
}
info note how TestEngine is defined with an static qualifier. This ensures the Engine is only initialized once throughout all the tests' executions.

My/An extension is not using the public API, what do I do?#

If you are the extension's author, please consider a new release upgrading your extension to use the public API.

If you are using an extension that does not use the public API, consider contacting the extension author so he/she considers a new release. In the meantime, JSPWiki includes an specific module, org.apache.jspwiki:jspwiki-210-adapters which provides backwards compatibility with extensions not using the public API.

Plugins and filters not using the public API don't need anything special, they should still keep working.

Page and attachment providers should modify its jspwiki-[custom].properties:

warning note this module is subject to disappear at some point in the future, on a minor release, so extension authors should consider migrating to the public API.

warning provided compatibility is limited to the execution of extensions not using the public API. If, for whatever reason, an extension uses part of JSPWiki that has disappeared due to minor release versioning, then the extension will be loaded but it is bound to cause an exception when reaching that piece of code (this of course applies to extensions using the public API anyway).


Category.Documentation