Compare commits

...

6 Commits

@ -0,0 +1,20 @@
meta {
name: findSession
type: http
seq: 4
}
get {
url: http://localhost:8761/services/api/session/a3518555-5a96-42a6-a5ec-958c4963a65e
body: none
auth: basic
}
headers {
operationName: findUsers
}
auth:basic {
username: cxfrs
password: password
}

@ -1,11 +1,11 @@
meta {
name: findUsers
name: findSessions
type: http
seq: 2
}
get {
url: http://localhost:9090/services/api/user
url: http://localhost:8761/services/api/session
body: none
auth: basic
}

@ -0,0 +1,20 @@
meta {
name: login
type: http
seq: 5
}
post {
url: http://localhost:8761/services/api/login/a3518555-5a96-42a6-a5ec-958c4963a65e
body: none
auth: basic
}
headers {
operationName: findUsers
}
auth:basic {
username: cxfrs
password: password
}

@ -0,0 +1,33 @@
meta {
name: updateSession
type: http
seq: 3
}
post {
url: http://localhost:8761/services/api/session
body: json
auth: basic
}
headers {
Content-Type: application/json
X-MethodName: updateUser
}
auth:basic {
username: cxfrs
password: password
}
body:json {
{
"sessionId": "{{uuid}}",
"username": "admin1",
"password": "password1"
}
}
script:pre-request {
bru.setVar('uuid', require("uuid").v4());
}

@ -1,28 +0,0 @@
meta {
name: updateUser
type: http
seq: 3
}
post {
url: http://localhost:9090/services/api/user
body: json
auth: basic
}
headers {
Content-Type: application/json
X-MethodName: updateUser
}
auth:basic {
username: cxfrs
password: password
}
body:json {
{
"id": 3,
"name": "Bruce Wayne"
}
}

@ -19,9 +19,7 @@
<pattern>%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.security.ldap.userdetails" level="TRACE" />
<logger name="org.springframework.security" level="DEBUG" />
<logger name="com.example.camel" level="DEBUG" />
<logger name="com.example.sbcamel" level="DEBUG" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>

@ -1,11 +1,13 @@
server:
port: 9090
port: 8761
camel:
springboot:
main-run-controller: true
spring:
application:
name: eureka-server
activemq:
broker-url: "tcp://localhost:61616"
ldap:
@ -15,5 +17,16 @@ spring:
password: secret
app:
queue-name: "UserServiceQueue"
queue-name: "SessionServiceQueue"
database:
url: "jdbc:h2:tcp://localhost/~/h2/db/appdb"
username: "app"
password: "app"
mapper-package: "com.example.sbcamel.mapper"
eureka:
client:
service-url:
defaultZone: http://cxfrs:password@localhost:8761/eureka/,http://cxfrs:password@localhost:8762/eureka/
register-with-eureka: false
fetch-registry: false

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true">
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/server.log</file>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/server.%d{yyyy-MM-dd}.log.gz</fileNamePattern>
<maxHistory>3</maxHistory>
<totalSizeCap>300MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%-5level %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="com.example.sbcamel" level="DEBUG" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

@ -0,0 +1,32 @@
server:
port: 8762
camel:
springboot:
main-run-controller: true
spring:
application:
name: eureka-server
activemq:
broker-url: "tcp://localhost:61616"
ldap:
urls: ldap://localhost:10389
base: dc=example,dc=com
username: uid=admin,ou=system
password: secret
app:
queue-name: "SessionServiceQueue"
database:
url: "jdbc:h2:tcp://localhost/~/h2/db/appdb"
username: "app"
password: "app"
mapper-package: "com.example.sbcamel.mapper"
eureka:
client:
service-url:
defaultZone: http://cxfrs:password@localhost:8761/eureka/,http://cxfrs:password@localhost:8762/eureka/
register-with-eureka: false
fetch-registry: false

Binary file not shown.

