Spring Boot / Spring Framework
Spring Framework
Das Spring Framework hat sich in den letzten Jahren bei der schnellen Entwicklung von Java Backend Anwendungen etabliert. Spring macht es den Entwicklern leicht, produktionsreife Anwendungen in kurzer Zeit zu erstellen. Das Spring Framework ergänzt dabei die bekannten JakartaEE Spezifikationen wie zum Beispiel Servlet API (JSR 340), WebSocket API (JSR 356), JSON Binding API (JSR 367) oder JPA (JSR 338).
Das Spring Framework basiert auf einem objektorientierten Entwurfsmuster, das als Dependency Injection bekannt geworden ist. Hierbei geht es darum, Objekte möglichst lose miteinander zu koppeln. Dies wird dadurch erreicht, dass ein Objekt andere Objekte, deren Hilfe es für seine Aufgabe benötigt, von außen "injiziert" bekommt, anstatt diese selbst zu erzeugen oder sich auf andere Art und Weise eigenverantwortlich zu beschaffen.
Spring Boot
Spring Boot hilft bei der Entwicklung von Spring basierten stand-alone Anwendungen, was sehr gut in die Welt von Microservices passt. Das jadice web toolkit und Spring Boot geben dabei einen Weg vor, der unserer Ansicht nach am besten funktioniert, um möglichst schnell und einfach eine Anwendung zu entwickeln. Dies wird unter anderem dadurch erzielt, dass es sinnvolle Defaults gibt und möglichst wenig Konfiguration erforderlich ist, um eine Anwendung zu entwickeln.
Integratoren, die das jadice web toolkit in eine Spring- oder Spring-Boot-Applikation integrieren möchten, können das ausgelieferte Integrationsmodul nutzen.
Spring Boot-Integrationsmodul
Das jadice web toolkit folgt dem Spring-Boot-Starter-Konzept, so, dass
das Aufsetzen einer Spring-Boot-Anwendung mit dem jadice web toolkit
sich sehr einfach gestaltet. Das webtoolkit-spring-boot-starter
als
Starter für das jadice web toolkit ist Bestandteil der Auslieferung und
kann als Maven-Dependency eingebunden werden. Er bringt die
erforderlichen Dependencies auf die einzubindenden jadice-web-toolkit-
und Spring-Boot-Module mit:
<dependency>
<groupId>com.levigo.jadice.webtoolkit</groupId>
<artifactId>webtoolkit-spring-boot-starter</artifactId>
</dependency>
Ein einführendes Tutorial, basierend auf Spring Boot, existiert unter Getting Started - jadice web toolkit mit Spring Boot.
Der Grundgedanke des webtoolkit-spring-boot-starter
liegt darin, die
Spring-Paradigmen für das jadice web toolkit zu unterstützen, so, dass
die erforderlichen Komponenten deklarativ injiziert bzw. konfiguriert
werden können. Dies umfasst DocumentDataProvider
, ServerOperations
,
ContextualFactories
sowie Annotationsprofile und Konfigurationswerte -
wie nachfolgend ausführlich beschrieben. Die programmatische
Registrierung dieser Komponenten, die früher typischerweise über einen
WebtoolkitServletContextListener
vorgenommen wurde, kann dadurch
vollständig entfallen.
Spring Boot Dependencies
Das jadice web toolkit erwartet, dass die Spring Boot Dependencies von der Integration bereitgestellt werden. Dadurch haben Sie die Kontrolle, über die konkret eingebundene Version. Wir empfehlen, die BOM (Bill of Materials) zu nutzen, um die Versionen und Abhängigkeiten zu setzen. Weitere Informationen hierzu finden Sie in unserer Knowledge Base.
Threadmanagement
Das Spring-Modul sorgt dafür, dass bei asynchron ausgeführten Operationen der zuständige Thread mit dem Spring-SecurityContext assoziiert wird. Dies passiert allerdings nur, sofern Spring Security im Klassenpfad gefunden wird. Andernfalls wird ein gewöhnlicher ThreadPoolExecutor aufgerufen.
Spring Boot Application
Eine jadice web toolkit-Spring-Boot-Anwendung wird durch Hinzufügen der
Annotationen @SpringBootApplication
und
@EnableJWTSpringBootApplication(...)
definiert:
-
@SpringBootApplication
: zur Aktivierung einer Spring Boot Application, entsprechend Using the @SpringBootApplication Annotation -
@EnableJWTSpringBootApplication(...)
: Diese Annotation bringt derwebtoolkit-spring-boot-starter
mit. Sie sorgt im Hintergrund für ein Autowiring von DocumentDataProvidern, ServerOperations und Annotationsprofilen.
@SpringBootApplication
// Activate jadice web toolkit support specifying the GWT module name for the entry point
@EnableJWTSpringBootApplication("com.levigo.jadice.web.demo.springboot.Application")
public class DemoApplication extends SpringBootServletInitializer {
public static void main(final String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
Automatische Registrierung von DocumentDataProvidern
DocumentDataProvider-Implementierungen lassen sich mittels Dependency
Injection automatisch registrieren. Eine programmatische Registrierung
an der DocumentDataProviderRegistry (siehe
DocumentDataProviderRegistry) ist dann
nicht mehr erforderlich. Hierzu ist die entsprechende Klasse lediglich
mit der Spring-Annotation @Component
zu versehen:
@Component
public class MyDocumentDataProvider implements DocumentDataProvider<MySource, MyPageSegmentHandle> {
...
}
Automatische Registrierung von ServerOperations
Auch ServerOperations lassen sich als @Component
injizieren. Die
manuelle Registrierung bei der ServerOperationRegistry im
ServletContextListener
lt. Server Operations
entfällt dann.
@Component
public class SampleServerOperation implements ServerOperation<SampleServerOperationParameters, SampleServerOperationMessage> {
...
}
Automatische Registrierung von ContextualFactories
Genauso können auch ContextualFactories als @Component
injiziert
werden, ohne dass diese programmatisch registriert werden müssen:
@Component
public class MyContextualServerOperationFactory implements ContextualFactory<ServerOperation<MyContextualServerOperationParameters, MyContextualServerOperationMessage>> {
@Override
public MyContextualServerOperation create(InvocationContext context) {
ServletInvocationContext servletInvocationContext = (ServletInvocationContext) context;
return new MyContextualServerOperation(servletInvocationContext.getSession().getId());
}
}
@Component
public class MyContextualDocumentDataProviderFactory implements ContextualFactory<DocumentDataProvider<ClassPathSource, ClassPathHandle>> {
@Override
public DocumentDataProvider<ClassPathSource, ClassPathHandle> create(InvocationContext context) {
return new ClassPathDocumentDataProvider();
}
}
Konfiguration serverseitiger Einstellungen
In einer Spring-Boot-Umgebung lassen sich Einstellungen des jadice web
toolkit, die für gewöhnlich programmatisch über die
ServerConfiguration vorgenommen werden, deklarativ über eine
application.yml
bzw. application.properties
konfigurieren.
Dabei werden die für das jadice web toolkit spezifischen Einstellungen
mit dem Prefix webtoolkit
angesprochen und die Werte über
entsprechende Selektoren konfiguriert. Die Namen der Selektoren
entsprechen dabei den Namen der Setter der ServerConfiguration.
Im folgenden Beispiel wird eine programmatische Konfiguration ihrem deklarativen Pendant gegenübergestellt:
ConfigurationManager.getServerConfiguration().getNetworkConfiguration().setSessionTimeout(Duration.ofSeconds(30));
ConfigurationManager.getServerConfiguration().getNetworkConfiguration().setResponseAggregationWindow(Duration.ofMillis(20));
ConfigurationManager.getServerConfiguration().setTileCompressionType(TileCompressionType.PNGJ_BEST_COMPRESSION);
ConfigurationManager.getServerConfiguration().getNetworkConfiguration().setKeepAliveInterval(Duration.ofSeconds(30));
Konfiguration per application.properties:
webtoolkit.tileCompressionType: PNGJ_BEST_COMPRESSION
webtoolkit.networkConfiguration.sessionTimeout: 30s
webtoolkit.networkConfiguration.responseAggregationWindow: 20ms
webtoolkit.networkConfiguration.keepAliveInterval: 30s
Konfiguration per application.yml:
webtoolkit:
tileCompressionType: PNGJ_BEST_COMPRESSION
networkConfiguration:
sessionTimeout: 30s
responseAggregationWindow: 20ms
keepAliveInterval: 30s
Deklaration von Annotationsprofilen
Neben den gerade erwähnten Konfigurationswerten lassen sich auch
Annotationsprofile über die Spring-Boot-Konfigurationsdateien
spezifizieren. Nachfolgendes Beispiel zeigt die Konfiguration zweier
Annotationsprofile in einer application.yml
.
#JWT prefix
webtoolkit:
# Specify annotation profiles
annotationProfiles: /jwt-minimal-profile.xml, /jwt-second-profile.xml
# Specify default annotation profile (The value must match annotation-profile name in jwt-minimal-profile.xml)
defaultAnnotationProfile: JWT-Minimal
WAR-Deployment (Traditional Deployment)
Spring Boot Anwendungen sind dafür vorgesehen, als "Runnable-JAR" erstellt zu werden, das heißt, nach dem Build
der Anwendung entsteht eine JAR-Datei, die direkt mit java -jar MySpringBootApp.jar
gestartet werden kann.
Spring Boot liefert hierfür einen eingebetteten Tomcat mit. Durch den Import eines anderen "Starter"-Moduls
können beispielsweise auch Wildfly oder weitere App-Server verwendet werden.
Es ist jedoch auch weiterhin möglich, die Anwendung als WAR-Datei erstellen zu lassen, um sie so auf einem App-Server zu deployen. Die dafür benötigten Anpassungen an den Dependencies finden Sie im Kapitel Artefakte.
Möglicherweise sind darüber hinaus noch Anpassungen am Code notwendig. Beim Traditional Deployment
wird der App-Server nicht von Spring Boot gestartet und verwaltet. Das hat zur Folge, dass manche Dinge
anders funktionieren als erwartet. Insbesondere das Verhalten von @ServletComponentScan
ist in diesem
Szenario anders. Da der App-Server die Javax-Annotationen wie @WebServlet
, @WebFilter
etc. erfasst
und die Klassen entsprechend registriert, kann Spring Boot hier nicht eingreifen und Felder die per
@Autowired
annotiert sind folglich nicht automatisch injecten. Wenn Sie also beispielsweise in Servlets Komponenten
per Dependency Injection (@Autowired
) injizieren möchten, funktioniert dies beim Traditional Deployment nicht.
Die folgenden Schritte sind nötig, um das Autowiring manuell durchzuführen:
@WebServlet
-Annotation im Servlet entfernen- An einer Klasse, welche vom
@ComponentScan
erfasst wird (also in einem entsprechendem Java-Package liegt), das folgende Feld injecten:@Autowired AutowireCapableBeanFactory beanFactory;
- Ein Snippet entsprechend dem Beispiel in dieser Klasse einfügen
@Bean
public ServletRegistrationBean<MyTestServlet> fileUploadServiceServletRegistrationBean(){
ServletRegistrationBean<MyTestServlet> servletRegistrationBean = new ServletRegistrationBean<>();
MyTestServlet servlet = new MyTestServlet();
beanFactory.autowireBean(servlet);
servletRegistrationBean.setServlet(servlet);
servletRegistrationBean.setUrlMappings(Collections.singletonList("/testEndpoint"));
servletRegistrationBean.setLoadOnStartup(1);
return servletRegistrationBean;
}
Eine weitere Besonderheit in diesem Szenario ist, dass die web.xml
-Datei nicht entfallen darf.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<display-name>MyApp</display-name>
</web-app>
Beim Traditional Deployment kann außerdem die Verwendung des spring-boot-maven-plugin
entfallen. Dieses Plugin
sorgt dafür, dass durch das Repacking zwei Ordner entstehen, WEB-INF/lib
und WEB-INF/lib-provided
. Beim
Deployment auf einem App-Server, werden die Libraries unter WEB-INF/lib-provided
ignoriert. Wird die Anwendung
jedoch über die Command-Line gestartet (java -jar
), werden die Libraries verwendet, da in diesem Fall kein App-Server
zur Verfügung steht. Wenn Sie sich für das Traditional Deployment entschieden haben, ist der Ordner WEB-INF/lib-provided
in jedem Fall überflüssig und kann somit entfallen, da die Dateigröße des WAR-Archivs nur unnötig ansteigt.
Weitere Informationen hierzu finden Sie in der offiziellen Dokumentation.
Nutzung des jadice web toolkit ohne Spring Framework
Das jadice web toolkit kann grundsätzlich auch ohne das Spring Framework und den damit verbundenen Mechanismen wie Dependency Injection genutzt werden. Dies wird jedoch ausdrücklich nicht empfohlen.
Hierfür empfiehlt es sich, den Weg zu wählen, der in der Vergangenheit vom jadice web toolkit
verwendet wurde: eine Konfiguration über den WebtoolkitServletContextListener
.
Da in einer Umgebung ohne Spring die benötigten Services nicht automatisch erstellt werden,
ist dies von Hand zu erledigen. Die Schritte hierfür sind nicht trivial:
- Erstellen eines
JWTServerContext
. Dieser enthält die Services, die vom jadice web toolkit benötigt werden. Der Context kann dann imServletContext
des Application Servers abgelegt werden, damit auf jadice Services, wie zum Beispiel dieServerOperationRegistry
, an anderen Stellen (Servlets etc.) zugegriffen werden kann. - Konfiguration der jadice document platform über
JadicePreferenceHolder
- Initialisierung der Caches über
CacheManager
- Initialisierung der Fonts über
FontEnvironments
- Initialisierung der Thread-Pools
- Initialisierung des
TransportManager
s - Registrierung der
MessageHandler
- Registrierung der Services für RPC
- Erweitern des
TileServlets
für URL-Mapping - Registrierung der
DocumentDataProvider
- Registrierung der
ServerOperation
s - Registrierung des Annotationsprofils
Beispiel
Das folgende Beispiel wurde aus der Showcase-Anwendung, welche Teil der Auslieferung ist, extrahiert.
WebtoolkitServletContextListener
@Override
protected void contextInitialized(ServletContextEvent sce, WebtoolkitServerContext context) {
// We do not use Spring here, so we have to wire that stuff by hand
JWTServerContext jwtServerContext = new JWTServerContext();
// calling getInstance() ensures that the JadicePreferenceStore is actually initialized instead
// of the default one
JadicePreferenceHolder.getInstance();
// after calling JadicePreferenceHolder.getInstance(), the jadice configuration preference store
// will be available.
final PreferenceStore ps = PreferenceStoreHolder.getPreferenceStoreByName(
JadicePreferenceHolder.JADICE_CONFIGURATION);
JadicePropertiesConfiguration.configure(ps);
CacheManager.setDefault(DefaultCacheProvider.getDefaultServerCache());
GitInfo.logCommitIdOnce();
FontEnvironments.initialize();
DocumentDataProviderRegistry documentDataProviderRegistry = new DocumentDataProviderRegistryImpl();
jwtServerContext.setDocumentDataProviderRegistry(documentDataProviderRegistry);
ServerConfiguration serverConfiguration = ConfigurationManager.getServerConfiguration();
final JWTThreadPoolExecutor threadPoolExecutor = new JWTThreadPoolExecutor(
serverConfiguration.getGeneralPoolCoreSize(), serverConfiguration.getGeneralPoolMaxSize(), 15);
jwtServerContext.setExecutorService(threadPoolExecutor);
AnnotationService annotationService = new AnnotationService();
jwtServerContext.setAnnotationService(annotationService);
TileRenderPriorityTaskExecutor tileRenderPriorityTaskExecutor = new TileRenderPriorityTaskExecutor();
TileRenderer tileRenderer = new TileRenderer(tileRenderPriorityTaskExecutor);
DocumentService documentService = new DocumentService(tileRenderer, threadPoolExecutor,
documentDataProviderRegistry, annotationService);
jwtServerContext.setDocumentService(documentService);
TileRenderService tileRenderService = new TileRenderService(documentService, tileRenderPriorityTaskExecutor, tileRenderer);
jwtServerContext.setTileRenderService(tileRenderService);
SynchronizeObjectDeserializer synchronizeObjectDeserializer = new SynchronizeObjectDeserializer(documentService);
TextService textService = new TextService(documentService, synchronizeObjectDeserializer);
jwtServerContext.setTextService(textService);
ServerOperationRegistry serverOperationRegistry = new ServerOperationRegistryImpl();
jwtServerContext.setServerOperationRegistry(serverOperationRegistry);
ServerOperationService serverOperationService = new ServerOperationService(synchronizeObjectDeserializer, serverOperationRegistry, threadPoolExecutor);
jwtServerContext.setServerOperationService(serverOperationService);
// Initialize the TransportManager
final TransportManager transportManager = TransportManagerProvider.getFromServletContext(sce.getServletContext());
final TransportManagerImpl transportManagerImpl = (TransportManagerImpl) transportManager;
transportManagerImpl.init(ConfigurationManager.getServerConfiguration().getNetworkConfiguration());
final ServiceCallRequestHandler serviceCallHandler = new ServiceCallRequestHandler(() -> threadPoolExecutor);
// register basic MessageHandler for Services
transportManagerImpl.getMessageHandlerManager().registerMessageHandler(ServiceCallRequest.class,
serviceCallHandler);
transportManagerImpl.getMessageHandlerManager().registerMessageHandler(CancelRequest.class,
new CancelHandler(serviceCallHandler));
transportManagerImpl.getMessageHandlerManager().registerMessageHandler(AuthenticationInfoUpdate.class,
new AuthenticationInfoUpdateHandler());
// register Services
serviceCallHandler.register("DocumentService", new DocumentServiceInvoker(documentService));
serviceCallHandler.register("AnnotationService", new AnnotationServiceInvoker(annotationService));
serviceCallHandler.register("TextService", new TextServiceInvoker(textService));
serviceCallHandler.register("ServerOperationService",
new ServerOperationServiceInvoker(serverOperationService));
serviceCallHandler.register("TileRenderService", new GenericInvoker(tileRenderService));
// Register DataProvider
documentDataProviderRegistry.registerProvider( //
ClassPathWithAnnoSource.class, //
ClassPathWithAnnoHandle.class, //
new ClassPathWithAnnoDocumentDataProvider() //
);
// Register Anno Profiles
serverOperationRegistry.register(SimpleServerOperationParameters.class, new SimpleServerOperation());
AnnotationProfile annotationProfile = AnnotationProfile.load(getClass().getResource("/annotationConfigurations/jwt-annotation-profile.xml"));
annotationService.registerProfile(annotationProfile);
// as we're dealing with a single profile only, it will be our default profile.
AnnotationProfile.setDefaultProfile(annotationProfile);
demoSystem = ShowcaseDemoSystem.create(sce.getServletContext(), jwtServerContext);
// Place JWTServerContext in ServletContext so it can be retrieved from Servlets, e.g. ShowcaseTileServlet
sce.getServletContext().setAttribute("JWT_SERVER_CONTEXT", jwtServerContext);
}
Anmerkung zu vorigen Methoden, einen DocumentDataProvider zu registrieren
In vorigen Versionen war es möglich, die DocumentDataProvider
im Verzeichnis META-INF/services
zu registrieren.
Diese Möglichkeit entfällt. Stattdessen wird empfohlen, über den Mechanismus, wie im folgenden Beispiel ShowcaseDemosSystem
aufgezeigt, zu gehen. Dort werden einige zueinander passende Trios Source, PageSegmentHandle und DocumentDataProvider registriert.
ShowcaseDemoSystem
/**
* <pre>
* Copyright (c), levigo holding gmbh.
*
* This file is subject to the terms and conditions defined in
* file 'LICENSE.txt', which is part of this source code package.
* </pre>
*/
package com.levigo.jadice.web.demo.showcase.server;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.Servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import com.levigo.jadice.annotation.profiles.AnnotationProfile;
import com.levigo.jadice.document.io.IOUtils;
import com.levigo.jadice.document.io.MemoryInputStream;
import com.levigo.jadice.document.io.SeekableInputStream;
import com.levigo.jadice.web.demo.common.server.DemoSystem;
import com.levigo.jadice.web.demo.common.server.dataprovider.ClassPathDocumentDataProvider;
import com.levigo.jadice.web.demo.common.server.dataprovider.ClassPathWithAnnoDocumentDataProvider;
import com.levigo.jadice.web.demo.common.server.dataprovider.ClassPathWithRenderControlsDocumentDataProvider;
import com.levigo.jadice.web.demo.common.server.dataprovider.SplitFileUploadDocumentDataProvider;
import com.levigo.jadice.web.demo.common.shared.service.sources.ClassPathHandle;
import com.levigo.jadice.web.demo.common.shared.service.sources.ClassPathSource;
import com.levigo.jadice.web.demo.common.shared.service.sources.ClassPathWithAnnoHandle;
import com.levigo.jadice.web.demo.common.shared.service.sources.ClassPathWithAnnoSource;
import com.levigo.jadice.web.demo.common.shared.service.sources.ClassPathWithRenderControlsHandle;
import com.levigo.jadice.web.demo.common.shared.service.sources.ClassPathWithRenderControlsSource;
import com.levigo.jadice.web.demo.showcase.shared.*;
import com.levigo.jadice.web.server.AnnotationProfileRegistry;
import com.levigo.jadice.web.server.DocumentDataProviderRegistry;
import com.levigo.jadice.web.server.WebtoolkitServerContext;
import com.levigo.jadice.web.server.annotation.AnnotationImageProvider;
import com.levigo.jadice.web.server.export.ExportRepository;
public class ShowcaseDemoSystem extends DemoSystem {
/**
* Retrieve the a {@link ShowcaseDemoSystem} instance associated with the given
* {@link ServletContext}. If no {@link ShowcaseDemoSystem} has been associated with the
* {@link ServletContext} this method will return {@code null}. If a {@link DemoSystem} instance
* other than a {@link ShowcaseDemoSystem} instance has been associated with the given
* {@link ServletContext}, an {@link IllegalStateException} will be thrown.
*
* @param context
* @return the ShowcaseDemoSystem
* @throws IllegalStateException if the {@link ServletContext} contains another type of
* {@link DemoSystem} or if no {@link DemoSystem} instance has been associated with the
* given {@link ServletContext}
* @throws IllegalArgumentException if context is null
*/
public static ShowcaseDemoSystem get(ServletContext context) {
if (context == null)
throw new IllegalArgumentException("context must not be null");
DemoSystem demoSystem = DemoSystem.get(context);
if (demoSystem instanceof ShowcaseDemoSystem)
return (ShowcaseDemoSystem) demoSystem;
throw new IllegalStateException(
"Incorrect type of " + DemoSystem.class.getSimpleName() + " has been started. Expected: "
+ ShowcaseDemoSystem.class.getName() + " received: " + demoSystem.getClass().getName());
}
/**
* Create a new {@link ShowcaseDemoSystem} instance and associate it with the given
* {@link ServletContext} . This method must be called within a
* {@link ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)} to ensure
* that the instance will be available before the {@link Servlet} implementations will be
* initialized.
*
* @param context
* @param webtoolkitServerContext
* @return a new {@link ShowcaseDemoSystem} instance associated with the given
* {@link ServletContext} and {@link WebtoolkitServerContext}
*/
public static ShowcaseDemoSystem create(ServletContext context, WebtoolkitServerContext webtoolkitServerContext) {
if (context == null)
throw new IllegalArgumentException("context must not be null");
ShowcaseDemoSystem system = new ShowcaseDemoSystem(webtoolkitServerContext, context);
DemoSystem.attach(context, system);
return system;
}
public ShowcaseDemoSystem(WebtoolkitServerContext webtoolkitServerContext, ServletContext servletContext) {
registerDocumentDataProvider(webtoolkitServerContext.getDocumentDataProviderRegistry());
registerServerOperation(webtoolkitServerContext.getServerOperationRegistry(), servletContext);
registerAnnotationProfiles(webtoolkitServerContext.getAnnotationProfileRegistry());
registerPrintingServerOperation(webtoolkitServerContext, servletContext);
}
private void registerPrintingServerOperation(WebtoolkitServerContext jwtServerContext,
ServletContext servletContext) {
// register stream printing server operation
jwtServerContext.getServerOperationRegistry().register(ExportParameters.class,
new ExportServerOperation(ExportRepository.get(servletContext)));
}
private void registerServerOperation(ServerOperationRegistry serverOperationRegistry, ServletContext servletContext) {
// register the ServerOperation instance using the corresponding parameters class as key
// the parameters class will be used to find the registered instance when invoking
serverOperationRegistry.register(SimpleServerOperationParameters.class, new SimpleServerOperation());
// register a ContextualFactory that creates the ServerOperation and injects the current
// HttpSession
serverOperationRegistry.register(HttpSessionServerOperationParameters.class,
new HttpSessionServerOperationFactory());
// register further ServerOperation instances
serverOperationRegistry.register(ConfirmedServerOperationParameters.class, new ConfirmedServerOperation());
serverOperationRegistry.register(PropertySerializationServerOperationParameters.class,
new PropertySerializationServerOperation());
serverOperationRegistry.register(ProgressiveServerOperationParameters.class, new ProgressiveServerOperation());
serverOperationRegistry.register(ComplexServerOperationParameters.class, new ComplexServerOperation());
serverOperationRegistry.register(BookmarkPersistencyServerOperationParameters.class,
new BookmarkPersistencyServerOperation());
serverOperationRegistry.register(DecorationPrintingServerOperationParameters.class,
new DecorationPrintingServerOperation(ExportRepository.get(servletContext)));
serverOperationRegistry.register(FilteredPrintingServerOperationParameters.class,
new FilteredPrintingServerOperation(ExportRepository.get(servletContext)));
}
protected void registerDocumentDataProvider(DocumentDataProviderRegistry documentDataProviderRegistry) {
documentDataProviderRegistry.registerProvider( //
ClassPathWithAnnoSource.class, //
ClassPathWithAnnoHandle.class, //
new ClassPathWithAnnoDocumentDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
FilteredClassPathWithAnnoSource.class, //
FilteredClassPathWithAnnoHandle.class, //
new FilteredClassPathWithAnnoDocumentDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
ClassPathWithRenderControlsSource.class, //
ClassPathWithRenderControlsHandle.class, //
new ClassPathWithRenderControlsDocumentDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
SplitFileUploadSource.class, //
SplitFileUploadHandle.class, //
new SplitFileUploadDocumentDataProvider(getFileUploadservice()) //
);
documentDataProviderRegistry.registerProvider( //
DocumentWithPermissionSource.class, //
DocumentWithPermissionHandle.class, //
new DocumentWithPermissionsDataProvider() //
);
// register the simple data provider that reads a specific file from disk
documentDataProviderRegistry.registerProvider( //
MyDataProviderSource.class, //
MyDataProviderHandle.class, //
new MyDataProvider() //
);
documentDataProviderRegistry.registerProvider(//
HocrDataProviderSource.class, //
HocrDataProviderHandle.class, //
new DataProviderWithHocr() //
);
documentDataProviderRegistry.registerProvider(//
AuthenticationSource.class, //
AuthenticationHandle.class, //
new DataProviderFactoryWithAuthentication() //
);
documentDataProviderRegistry.registerProvider( //
LazyClassPathSource.class, //
LazyClassPathHandle.class, //
new LazyClassPathDocumentDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
CompositePageSource.class, //
CompositePageHandle.class, //
new CompositePageDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
ClassPathWithBookmarksSource.class, //
ClassPathWithBookmarksHandle.class, //
new ClassPathWithBookmarksDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
FontSubstitutionSource.class, //
FontSubstitutionHandle.class, //
new FontSubstitutionDocumentDataProvider() //
);
documentDataProviderRegistry.registerProvider( //
ClassPathSource.class, //
ClassPathHandle.class, //
new ClassPathDocumentDataProvider() //
);
// create example file if not existing (save resource at server location)
try {
new File(MyDataProvider.BASEPATH).mkdirs();
File file = new File(MyDataProvider.BASEPATH + "testimage_full.jpg");
file.deleteOnExit();
IOUtils.copyAndClose(getClass().getClassLoader().getResourceAsStream("example-docs/testimage_full.jpg"),
new FileOutputStream(file));
} catch (Exception e) {
throw new RuntimeException("Failed to initialize showcase system", e);
}
}
protected void registerAnnotationProfiles(AnnotationProfileRegistry annotationProfileRegistry) {
// we would like to use annotations. In this case we have to load and register the desired
// annotation profile.
AnnotationProfile annotationProfile = registerProfile(annotationProfileRegistry,
"/annotationConfigurations/jwt-annotation-profile.xml");
// as we're dealing with a single profile only, it will be our default profile.
AnnotationProfile.setDefaultProfile(annotationProfile);
// in order to provide different images according to the defined image ids at the client side,
// we register an AnnotationImageProvider for the registered profile
annotationProfileRegistry.registerAnnotationImageProvider(annotationProfile.getName(),
new AnnotationImageProvider() {
@Override
public SeekableInputStream provideAnnotationImage(String annotationImageID) throws IOException {
InputStream is = null;
if (annotationImageID.equals("signatureAnnoImage"))
is = Thread.currentThread().getContextClassLoader().getResourceAsStream("signature_kl_opaque_dotted.png");
else if (annotationImageID.equals("qrJWTAnnoImage"))
is = Thread.currentThread().getContextClassLoader().getResourceAsStream("qr_jwt.png");
else if (annotationImageID.equals("qrJadiceAnnoImage"))
is = Thread.currentThread().getContextClassLoader().getResourceAsStream("qr_jadice.png");
if (null == is)
throw new IOException("Couldn't find/load image for id "" + annotationImageID + """);
return new MemoryInputStream(is);
}
});
registerProfile(annotationProfileRegistry, "/annotationConfigurations/cm7_profile.xml");
registerProfile(annotationProfileRegistry, "/annotationConfigurations/cm8_profile.xml");
registerProfile(annotationProfileRegistry, "/annotationConfigurations/filenet-p8_profile.xml");
registerProfile(annotationProfileRegistry, "/annotationConfigurations/filenetIS_profile.xml");
}
protected AnnotationProfile registerProfile(AnnotationProfileRegistry annotationProfileRegistry, String path) {
AnnotationProfile annotationProfile = AnnotationProfile.load(getClass().getResource(path));
if (annotationProfile == null)
throw new IllegalStateException("Required AnnotationProfile could not be loaded.");
annotationProfileRegistry.registerProfile(annotationProfile);
return annotationProfile;
}
@Override
protected void doShutdown() {
}
}
In einer Integration ohne Spring Boot und das dazugehörende DependencyInjection kann der JWTServerContext
über
den folgenden Mechanismus zur Verfügung gestellt werden.
MyTileServlet
@WebServlet(
asyncSupported = true,
description = "Servlet handling tile requests",
displayName = "jadice web toolkit tile download",
name = "jwtTileDownloadServlet",
urlPatterns = {
"/jwt/tile/*"
})
public class MyTileServlet extends TileServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
if (null == tileRenderService) {
final JWTServerContext jwtServerContext = (JWTServerContext) getFromServletContext(
config.getServletContext());
if (null == jwtServerContext)
throw new UnavailableException("No JWTServerContext found in context");
tileRenderService = jwtServerContext.getTileRenderService();
}
}
public WebtoolkitServerContext getFromServletContext(ServletContext servletContext) {
JWTServerContext serverContext = (JWTServerContext) servletContext.getAttribute("JWT_SERVER_CONTEXT");
if (serverContext == null) {
throw new NullPointerException("JWTServerContext was not placed in ServletContext");
}
return serverContext;
}
}