IES extensions extend the functionality of the IES. With the help of an API these extensions can be implemented.
Add the following Maven dependency to use the API.
<dependency>
<groupId>com.sitepark.ies</groupId>
<artifactId>ies-extension-api</artifactId>
<version>1.0.0</version>
<scope>provided</scope>
</dependency>The starting point of each extension is the interface com.sitepark.ies.extension.api.Extension.
package com.sitepark.ies.extension.api;
public interface Extension {
void initialize();
default void destroy() {
}
}The initialize() method is called when the extension is started. Here e.g. event handlers can be registered or
background processes can be started.
The destroy() method is called when the extension is terminated. If event handlers have been registered, they must be
unregistered here. Background processes must also be stopped here.
All extensions that implement this interface will be executed automatically. It is not necessary to register them anywhere.
There are several services that can be used via the API. These are provided via port interfaces. You can access these
services via dependency injection. All port interfaces that can be used via the API are contained in the package
com.sitepark.ies.extension.api.port.
For this purpose the constructor must be marked with the annotation @javax.inject.Inject.
import javax.inject.Inject;
import com.sitepark.ies.extension.api.Extension;
public class MyExtension implements Extension {
private final SomeService someService;
@Inject
protected MyExtension(SomeService someService) {
this.someService = someService;
}
}Maven dependency for @Inject
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
<scope>provided</scope>
</dependency>Extensions can react to events in the IES. All events to which the extension can react are contained in the package
com.sitepark.ies.extension.api.events.
To register a handler for a specific event the port interface EventBusSubscriber is used. An object is passed to the
register() method. This is scanned for the @com.sitepark.ies.extension.api.annotations.Subscribe annotation and
registers the appropriately marked methods for the event that the method accepts. Inheritance hierarchies of the event
classes are supported.
It is important that registered handlers are unregistered via the unregister() method of the EventBusSubscriber when
the extension is terminated.
import javax.inject.Inject;
import com.sitepark.ies.extension.api.Extension;
import com.sitepark.ies.extension.api.annotations.Subscribe;
import com.sitepark.ies.extension.api.events.ContentEntryPurged;
import com.sitepark.ies.extension.api.port.EventBusSubscriber;
public class MyExtension implements Extension {
private final EventBusSubscriber eventBusSubscriber;
@Inject
protected MyExtension(EventBusSubscriber eventBusSubscriber) {
this.eventBusSubscriber = eventBusSubscriber;
}
@Override
public void initialize() {
this.eventBusSubscriber.register(this);
}
@Override
public void destroy() {
this.eventBusSubscriber.unregister(this);
}
@Subscribe
public void purgeHandler(ContentEntryPurged purgeEvent) {
// todo something
}
}The extension class itself serves only as an entry point. In most cases it makes sense to outsource the logic of the extension into different classes. These classes should also be injected into the extension constructor.
The own classes can also be injected in the extension constructor. Also, the own classes can be annotated with @Inject
to inject own or API classes.
import javax.inject.Inject;
import com.sitepark.ies.extension.api.annotations.Subscribe;
import com.sitepark.ies.extension.api.events.ContentEntryPurged;
import com.sitepark.ies.extension.api.port.EventBusSubscriber;
public class MyService {
private final EventBusSubscriber eventBusSubscriber;
@Inject
protected MyService(EventBusSubscriber eventBusSubscriber) {
this.eventBusSubscriber = eventBusSubscriber;
}
@Override
public void initialize() {
this.eventBusSubscriber.register(this);
}
@Override
public void destroy() {
this.eventBusSubscriber.unregister(this);
}
@Subscribe
public void purgeHandler(ContentEntryPurged purgeEvent) {
// todo something
}
}Use MyService in MyExtension
import javax.inject.Inject;
import com.sitepark.ies.extension.api.Extension;
public class MyExtension implements Extension {
private final MyService myService;
@Inject
protected MyExtension(MyService myService) {
this.myService = myService;
}
@Override
public void initialize() {
this.myService.initialize();
}
@Override
public void destroy() {
this.myService.destroy();
}
}The IES uses Guice as the dependency injection framework.
Maven dependency:
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>5.1.0</version>
<scope>provided</scope>
</dependency>The full functionality of the framework can also be used in the extension. For this purpose it is necessary to create a Guice module. This module must be known before the extension object is created. Therefore, a static method is used here, with which Factory configurations can be set. The extensions are created via a factory, whose behavior can be controlled via the factory configuration.
To set the created Guice module in the factory configuration, a static method is marked in the extension class with the
annotation @com.sitepark.ies.extension.api.annotations.ConfigureFactory. The marked method must take an argument of
the com.sitepark.ies.extension.api.FactoryConfig class. The FactoryConfig can be used to pass the Guice module using
the addInjectionModule() method.
import com.google.inject.AbstractModule;
public class MyInjectionModule extends AbstractModule {
@Override
protected void initialize() {
// ...
}
}Set MyInjectionModule to FactoryConfig
import com.sitepark.ies.extension.api.FactoryConfig;
import com.sitepark.ies.extension.api.Extension;
import com.sitepark.ies.extension.api.annotations.ConfigureFactory;
public class MyExtension implements Extension {
@ConfigureFactory
public static void configureInjection(FactoryConfig config) {
config.addInjectionModule(new MyInjectionModule());
}
}@ConfigureFactory can only be used in classes that implement the Extension interface.
The IES uses MyBatis, a SQL mapping framework. This can also be used in the extensions.
MyBatis has a Guice integration that can also be used for IES extensions.
Maven dependency:
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-guice</artifactId>
<version>3.17</version>
<scope>provided</scope>
</dependency>For this purpose MyBatisModule is extended as an injection module and made known to the extension factory.
import org.mybatis.guice.MyBatisModule;
public class MyBatisInjectionModule extends MyBatisModule {
@Override
protected void initialize() {
// ...
addMapperClass(MyRepositoryMapper.class);
}
}Mapper example:
import org.apache.ibatis.annotations.Delete;
public interface MyRepositoryMapper {
@Delete("DELETE FROM `MyTable` where `id` = #{id}")
int delete(long id);
}Set MyBatisInjectionModule to FactoryConfig
import com.sitepark.ies.extension.api.FactoryConfig;
import com.sitepark.ies.extension.api.Extension;
import com.sitepark.ies.extension.api.annotations.ConfigureFactory;
public class MyExtension implements Extension {
@ConfigureFactory
public static void configureInjection(FactoryConfig config) {
config.addInjectionModule(new MyBatisInjectionModule());
}
}MyMapper can now be injected.
import javax.inject.Inject;
public class MyRepository {
private final MyMapper mapper;
@Inject
protected MyRepository(MyMapper mapper) {
this.mapper = mapper;
}
public void delete(long id) {
this.mapper.delete(id);
}
}Extensions can provide their own servlets. For this purpose, the IES uses the Guice Servlet Extensions.
Maven dependencies:
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>5.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>The extension provides the servlet. The extension itself does not have to be a webapplication.
import java.io.IOException;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Singleton
public class MyServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.getWriter().print("my-servlet");
}
}Dependency-injection can also be used here. See also here for more information.
With the ServletModule the servlets are configured.
import com.google.inject.servlet.ServletModule;
public class MyServletInjectionModule extends ServletModule {
@Override
protected void configureServlets() {
serve("/my").with(MyServlet.class);
}
}Now only the Injection module for the Factory has to be added.
Set MyServletInjectionModule to FactoryConfig
import com.sitepark.ies.extension.api.FactoryConfig;
import com.sitepark.ies.extension.api.Extension;
import com.sitepark.ies.extension.api.annotations.ConfigureFactory;
public class MyExtension implements Extension {
@ConfigureFactory
public static void configureInjection(FactoryConfig config) {
config.addInjectionModule(new MyServletInjectionModule());
}
}The servlet can then be accessed at the URL https://ies.domain.com/ies3/my.
To keep access to the ServletRequest and the ServletContext, they can be easily injected.
The IES provides a GraphQL endpoint. This is itself also implemented as an extension and can be extended via extensions.
Extensions can extend the schema and add resolvers for this endpoint. This functionality is provided by the extension
ies-graphql-extension and can be used by other extensions.
To learn how to extend the GraphQL schema please read here.
There is a GitHub project with examples.