@ -0,0 +1,105 @@
2025-03-08 12:36:27.115360+08:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "MERGE INTO [*]USER (?) VALUES (?, ?)"; expected "identifier"; SQL statement:
MERGE INTO USER (?) VALUES (?, ?) [42001-224]
2025-03-08 12:41:38.334685+08:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "CREATE TABLE IF NOT EXISTS public.[*]user (id BIGINT not null, name CHARACTER VARYING not null, PRIMARY KEY (id))"; expected "identifier"; SQL statement:
CREATE TABLE IF NOT EXISTS public.user (id BIGINT not null, name CHARACTER VARYING not null, PRIMARY KEY (id)) [42001-224]
2025-03-08 12:45:24.184967+08:00 jdbc[3]: exception
org.h2.jdbc.JdbcSQLSyntaxErrorException: Syntax error in SQL statement "MERGE INTO public.""user"" ([*]?) VALUES (?, ?)"; expected "identifier"; SQL statement:
MERGE INTO public."user" (?) VALUES (?, ?) [42001-224]
2025-03-08 15:26:55.471296+08:00 database: flush
org.h2.message.DbException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/Yan/eclipse-workspace/camel-springboot-activemq6-example/db/appdb.mv.db [2.2.224/7]" [50000-224]
at org.h2.message.DbException.get(DbException.java:212)
at org.h2.message.DbException.convert(DbException.java:407)
at org.h2.mvstore.db.Store.lambda$new$0(Store.java:122)
at org.h2.mvstore.MVStore.handleException(MVStore.java:1546)
at org.h2.mvstore.MVStore.panic(MVStore.java:371)
at org.h2.mvstore.MVStore.<init>(MVStore.java:291)
at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2035)
at org.h2.mvstore.db.Store.<init>(Store.java:133)
at org.h2.engine.Database.<init>(Database.java:326)
at org.h2.engine.Engine.openSession(Engine.java:92)
at org.h2.engine.Engine.openSession(Engine.java:222)
at org.h2.engine.Engine.createSession(Engine.java:201)
at org.h2.engine.SessionRemote.connectEmbeddedOrServer(SessionRemote.java:343)
at org.h2.jdbc.JdbcConnection.<init>(JdbcConnection.java:125)
at org.h2.Driver.connect(Driver.java:59)
at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:137)
at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:360)
at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:202)
at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:461)
at com.zaxxer.hikari.pool.HikariPool.checkFailFast(HikariPool.java:550)
at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:98)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:80)
at com.example.sbcamel.DatabaseConfig.dataSource(DatabaseConfig.java:69)
at com.example.sbcamel.DatabaseConfig$$SpringCGLIB$$0.CGLIB$dataSource$0(<generated>)
at com.example.sbcamel.DatabaseConfig$$SpringCGLIB$$FastClass$$1.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:258)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:372)
at com.example.sbcamel.DatabaseConfig$$SpringCGLIB$$0.dataSource(<generated>)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:146)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:644)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:636)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1448)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1358)
at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:904)
at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:782)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:542)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1355)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1448)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1358)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:785)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:768)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:509)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1439)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:335)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352)
at com.example.sbcamel.Boot.main(Boot.java:27)
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: General error: "org.h2.mvstore.MVStoreException: The file is locked: C:/Users/Yan/eclipse-workspace/camel-springboot-activemq6-example/db/appdb.mv.db [2.2.224/7]" [50000-224]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:566)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:489)
... 83 more
Caused by: org.h2.mvstore.MVStoreException: The file is locked: C:/Users/Yan/eclipse-workspace/camel-springboot-activemq6-example/db/appdb.mv.db [2.2.224/7]
at org.h2.mvstore.DataUtils.newMVStoreException(DataUtils.java:996)
at org.h2.mvstore.SingleFileStore.lockFileChannel(SingleFileStore.java:143)
at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:117)
at org.h2.mvstore.SingleFileStore.open(SingleFileStore.java:81)
at org.h2.mvstore.MVStore.<init>(MVStore.java:286)
... 77 more

