Skip to content

GH-1502 Create experimental Spring Boot standalone executable for server #5263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tools/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<module>workbench</module>
<module>runtime</module>
<module>runtime-osgi</module>
<module>server-jar</module>
</modules>
<profiles>
<profile>
Expand Down
100 changes: 100 additions & 0 deletions tools/server-jar/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.rdf4j</groupId>
<artifactId>rdf4j-tools</artifactId>
<version>5.1.3-SNAPSHOT</version>
</parent>
<artifactId>rdf4j-http-server-jar</artifactId>
<name>RDF4J: HTTP server - self-contained executable</name>
<description>A self-contained executable of the RDF4J Server</description>
<properties>
<spring.boot.version>2.7.18</spring.boot.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rdf4j-http-server-spring</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>rdf4j-config</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.rdf4j</groupId>
<artifactId>rdf4j-tools-federation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
<configuration>
<mainClass>org.eclipse.rdf4j.server.Application</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.eclipse.rdf4j.server;

import org.eclipse.rdf4j.common.annotation.Experimental;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.PropertySource;

@Experimental
@SpringBootApplication
@PropertySource(
value = "classpath:org/eclipse/rdf4j/http/server/application.properties", ignoreResourceNotFound = true, name = "org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
)
public class Application {
public static void main(final String[] args) {
SpringApplication.run(Application.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.eclipse.rdf4j.server;

import java.util.List;

import org.eclipse.rdf4j.http.server.ProtocolExceptionResolver;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class MvcConfiguration implements WebMvcConfigurer {
@Override
public void configureHandlerExceptionResolvers(@NonNull final List<HandlerExceptionResolver> resolvers) {
resolvers.add(new ProtocolExceptionResolver());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.eclipse.rdf4j.server;

import org.eclipse.rdf4j.http.server.protocol.ProtocolController;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;

@Configuration
public class ProtocolControllers {
@NonNull
@Bean(name = "rdf4jProtocolController")
public ProtocolController rdf4jProtocolController() {
return new ProtocolController();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package org.eclipse.rdf4j.server;

import org.eclipse.rdf4j.http.server.repository.RepositoryController;
import org.eclipse.rdf4j.http.server.repository.RepositoryInterceptor;
import org.eclipse.rdf4j.http.server.repository.RepositoryListController;
import org.eclipse.rdf4j.http.server.repository.config.ConfigController;
import org.eclipse.rdf4j.http.server.repository.contexts.ContextsController;
import org.eclipse.rdf4j.http.server.repository.graph.GraphController;
import org.eclipse.rdf4j.http.server.repository.namespaces.NamespaceController;
import org.eclipse.rdf4j.http.server.repository.namespaces.NamespacesController;
import org.eclipse.rdf4j.http.server.repository.size.SizeController;
import org.eclipse.rdf4j.http.server.repository.statements.StatementsController;
import org.eclipse.rdf4j.http.server.repository.transaction.TransactionController;
import org.eclipse.rdf4j.http.server.repository.transaction.TransactionStartController;
import org.eclipse.rdf4j.repository.manager.RepositoryManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.web.context.annotation.RequestScope;

@Configuration
public class RepositoryControllers {

@NonNull
@Autowired
@Bean(name = "rdf4jRepositoryInterceptor")
@RequestScope
public RepositoryInterceptor rdf4jRepositoryInterceptor(
@NonNull @Qualifier("rdf4jRepositoryManager") final RepositoryManager repositoryManager) {
final RepositoryInterceptor interceptor = new RepositoryInterceptor();
interceptor.setRepositoryManager(repositoryManager);

return interceptor;
}

@NonNull
@Autowired
@Bean(name = "rdf4jRepositoryController")
public RepositoryController repositoryController(
@NonNull @Qualifier("rdf4jRepositoryManager") final RepositoryManager repositoryManager) {
final RepositoryController controller = new RepositoryController();
controller.setRepositoryManager(repositoryManager);

return controller;
}

@NonNull
@Autowired
@Bean(name = "rdf4jRepositoryListController")
public RepositoryListController repositoryListController(
@NonNull @Qualifier("rdf4jRepositoryManager") final RepositoryManager repositoryManager) {
final RepositoryListController controller = new RepositoryListController();
controller.setRepositoryManager(repositoryManager);

return controller;
}

@NonNull
@Autowired
@Bean(name = "rdf4jRepositoryConfigController")
public ConfigController rdf4jRepositoryConfigController(
@NonNull @Qualifier("rdf4jRepositoryManager") final RepositoryManager repositoryManager) {
final ConfigController controller = new ConfigController();
controller.setRepositoryManager(repositoryManager);

return controller;
}

@NonNull
@Bean(name = "rdf4jRepositoryContextsController")
public ContextsController rdf4jRepositoryContextsController() {
return new ContextsController();
}

@NonNull
@Bean(name = "rdf4jRepositoryNamespacesController")
public NamespacesController rdf4jRepositoryNamespacesController() {
return new NamespacesController();
}

@NonNull
@Bean(name = "rdf4jRepositoryNamespaceController")
public NamespaceController rdf4jRepositoryNamespaceController() {
return new NamespaceController();
}

@NonNull
@Bean(name = "rdf4jRepositorySizeController")
public SizeController rdf4jRepositorySizeController() {
return new SizeController();
}

@NonNull
@Bean(name = "rdf4jRepositoryStatementsController")
public StatementsController rdf4jRepositoryStatementsController() {
return new StatementsController();
}

@NonNull
@Bean(name = "rdf4jRepositoryGraphController")
public GraphController rdf4jRepositoryGraphController() {
return new GraphController();
}

@NonNull
@Bean(name = "rdf4jRepositoryTransactionController")
public TransactionController rdf4jRepositoryTransactionController() {
return new TransactionController();
}

@NonNull
@Bean(name = "rdf4jRepositoryTransactionStartController")
public TransactionStartController rdf4jRepositoryTransactionStartController(
@Nullable @Value("${rdf4j.externalurl:#{null}}") final String externalUrl
) {
final TransactionStartController transactionStartController = new TransactionStartController();
transactionStartController.setExternalUrl(externalUrl);

return transactionStartController;
}

}
106 changes: 106 additions & 0 deletions tools/server-jar/src/main/java/org/eclipse/rdf4j/server/Routes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.eclipse.rdf4j.server;

import static org.eclipse.rdf4j.http.server.repository.RepositoryInterceptor.REPOSITORY_KEY;

import java.util.LinkedHashMap;
import java.util.Map;

import org.eclipse.rdf4j.http.server.protocol.ProtocolController;
import org.eclipse.rdf4j.http.server.protocol.ProtocolInterceptor;
import org.eclipse.rdf4j.http.server.repository.RepositoryController;
import org.eclipse.rdf4j.http.server.repository.RepositoryInterceptor;
import org.eclipse.rdf4j.http.server.repository.RepositoryListController;
import org.eclipse.rdf4j.http.server.repository.config.ConfigController;
import org.eclipse.rdf4j.http.server.repository.contexts.ContextsController;
import org.eclipse.rdf4j.http.server.repository.graph.GraphController;
import org.eclipse.rdf4j.http.server.repository.namespaces.NamespaceController;
import org.eclipse.rdf4j.http.server.repository.namespaces.NamespacesController;
import org.eclipse.rdf4j.http.server.repository.size.SizeController;
import org.eclipse.rdf4j.http.server.repository.statements.StatementsController;
import org.eclipse.rdf4j.http.server.repository.transaction.TransactionController;
import org.eclipse.rdf4j.http.server.repository.transaction.TransactionStartController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;

@Configuration
public class Routes {
@NonNull
@Autowired
@Bean(name = "rdf4jProtocolUrlMapping")
public HandlerMapping rdf4jProtocolUrlMapping(
@NonNull @Qualifier("rdf4jProtocolController") final ProtocolController protocolController) {
final Map<String, Object> urlMap = new LinkedHashMap<>(1);

urlMap.put("/protocol", protocolController);

final SimpleUrlHandlerMapping mappings = new SimpleUrlHandlerMapping();
mappings.setUrlMap(urlMap);
mappings.setOrder(0);
mappings.setAlwaysUseFullPath(true);
mappings.setInterceptors(new ProtocolInterceptor());

return mappings;
}

@NonNull
@Autowired
@Bean(name = "rdf4jRepositoryListUrlMapping")
public HandlerMapping rdf4jRepositoryListUrlMapping(
@NonNull @Qualifier("rdf4jRepositoryListController") final RepositoryListController repositoryListController) {
final Map<String, Object> urlMap = new LinkedHashMap<>(1);

urlMap.put("/repositories", repositoryListController);

final SimpleUrlHandlerMapping mappings = new SimpleUrlHandlerMapping();
mappings.setUrlMap(urlMap);
mappings.setOrder(1);
mappings.setAlwaysUseFullPath(true);

return mappings;
}

@NonNull
@Autowired
@Bean(name = "rdf4jRepositoryUrlMapping")
public HandlerMapping rdf4jRepositoryUrlMapping(
@NonNull @Qualifier("rdf4jRepositoryController") final RepositoryController repositoryController,
@NonNull @Qualifier("rdf4jRepositoryConfigController") final ConfigController repositoryConfigController,
@NonNull @Qualifier("rdf4jRepositoryContextsController") final ContextsController contextsController,
@NonNull @Qualifier("rdf4jRepositoryNamespacesController") final NamespacesController namespacesController,
@NonNull @Qualifier("rdf4jRepositoryNamespaceController") final NamespaceController namespaceController,
@NonNull @Qualifier("rdf4jRepositorySizeController") final SizeController sizeController,
@NonNull @Qualifier("rdf4jRepositoryStatementsController") final StatementsController statementsController,
@NonNull @Qualifier("rdf4jRepositoryGraphController") final GraphController graphController,
@NonNull @Qualifier("rdf4jRepositoryTransactionController") final TransactionController transactionController,
@NonNull @Qualifier("rdf4jRepositoryTransactionStartController") final TransactionStartController transactionStartController,
@NonNull @Qualifier("rdf4jRepositoryInterceptor") final RepositoryInterceptor repositoryInterceptor
) {
final Map<String, Object> urlMap = new LinkedHashMap<>(11);

final String repositoryPrefix = "/repositories/{" + REPOSITORY_KEY + "}";
urlMap.put(repositoryPrefix + "/namespaces/{nsPrefix}", namespaceController);
urlMap.put(repositoryPrefix + "/namespaces", namespacesController);
urlMap.put(repositoryPrefix + "/config", repositoryConfigController);
urlMap.put(repositoryPrefix + "/contexts", contextsController);
urlMap.put(repositoryPrefix + "/statements", statementsController);
urlMap.put(repositoryPrefix + "/rdf-graphs", contextsController);
urlMap.put(repositoryPrefix + "/rdf-graphs/{graph}", graphController);
urlMap.put(repositoryPrefix + "/size", sizeController);
urlMap.put(repositoryPrefix + "/transactions", transactionStartController);
urlMap.put(repositoryPrefix + "/transactions/{xid}", transactionController);
urlMap.put(repositoryPrefix, repositoryController);

final SimpleUrlHandlerMapping mappings = new SimpleUrlHandlerMapping();
mappings.setUrlMap(urlMap);
mappings.setOrder(2);
mappings.setAlwaysUseFullPath(true);
mappings.setInterceptors(repositoryInterceptor);

return mappings;
}
}
Loading
Loading