From ee7b4028ded2266ece5385677fd900e6cf3975ae Mon Sep 17 00:00:00 2001 From: Yan Date: Sat, 8 Mar 2025 15:41:20 +0800 Subject: [PATCH] 2.1.1 Added h2 storage using camel-mybatis --- bruno/findUser.bru | 20 +++ bruno/findUsers.bru | 2 +- bruno/updateUser.bru | 6 +- conf/springboot.yml | 5 + conf2/mybatis/mybatis-3-config.dtd | 117 +++++++++++++++++ conf2/mybatis/mybatis-h2-config.xml | 17 +++ conf2/springboot.yml | 5 + db/appdb.mv.db | Bin 0 -> 24576 bytes db/appdb.trace.db | 105 +++++++++++++++ pom.xml | 37 +++++- readme.md | 14 ++ src/main/java/com/example/sbcamel/Boot.java | 4 +- .../java/com/example/sbcamel/CamelRouter.java | 45 ++++++- .../com/example/sbcamel/DatabaseConfig.java | 120 ++++++++++++++++++ .../com/example/sbcamel/SecurityConfig.java | 5 +- src/main/java/com/example/sbcamel/User.java | 74 ++++++----- .../java/com/example/sbcamel/UserService.java | 58 ++++----- .../com/example/sbcamel/UserServiceImpl.java | 33 ----- .../example/sbcamel/mapper/UserMapper.java | 24 ++++ 19 files changed, 572 insertions(+), 119 deletions(-) create mode 100644 bruno/findUser.bru create mode 100644 conf2/mybatis/mybatis-3-config.dtd create mode 100644 conf2/mybatis/mybatis-h2-config.xml create mode 100644 db/appdb.mv.db create mode 100644 db/appdb.trace.db create mode 100644 src/main/java/com/example/sbcamel/DatabaseConfig.java delete mode 100644 src/main/java/com/example/sbcamel/UserServiceImpl.java create mode 100644 src/main/java/com/example/sbcamel/mapper/UserMapper.java diff --git a/bruno/findUser.bru b/bruno/findUser.bru new file mode 100644 index 0000000..43364c0 --- /dev/null +++ b/bruno/findUser.bru @@ -0,0 +1,20 @@ +meta { + name: findUser + type: http + seq: 4 +} + +get { + url: http://localhost:9091/services/api/user/2 + body: none + auth: basic +} + +headers { + operationName: findUsers +} + +auth:basic { + username: cxfrs + password: password +} diff --git a/bruno/findUsers.bru b/bruno/findUsers.bru index e14b0de..ae9b23d 100644 --- a/bruno/findUsers.bru +++ b/bruno/findUsers.bru @@ -5,7 +5,7 @@ meta { } get { - url: http://localhost:9090/services/api/user + url: http://localhost:9091/services/api/user body: none auth: basic } diff --git a/bruno/updateUser.bru b/bruno/updateUser.bru index 2a7b114..0f1bee9 100644 --- a/bruno/updateUser.bru +++ b/bruno/updateUser.bru @@ -5,7 +5,7 @@ meta { } post { - url: http://localhost:9091/services/api/user + url: http://localhost:9090/services/api/user body: json auth: basic } @@ -22,7 +22,7 @@ auth:basic { body:json { { - "id": 3, - "name": "Bruce Wayne" + "id": 2, + "name": "Wallie West" } } diff --git a/conf/springboot.yml b/conf/springboot.yml index 11e1d94..d6c92af 100644 --- a/conf/springboot.yml +++ b/conf/springboot.yml @@ -19,3 +19,8 @@ app: zookeeper: url: "127.0.0.1:2181" group-name: "UserServiceGroup" + database: + url: "jdbc:h2:tcp://localhost/~/h2/db/appdb" + username: "app" + password: "app" + mapper-package: "com.example.sbcamel.mapper" diff --git a/conf2/mybatis/mybatis-3-config.dtd b/conf2/mybatis/mybatis-3-config.dtd new file mode 100644 index 0000000..38a19cf --- /dev/null +++ b/conf2/mybatis/mybatis-3-config.dtd @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/conf2/mybatis/mybatis-h2-config.xml b/conf2/mybatis/mybatis-h2-config.xml new file mode 100644 index 0000000..60bde89 --- /dev/null +++ b/conf2/mybatis/mybatis-h2-config.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/conf2/springboot.yml b/conf2/springboot.yml index 3a0d5f8..1a8d4a5 100644 --- a/conf2/springboot.yml +++ b/conf2/springboot.yml @@ -19,3 +19,8 @@ app: zookeeper: url: "127.0.0.1:2181" group-name: "UserServiceGroup" + database: + url: "jdbc:h2:tcp://localhost/~/h2/db/appdb" + username: "app" + password: "app" + mapper-package: "com.example.sbcamel.mapper" diff --git a/db/appdb.mv.db b/db/appdb.mv.db new file mode 100644 index 0000000000000000000000000000000000000000..2bc030df62db15773c76339636bd4c33bd9a4874 GIT binary patch literal 24576 zcmeHP-EJGl6(;GwjS@FSklb$=JB}NMn7^HwB~ZYWL|bemT97E)DNq=*yR)`niWDeH zwFG8qtXc$)v z2YTYa)Z-QnJ>hA*R55=>0!9Kx0!9Kx0!9Kx0!9Kx0!9Kx0!9Kx0!9Kqz691X-k+Tf z|Nrq{ia}r`U?gB9U?gB9U?gB9U?gB9U?gB9U?gB9aLy8#2Kfhi*usr{^+F%OUcjDu z-EtraU{CG0IBASWqe)Bp67m8NQWTTMWOonp1VZL$5A#wIz)-)Qw0L7O@}ULSKEFT6 zCaC`B+JnlC8t}L>8`KZkg!m<>$m?sY7&tQHZ2;oeCLG90*J5ThV5=|weze{zYM5Ssr|P0k7~uL zd=RT;laMegQIwbPtvx+a&E4Q;q?Jv4D>jkNE?SkkRK$-Wb+}pZcm=%$uW33M*vYeIT|D1KipSC z|G0(dpEJZ1rHJXNh;fXVa@5EWLouDJCCCY4M1$g#brEAJBm=HAi4WHi>zz-#sn z2ZJYSaHv<+MD>sN^?B84%=9&R-Aoln2XTi{XLlYdACMg1ov94Kwno3sAZ4{+b&UUJ zYfqr1=JN4Gx5s03oc-#&2C_&y7ckh`wP>u1bZ+YWFdA*oC~2&A>!aa|^VT>r(-F*u z^^vy?69rcG4Yhw~c`)*}bg0LA=<7StMEYitpKO4MiED#V>U^+Mt$td$3F~VUqZ`qQ z#77z*o%qP(#~df8m_W>x zc3dmRKZB9rpj;u#P|XGb749c+a*3Sm%W)M46Ej5wa*u0i5-7CoDy5l%dt zk`bQoCwQ?XoH4=J^@E~obBakW_zeIl@*8GMviM65`D|w_acv^*k+}_#3jvcZ;vprs z;VgHo;M;)9b(Fbc^W86U1>CQ<@N81qB%V#>_u$$55=`WSN^NZ`vXzzEKmVA^cgA&e zQ?@5#A1ZPkfy||BkKj=9lU^Aqcx6zIy;~)UUKxq7%S6c%uPkjo@ye1XsaGZvhwTm6 z{}hkmeK^eW?_5hE?LN<@SHL|38Itp((pgJOS^qHGPVoPTUZnFb<^PEzJ%>z8VWVu0 zru-r6=^W0{*94Dh|Em1-dd&YTxVJJ;<5%{#dN?7yr)n_RwV&#P34OdgKJ>NyR2>gB z+gaUJLuL10>b>IwU+s<+X#ejje=qUOAYY9O>+(XY@swuP-3nWmcUNuO*d1Vrfo) zEr$PJ)y)pW|1aCV#(T#9e_{B);s3B_@=pBUDe-?V_c;B$6fER%PWiu=dYt9R#{b3t zRm{1{{GV~x%gA0F+9>P?oaQ%pXYhYNg?v_MVr&dEKwK@och~M-Y#qIgl`QTw8~$(je-t0SY+U*(;xYUm0w+xq|DWa%nE1cp|1APM zJo#^9hX2PIqeTz#?C{Imcs7RrUqZHj64EqDIpN<$BAxSp?S>&kAwGu~`b-mf{2!P2 zKaB}doHkTW07%km=OpUpxFIRGumJ#xKr=nQ!zIN3t;y1VE46Pbw=kDPb7f%}1VV6O zVK-Dd@O=v_A_xnpg?$nP()FMqLatqIVMy(gj6&r!tIHxpD3{Uz3ZBp*@hsv58omUO z7V(fP9ZsR(gi>=11%=>S0I1`0mxvHq6ltGetSm|b6bS8Elu}29erQo1C`h7X7KPLe zCPHaZ9}6!)p2ZmVr7wu(2!^?4uH~fG(aMt2EXQN6!#t?tOXazNwj52R(MVStore.java:291) + at org.h2.mvstore.MVStore$Builder.open(MVStore.java:2035) + at org.h2.mvstore.db.Store.(Store.java:133) + at org.h2.engine.Database.(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.(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.(HikariPool.java:98) + at com.zaxxer.hikari.HikariDataSource.(HikariDataSource.java:80) + at com.example.sbcamel.DatabaseConfig.dataSource(DatabaseConfig.java:69) + at com.example.sbcamel.DatabaseConfig$$SpringCGLIB$$0.CGLIB$dataSource$0() + at com.example.sbcamel.DatabaseConfig$$SpringCGLIB$$FastClass$$1.invoke() + 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() + 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.(MVStore.java:286) + ... 77 more diff --git a/pom.xml b/pom.xml index ebbc2a3..93fbbc5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.example camel-springboot-activemq6-example - 2.1.0 + 2.1.1 camel-springboot-activemq6-example org.springframework.boot @@ -17,6 +17,8 @@ 17 4.8.3 ${project.parent.version} + 3.5.19 + 3.0.4 @@ -56,6 +58,10 @@ org.springframework.security spring-security-ldap + + org.springframework + spring-jdbc + org.apache.camel.springboot @@ -82,12 +88,35 @@ camel-jackson-starter - com.fasterxml.jackson.jakarta.rs - jackson-jakarta-rs-json-provider + org.apache.camel.springboot + camel-zookeeper-master-starter org.apache.camel.springboot - camel-zookeeper-master-starter + camel-mybatis-starter + + + com.h2database + h2 + runtime + + + com.zaxxer + HikariCP + + + org.mybatis + mybatis + ${mybatis.version} + + + org.mybatis + mybatis-spring + ${mybatis-spring.version} + + + com.fasterxml.jackson.jakarta.rs + jackson-jakarta-rs-json-provider diff --git a/readme.md b/readme.md index 3e834db..544a12f 100644 --- a/readme.md +++ b/readme.md @@ -6,6 +6,7 @@ ApacheDS Server 2.0.0.AM27 Apache ActiveMQ 6.1.5 Apache Zookeeper 3.9.3 + H2 Database Version 2.3.232 ``` 2. Please see conf/springboot.yml for LDAP/ActiveMQ Address @@ -207,3 +208,16 @@ C:\Users\XXX\apache-zookeeper-3.9.3-bin>call "C:\Users\XXX\graalvm-jdk-17.0.14+8 2025-03-01 15:28:22,213 [myid:] - INFO [SyncThread:0:o.a.z.s.p.FileTxnLog@291] - Creating new log file: log.1 ``` +**4. H2 Database Version 2.3.232** + +``` +C:\Users\XXX\Desktop>SET JAVA_HOME=C:\Users\XXX\graalvm-jdk-17.0.14+8.1 + +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) +``` diff --git a/src/main/java/com/example/sbcamel/Boot.java b/src/main/java/com/example/sbcamel/Boot.java index c63d1af..1217c10 100644 --- a/src/main/java/com/example/sbcamel/Boot.java +++ b/src/main/java/com/example/sbcamel/Boot.java @@ -18,12 +18,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); } diff --git a/src/main/java/com/example/sbcamel/CamelRouter.java b/src/main/java/com/example/sbcamel/CamelRouter.java index 0117900..0f19c69 100644 --- a/src/main/java/com/example/sbcamel/CamelRouter.java +++ b/src/main/java/com/example/sbcamel/CamelRouter.java @@ -2,16 +2,24 @@ package com.example.sbcamel; 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.component.zookeepermaster.policy.MasterRoutePolicy; 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 jakarta.annotation.PostConstruct; import jakarta.ws.rs.core.Response; @Component public class CamelRouter extends RouteBuilder { + private static final String createUserSql = "CREATE TABLE IF NOT EXISTS public.\"user\" (id BIGINT not null, " + + "name CHARACTER VARYING not null, PRIMARY KEY (id))"; @Value("${app.queue-name}") private String queueName; @@ -22,6 +30,14 @@ public class CamelRouter extends RouteBuilder { @Value("${app.zookeeper.group-name}") private String groupName; + @Autowired + private JdbcTemplate jdbcTemplate; + + @PostConstruct + private void init() { + jdbcTemplate.execute(createUserSql); + } + @Override public void configure() throws Exception { // very raw way, just to handle the validation responses @@ -29,17 +45,36 @@ public class CamelRouter extends RouteBuilder { .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); + 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=" + UserService.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(); + } + } + }); MasterRoutePolicy masterRoutePolicy = new MasterRoutePolicy(); masterRoutePolicy.setZooKeeperUrl(zookeeperUrl); masterRoutePolicy.setGroupName(groupName); from("activemq6:queue:" + queueName).autoStartup("false").routePolicy(masterRoutePolicy) - .to("bean-validator:user").bean(UserServiceImpl.class).marshal().json(JsonLibrary.Jackson); + .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("updateUser")) + .to("mybatis:com.example.sbcamel.mapper.UserMapper.updateUser?statementType=Update") + .when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findUsers")) + .to("mybatis:com.example.sbcamel.mapper.UserMapper.findUsers?statementType=SelectList") + .when(header(BeanConstants.BEAN_METHOD_NAME).isEqualTo("findUser")) + .to("mybatis:com.example.sbcamel.mapper.UserMapper.findUser?statementType=SelectOne").end().marshal() + .json(JsonLibrary.Jackson); } } \ No newline at end of file diff --git a/src/main/java/com/example/sbcamel/DatabaseConfig.java b/src/main/java/com/example/sbcamel/DatabaseConfig.java new file mode 100644 index 0000000..07f6b9e --- /dev/null +++ b/src/main/java/com/example/sbcamel/DatabaseConfig.java @@ -0,0 +1,120 @@ +package com.example.sbcamel; + +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> 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> 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()); + } +} diff --git a/src/main/java/com/example/sbcamel/SecurityConfig.java b/src/main/java/com/example/sbcamel/SecurityConfig.java index 0e1a11e..5607fa2 100644 --- a/src/main/java/com/example/sbcamel/SecurityConfig.java +++ b/src/main/java/com/example/sbcamel/SecurityConfig.java @@ -35,9 +35,8 @@ 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)) .httpBasic(Customizer.withDefaults()).csrf(csrf -> csrf.disable()); return http.build(); } diff --git a/src/main/java/com/example/sbcamel/User.java b/src/main/java/com/example/sbcamel/User.java index c94a970..1c39d0c 100644 --- a/src/main/java/com/example/sbcamel/User.java +++ b/src/main/java/com/example/sbcamel/User.java @@ -13,42 +13,40 @@ import jakarta.validation.constraints.Size; @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(); - } + @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(); + } } \ No newline at end of file diff --git a/src/main/java/com/example/sbcamel/UserService.java b/src/main/java/com/example/sbcamel/UserService.java index ee01434..2aef174 100644 --- a/src/main/java/com/example/sbcamel/UserService.java +++ b/src/main/java/com/example/sbcamel/UserService.java @@ -16,37 +16,35 @@ import jakarta.ws.rs.core.MediaType; */ public interface UserService { - /** - * Find a user by the given ID - * - * @param id - * the ID of the user - * @return the user, or null if user not found. - */ - @GET - @Path("/user/{id}") - @Produces(MediaType.APPLICATION_JSON) - User findUser(@PathParam("id") Integer id); + /** + * Find a user by the given ID + * + * @param id the ID of the user + * @return the user, or null 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 findUsers(); + /** + * Find all users + * + * @return a collection of all users + */ + @GET + @Path("/user") + @Produces(MediaType.APPLICATION_JSON) + Collection findUsers(); - /** - * Update the given user - * - * @param user - * the user - */ - @POST - @Path("/user") - @Consumes(MediaType.APPLICATION_JSON) - User updateUser(@Valid User user); + /** + * Update the given user + * + * @param user the user + */ + @POST + @Path("/user") + @Consumes(MediaType.APPLICATION_JSON) + User updateUser(@Valid User user); } \ No newline at end of file diff --git a/src/main/java/com/example/sbcamel/UserServiceImpl.java b/src/main/java/com/example/sbcamel/UserServiceImpl.java deleted file mode 100644 index eaf2c62..0000000 --- a/src/main/java/com/example/sbcamel/UserServiceImpl.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.example.sbcamel; - -import java.util.Collection; -import java.util.Map; -import java.util.TreeMap; - -public class UserServiceImpl implements UserService { - - private final Map 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 findUsers() { - return users.values(); - } - - @Override - public User updateUser(User user) { - users.put(user.getId(), user); - return user; - } - -} \ No newline at end of file diff --git a/src/main/java/com/example/sbcamel/mapper/UserMapper.java b/src/main/java/com/example/sbcamel/mapper/UserMapper.java new file mode 100644 index 0000000..3f66dd4 --- /dev/null +++ b/src/main/java/com/example/sbcamel/mapper/UserMapper.java @@ -0,0 +1,24 @@ +package com.example.sbcamel.mapper; + +import java.util.Collection; + +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 com.example.sbcamel.User; + +public interface UserMapper { + + @Insert({ "" }) + User updateUser(User user); + + @Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name") }) + @Select({ "" }) + User findUser(Integer id); + + @Results({ @Result(property = "id", column = "id"), @Result(property = "name", column = "name") }) + @Select({ "" }) + Collection findUsers(); +}