@ -4,19 +4,21 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>camel-springboot-activemq6-example</artifactId>
<version>2.0.1</version>
<version>3.0.1</version>
<name>camel-springboot-activemq6-example</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.8</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<camel.version>4.8.3</camel.version>
<springboot.version>${project.parent.version}</springboot.version>
<camel.version>4.8.4</camel.version>
<spring-boot-dependencies.version>3.4.4</spring-boot-dependencies.version>
<spring-cloud-dependencies.version>2024.0.1</spring-cloud-dependencies.version>
<mybatis.version>3.5.19</mybatis.version>
<mybatis-spring.version>3.0.4</mybatis-spring.version>
<htmlunit.version>4.11.1</htmlunit.version>
<guava.version>33.1.0-jre</guava.version>
<maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
</properties>
<dependencyManagement>
@ -31,7 +33,14 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<version>${spring-boot-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud-dependencies.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -56,6 +65,14 @@
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-ldap</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel.springboot</groupId>
@ -81,16 +98,55 @@
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-jackson-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel.springboot</groupId>
<artifactId>camel-mybatis-starter</artifactId>
</dependency>
<!-- Other -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>org.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis-spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jakarta.rs</groupId>
<artifactId>jackson-jakarta-rs-json-provider</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
@ -99,8 +155,9 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot-dependencies.version}</version>
<configuration>
<mainClass>com.example.camel.Boot</mainClass>
<mainClass>com.example.sbcamel.Boot</mainClass>
</configuration>
<executions>
<execution>

@ -1,13 +1,19 @@
**Please start the following services before testing**
## Setup
1. ApacheDS Server 2.0.0.AM27
1. Please start the following services before testing :
2. Apache ActiveMQ 6.1.5
```
ApacheDS Server 2.0.0.AM27
Apache ActiveMQ 6.1.5
H2 Database Version 2.3.232
```
2. Please see conf/springboot.yml for LDAP/ActiveMQ Address
3. For LDAP group and user setup, see misc/ldapdb.ldif
**Startup screens**
## Startup screens
1. ApacheDS Server 2.0.0.AM27
**1. ApacheDS Server 2.0.0.AM27**
```
C:\Users\XXX\apacheds-2.0.0.AM28-SNAPSHOT\bin>apacheds.bat default start
@ -41,7 +47,7 @@ Starting ApacheDS instance 'default'...
```
2. Apache ActiveMQ 6.1.5
**2. Apache ActiveMQ 6.1.5**
```
C:\Users\XXX\apache-activemq-6.1.5\bin>activemq start
@ -89,10 +95,16 @@ Loading message broker from: xbean:activemq.xml
INFO | ActiveMQ Jolokia REST API available at http://127.0.0.1:8161/api/jolokia/
```
**Setup**
**3. H2 Database Version 2.3.232**
* Please see conf/springboot.yml for LDAP/ActiveMQ Address
```
C:\Users\XXX\Desktop>SET JAVA_HOME=C:\Users\XXX\graalvm-jdk-17.0.14+8.1
* For LDAP group and user setup, see misc/ldapdb.ldif
C:\Users\XXX\Desktop>SET PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\NVIDIA Corporation\NVIDIA NvDLISR;C:\Program Files\PuTTY\;C:\Users\XXX\AppData\Local\Microsoft\WindowsApps;C:\Users\XXX\graalvm-jdk-17.0.14+8.1\bin;;C:\Users\XXX\graalvm-jdk-17.0.14+8.1\bin
C:\Users\XXX\Desktop>cd C:\Users\XXX\h2\bin
C:\Users\XXX\h2\bin>h2.bat -tcp -web
Web Console server running at http://127.0.0.1:8082?key=8c2f1bfb9fb08604f1e3a7849e8b338514438c2c729b87ecc98108b6102818c6 (only local connections)
TCP server running at tcp://127.0.0.1:9092 (only local connections)
```

@ -1,34 +0,0 @@
package com.example.camel;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.bean.validator.BeanValidationException;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import jakarta.ws.rs.core.Response;
@Component
public class CamelRouter extends RouteBuilder {
@Value("${app.queue-name}")
private String queueName;
@Override
public void configure() throws Exception {
// very raw way, just to handle the validation responses
onException(BeanValidationException.class).handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.BAD_REQUEST.getStatusCode()))
.setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}"));
from("cxfrs:/api?resourceClasses=" + UserService.class.getName() + "&bindingStyle=SimpleConsumer"
+ "&providers=jaxrsProvider&loggingFeatureEnabled=true").to("log:cxfrs-log?showAll=true")
.setHeader(Exchange.BEAN_METHOD_NAME, simple("${header.operationName}"))
.to("activemq6:queue:" + queueName);
from("activemq6:queue:" + queueName).to("bean-validator:user").bean(UserServiceImpl.class).marshal()
.json(JsonLibrary.Jackson);
}
}

@ -1,54 +0,0 @@
package com.example.camel;
import java.io.Serializable;
import java.util.StringJoiner;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
/**
* User entity
*
*/
@SuppressWarnings("serial")
public class User implements Serializable {
@NotNull(message = "custom message")
private Integer id;
@NotNull
@Size(min = 3, max = 20)
private String name;
public User() {
}
public User(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return new StringJoiner(", ", User.class.getSimpleName() + "[", "]")
.add("id=" + id)
.add("name='" + name + "'")
.toString();
}
}

@ -1,52 +0,0 @@
package com.example.camel;
import java.util.Collection;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* Service interface for managing users.
*/
public interface UserService {
/**
* Find a user by the given ID
*
* @param id
* the ID of the user
* @return the user, or <code>null</code> if user not found.
*/
@GET
@Path("/user/{id}")
@Produces(MediaType.APPLICATION_JSON)
User findUser(@PathParam("id") Integer id);
/**
* Find all users
*
* @return a collection of all users
*/
@GET
@Path("/user")
@Produces(MediaType.APPLICATION_JSON)
Collection<User> findUsers();
/**
* Update the given user
*
* @param user
* the user
*/
@POST
@Path("/user")
@Consumes(MediaType.APPLICATION_JSON)
User updateUser(@Valid User user);
}

@ -1,33 +0,0 @@
package com.example.camel;
import java.util.Collection;
import java.util.Map;
import java.util.TreeMap;
public class UserServiceImpl implements UserService {
private final Map<Integer, User> users = new TreeMap<>();
public UserServiceImpl() {
users.put(1, new User(1, "John Coltrane"));
users.put(2, new User(2, "Miles Davis"));
users.put(3, new User(3, "Sonny Rollins"));
}
@Override
public User findUser(Integer id) {
return users.get(id);
}
@Override
public Collection<User> findUsers() {
return users.values();
}
@Override
public User updateUser(User user) {
users.put(user.getId(), user);
return user;
}
}

@ -1,4 +1,4 @@
package com.example.camel;
package com.example.sbcamel;
import java.io.File;
@ -6,8 +6,10 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class Boot {
private static final Logger logger = LoggerFactory.getLogger(Boot.class);
@ -18,12 +20,12 @@ public class Boot {
configDirectory = args[0];
}
logger.info("config directory: {}", configDirectory);
if (new File(configDirectory).exists() && new File(configDirectory).isDirectory()) {
System.setProperty("spring.config.location", configDirectory + "/springboot.yml");
System.setProperty("logging.config", configDirectory + "/logback.xml");
}
System.setProperty("org.apache.activemq.SERIALIZABLE_PACKAGES","*");
System.setProperty("org.apache.activemq.SERIALIZABLE_PACKAGES", "*");
SpringApplication.run(Boot.class, args);
}

@ -0,0 +1,21 @@
package com.example.sbcamel.init;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.example.sbcamel.processor.LoginProcessor;
import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
@Configuration
public class AppConfig {
@Bean
public JacksonJsonProvider jaxrsProvider() {
return new JacksonJsonProvider();
}
@Bean
public LoginProcessor loginProcessor() {
return new LoginProcessor();
}
}

@ -0,0 +1,79 @@
package com.example.sbcamel.init;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.bean.BeanConstants;
import org.apache.camel.component.bean.validator.BeanValidationException;
import org.apache.camel.component.cxf.common.message.CxfConstants;
import org.apache.camel.model.dataformat.JsonLibrary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import com.example.sbcamel.mapper.SessionMapper;
import com.example.sbcamel.processor.LoginProcessor;
import com.example.sbcamel.service.SessionService;
import jakarta.annotation.PostConstruct;
import jakarta.ws.rs.core.Response;
@Component
public class CamelRouter extends RouteBuilder {
private static final String createSessionSql = "CREATE TABLE IF NOT EXISTS public.session (sessionId UUID not null, "
+ "username CHARACTER VARYING not null, password CHARACTER VARYING not null, PRIMARY KEY (sessionId))";
@Value("${app.queue-name}")
private String queueName;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
protected LoginProcessor loginProcessor;
@PostConstruct
private void init() {
org.apache.ibatis.logging.LogFactory.useSlf4jLogging();
jdbcTemplate.execute(createSessionSql);
}
@Override
public void configure() throws Exception {
// very raw way, just to handle the validation responses
onException(BeanValidationException.class).handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.BAD_REQUEST.getStatusCode()))
.setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}"));
onException(jakarta.ws.rs.NotFoundException.class).handled(true)
.setHeader(Exchange.HTTP_RESPONSE_CODE, constant(Response.Status.NOT_FOUND.getStatusCode()))
.setBody(simple("${exchangeProperty.CamelExceptionCaught.getMessage()}"));
from("cxfrs:/api?resourceClasses=" + SessionService.class.getName() + "&bindingStyle=Default"
+ "&providers=jaxrsProvider&loggingFeatureEnabled=true").to("log:cxfrs?showAll=true")
.to("bean-validator:user").to("activemq6:queue:" + queueName).process(exchange -> {
if (exchange.getMessage().getBody() != null && exchange.getMessage().getBody() instanceof byte[]
&& new String((byte[]) exchange.getMessage().getBody()).equals("null")) {
if (exchange.getIn().getHeader(Exchange.HTTP_METHOD).equals("GET")) {
throw new jakarta.ws.rs.NotFoundException();
}
}
});
from("activemq6:queue:" + queueName)
.process(exchange -> exchange.getIn().setHeader(BeanConstants.BEAN_METHOD_NAME,
exchange.getIn().getHeader(CxfConstants.OPERATION_NAME.toLowerCase())))
.to("log:activemq?showAll=true").transacted("propagationRequired").choice()
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("updateSession"))
.to("mybatis:" + SessionMapper.class.getName() + ".updateSession?statementType=Update")
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findSessions"))
.to("mybatis:" + SessionMapper.class.getName() + ".findSessions?statementType=SelectList")
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findSession"))
.to("mybatis:" + SessionMapper.class.getName() + ".findSession?statementType=SelectOne")
.when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("login"))
.to("mybatis:" + SessionMapper.class.getName() + ".findSession?statementType=SelectOne")
.process(loginProcessor).end().marshal().json(JsonLibrary.Jackson);
}
}

@ -0,0 +1,120 @@
package com.example.sbcamel.init;
import java.io.IOException;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.sql.DataSource;
import org.apache.camel.component.mybatis.MyBatisComponent;
import org.apache.camel.spring.spi.SpringTransactionPolicy;
import org.apache.ibatis.mapping.Environment;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
import org.springframework.transaction.PlatformTransactionManager;
import com.google.common.reflect.ClassPath;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
@Configuration
public class DatabaseConfig {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfig.class);
public static final String CFG_APP_DATABASE_URL = "${app.database.url}";
public static final String CFG_APP_DATABASE_USERNAME = "${app.database.username:}";
public static final String CFG_APP_DATABASE_PASSWORD = "${app.database.password:}";
public static final String CFG_APP_DATABASE_MAPPER_PACKAGE = "${app.database.mapper-package}";
public static final String CFG_APP_DATABASE_SPRINGBOOT_CLASS_PREFIX = "${app.database.springboot-class-prefix:BOOT-INF.classes.}";
@Value(CFG_APP_DATABASE_URL)
private String dbUrl;
@Value(CFG_APP_DATABASE_USERNAME)
private String dbUsername;
@Value(CFG_APP_DATABASE_PASSWORD)
private String dbPassword;
@Value(CFG_APP_DATABASE_MAPPER_PACKAGE)
private String mapperPackage;
@Value(CFG_APP_DATABASE_SPRINGBOOT_CLASS_PREFIX)
private String springBootClassPrefix;
@Bean
HikariConfig hikariConfig() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl(dbUrl);
config.setUsername(dbUsername);
config.setPassword(dbPassword);
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
return config;
}
@Bean
DataSource dataSource(HikariConfig hikariConfig) {
return new TransactionAwareDataSourceProxy(new HikariDataSource(hikariConfig));
}
@Bean
PlatformTransactionManager txManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
Environment environment = new Environment("development", new JdbcTransactionFactory(), dataSource);
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration(
environment);
Set<Class<?>> mapperClasses = findAllClassesUsingGuava(mapperPackage);
mapperClasses.forEach(configuration::addMapper);
return new SqlSessionFactoryBuilder().build(configuration);
}
@Bean
MyBatisComponent mybatis(SqlSessionFactory sqlSessionFactory) {
MyBatisComponent mybatis = new MyBatisComponent();
mybatis.setSqlSessionFactory(sqlSessionFactory);
return mybatis;
}
@Bean
SpringTransactionPolicy propagationRequired(PlatformTransactionManager txManager) {
SpringTransactionPolicy propagationRequired = new SpringTransactionPolicy();
propagationRequired.setTransactionManager(txManager);
propagationRequired.setPropagationBehaviorName("PROPAGATION_REQUIRED");
return propagationRequired;
}
private Set<Class<?>> findAllClassesUsingGuava(String packageName) throws IOException {
logger.trace("Orm mappers packageName: {}", packageName);
return ClassPath.from(ClassLoader.getSystemClassLoader()).getAllClasses().stream()
.peek(clazz -> logger.trace("candidate class: {}, package name: {}", clazz, clazz.getPackageName()))
.filter(clazz -> clazz.getPackageName().endsWith(packageName))
.peek(clazz -> logger.info("accepted class: {}, package name: {}", clazz, clazz.getPackageName()))
.map(clazz -> {
try {
if (clazz.getName().startsWith(springBootClassPrefix)) {
return Class.forName(clazz.getName().replace(springBootClassPrefix, ""));
}
return Class.forName(clazz.getName());
} catch (ClassNotFoundException e) {
logger.error("cannot convert this class name to class: {}", clazz.getName());
}
return null;
}).filter(Objects::nonNull).collect(Collectors.toSet());
}
}

@ -1,4 +1,4 @@
package com.example.camel;
package com.example.sbcamel.init;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
@ -13,8 +13,6 @@ import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopul
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
import org.springframework.security.web.SecurityFilterChain;
import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
@Configuration
public class SecurityConfig {
@ -35,9 +33,9 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(
(authorize) -> authorize.requestMatchers(HttpMethod.GET, "/**").hasAuthority(ROLE_BACKEND)
.requestMatchers(HttpMethod.POST, "/**").hasAuthority(ROLE_SERVER))
http.authorizeHttpRequests((authorize) -> authorize.requestMatchers(HttpMethod.GET, "/**")
.hasAuthority(ROLE_BACKEND).requestMatchers(HttpMethod.POST, "/**").hasAuthority(ROLE_SERVER)
.requestMatchers(HttpMethod.PUT, "/**").permitAll())
.httpBasic(Customizer.withDefaults()).csrf(csrf -> csrf.disable());
return http.build();
}
@ -58,10 +56,5 @@ public class SecurityConfig {
factory.setUserSearchFilter(userSearchFilter);
factory.setLdapAuthoritiesPopulator(authorities);
return factory.createAuthenticationManager();
}
@Bean
public JacksonJsonProvider jaxrsProvider() {
return new JacksonJsonProvider();
}
}
}

@ -0,0 +1,34 @@
package com.example.sbcamel.mapper;
import java.util.Collection;
import java.util.UUID;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.type.JdbcType;
import com.example.sbcamel.service.Session;
import com.example.sbcamel.service.UuidTypeHandler;
public interface SessionMapper {
@Insert({ "<script>",
"MERGE INTO public.session (sessionId, username, password) KEY (sessionId) VALUES (#{sessionId, javaType=java.util.UUID, "
+ "jdbcType=OTHER, typeHandler=com.example.sbcamel.service.UuidTypeHandler}, #{username}, #{password}) ",
"</script>" })
Session updateSession(Session session);
@Results({ @Result(property = "sessionId", column = "sessionId", javaType=UUID.class, jdbcType=JdbcType.OTHER, typeHandler=UuidTypeHandler.class),
@Result(property = "username", column = "username"), @Result(property = "password", column = "password") })
@Select({ "<script>", "select sessionId, username, password from public.session where sessionId=#{list[0], javaType=java.util.UUID, "
+ "jdbcType=OTHER, typeHandler=com.example.sbcamel.service.UuidTypeHandler}",
"</script>" })
Session findSession(UUID sessionId);
@Results({ @Result(property = "sessionId", column = "sessionId", javaType=UUID.class, jdbcType=JdbcType.OTHER, typeHandler=UuidTypeHandler.class),
@Result(property = "username", column = "username"), @Result(property = "password", column = "password") })
@Select({ "<script>", "select sessionId, username, password from public.session order by sessionId", "</script>" })
Collection<Session> findSessions();
}

@ -0,0 +1,17 @@
package com.example.sbcamel.processor;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class LoginProcessor implements Processor {
private static final Logger logger = LoggerFactory.getLogger(LoginProcessor.class);
@Override
public void process(Exchange exchange) throws Exception {
logger.info("response body: {}", exchange.getMessage().getBody());
}
}

@ -0,0 +1,66 @@
package com.example.sbcamel.service;
import java.io.Serializable;
import java.util.UUID;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
/**
* User entity
*
*/
@SuppressWarnings("serial")
public class Session implements Serializable {
private UUID sessionId;
@NotNull
@Size(min = 3, max = 40)
private String username;
@NotNull
@Size(min = 3, max = 40)
private String password;
public Session() {
}
public Session(UUID sessionId, @NotNull @Size(min = 3, max = 40) String username,
@NotNull @Size(min = 3, max = 40) String password) {
this.sessionId = sessionId;
this.username = username;
this.password = password;
}
public UUID getSessionId() {
return sessionId;
}
public void setSessionId(UUID sessionId) {
this.sessionId = sessionId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
}

@ -0,0 +1,39 @@
package com.example.sbcamel.service;
import java.util.Collection;
import java.util.UUID;
import jakarta.validation.Valid;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
/**
* Service interface for managing sessions.
*/
public interface SessionService {
@POST
@Path("/session")
@Consumes(MediaType.APPLICATION_JSON)
Session updateSession(@Valid Session session);
@GET
@Path("/session/{sessionId}")
@Produces(MediaType.APPLICATION_JSON)
Session findSession(@PathParam("sessionId") UUID sessionId);
@GET
@Path("/session")
@Produces(MediaType.APPLICATION_JSON)
Collection<Session> findSessions();
@POST
@Path("/login/{sessionId}")
@Produces(MediaType.APPLICATION_JSON)
Session login(@PathParam("sessionId") UUID sessionId);
}

@ -0,0 +1,33 @@
package com.example.sbcamel.service;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.UUID;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
public class UuidTypeHandler extends BaseTypeHandler<UUID> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, UUID parameter, JdbcType jdbcType)
throws SQLException {
ps.setObject(i, parameter);
}
@Override
public UUID getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.getObject(columnName, UUID.class);
}
@Override
public UUID getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.getObject(columnIndex, UUID.class);
}
@Override
public UUID getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.getObject(columnIndex, UUID.class);
}
}
Loading…
Cancel
Save