diff --git a/.gitignore b/.gitignore
index 1d963a9..fd6098f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,27 @@
-*.class
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
.project
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
+.settings
+.springBeans
-# Package Files #
-*.jar
-*.war
-*.ear
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+/bin/
+/target/
diff --git a/README.md b/README.md
index 86fd030..db31f5a 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
# Distributed Java.《分布式 Java》
+
Distributed Java.Let's [READ](SUMMARY.md)!
《分布式 Java》是一本关于 Java 分布式应用的学习教程,是对市面上基于 Java 的分布式系统最佳实践的技术总结。图文并茂,并通过大量实例让你走近 Java 的世界!
@@ -9,10 +10,77 @@ Distributed Java.Let's [READ](SUMMARY.md)!
从[目录](SUMMARY.md)开始阅读吧!
-### Contact 联系作者:
-* Blog:[waylau.com](https://waylau.com)
-* Gmail: [waylau521@gmail.com](mailto:waylau521@gmail.com)
-* Weibo: [waylau521](http://weibo.com/waylau521)
-* Twitter: [waylau521](https://twitter.com/waylau521)
-* Github : [waylau](https://github.com/waylau)
\ No newline at end of file
+## 本书所涉及的技术和相关版本
+
+涉及的相关技术及版本如下。
+
+* JDK 13
+* Apache Maven 3.6.3
+* Eclipse 2019-12 (4.14)
+* JUnit 5.5.2
+* Jersey 2.30
+* Apache CXF 3.3.5
+* Spring 5.2.3.RELEASE
+* ActiveMQ 5.15.11
+* Spring Boot 2.1.2.RELEASE
+* Axon Framework 3.4.3
+* Docker 17.09.1-ce-win42
+* Spark 2.3.0
+* MongoDB 3.4.6
+* ZooKeeper 3.5.6
+* Spring Security 5.2.0.BUILD-SNAPSHOT
+* NGINX 1.15.8
+* Spring Cloud Finchley.M9
+
+
+包含示例如下:
+
+* [在Java中实现常用网络I/O模型](samples/java-io-mode)
+* [并发带来的风险——死锁](samples/java-concurrency)
+* [基于Java RMI实现分布式对象通信](samples/java-rmi)
+* [基于JAX-WS实现Web服务](samples/java-ws)
+* [基于JMS的消息发送和接收](samples/jms-msg)
+* [基于Jersey来构建REST服务](samples/jersey-rest)
+* [基于Apache CXF来构建REST服务](samples/cxf-rest)
+* [基于Spring Web MVC来构建REST服务](samples/spring-rest)
+* [Jetty HTTP Server](samples/javase-rest)
+* [基于Spring Boot实现微服务](samples/spring-boot-rest)
+* [基于CQRS微服务通信](samples/axon-cqrs)
+* [使用AWS平台实现Serverless架构](samples/game-server)
+* [基于Spark词频统计](samples/spark-word-count)
+* [基于MongoDB文件服务器](https://github.com/waylau/mongodb-file-server)
+* [基于ZooKeeper的服务注册和发现](samples/zk-registry-discovery)
+* [基于Spring Cloud的服务器](samples/eureka-server)
+* [基于Spring Cloud的客户端](samples/eureka-client)
+* 陆续整理中...
+
+
+## 相关书籍
+
+与本书配套的书籍已经出版:
+
+* [《分布式系统开发实战》](https://github.com/waylau/distributed-system-tutorial-samples)
+
+
+## 联系作者
+
+您也可以直接联系我:
+
+* 博客:https://waylau.com
+* 邮箱:[waylau521(at)gmail.com](mailto:waylau521@gmail.com)
+* 微博:http://weibo.com/waylau521
+* 开源:https://github.com/waylau
+
+## 其他书籍
+
+若您对本书不感冒,笔者还写了其他方面的超过一打的书籍(可见),多是开源电子书。
+
+本人也维护了一个[books-collection](https://github.com/waylau/books-collection)项目,里面提供了优质的专门给程序员的开源、免费图书集合。
+
+## 开源捐赠
+
+
+
+
+捐赠所得所有款项将用于开源事业!见[捐赠列表](https://waylau.com/donate/)。
diff --git a/SUMMARY.md b/SUMMARY.md
index 1b164ce..6836a9f 100644
--- a/SUMMARY.md
+++ b/SUMMARY.md
@@ -18,7 +18,7 @@
* [概述](docs/rmi-overview.md)
* [架构](docs/architecture.md)
* [常用接口](docs/api.md)
- * [示例](docs/example.md)
+ * [示例](docs/rmi-example.md)
* 基于消息的通信
* [概述](docs/mq-overview.md)
* [JMS](docs/jms.md)
diff --git a/docs/example.md b/docs/example.md
deleted file mode 100644
index c098617..0000000
--- a/docs/example.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# 示例
-
diff --git a/docs/rmi-example.md b/docs/rmi-example.md
new file mode 100644
index 0000000..c89e2ed
--- /dev/null
+++ b/docs/rmi-example.md
@@ -0,0 +1,5 @@
+# 示例
+
+
+
+本节示例,可以在`java-rmi`项目下找到。
\ No newline at end of file
diff --git a/samples/axon-cqrs/.gitignore b/samples/axon-cqrs/.gitignore
new file mode 100644
index 0000000..fd6098f
--- /dev/null
+++ b/samples/axon-cqrs/.gitignore
@@ -0,0 +1,27 @@
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+/bin/
+/target/
diff --git a/samples/axon-cqrs/pom.xml b/samples/axon-cqrs/pom.xml
new file mode 100644
index 0000000..50e0531
--- /dev/null
+++ b/samples/axon-cqrs/pom.xml
@@ -0,0 +1,73 @@
+
+ 4.0.0
+ com.waylau.spring
+ axon-cqrs
+ 1.0.0
+ axon-cqrs
+ jar
+
+ waylau.com
+ https://waylau.com
+
+
+
+ UTF-8
+ 5.2.3.RELEASE
+ 3.4.3
+ 2.13.3
+
+
+
+ org.springframework
+ spring-context
+ ${spring.version}
+
+
+ org.axonframework
+ axon-core
+ ${axon.version}
+
+
+ org.axonframework
+ axon-spring
+ ${axon.version}
+
+
+ org.apache.logging.log4j
+ log4j-core
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-jcl
+ ${log4j.version}
+
+
+ org.apache.logging.log4j
+ log4j-slf4j-impl
+ ${log4j.version}
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+
+
+ maven-compiler-plugin
+
+ 3.7.0
+
+ 1.8
+ 1.8
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/Application.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/Application.java
new file mode 100644
index 0000000..f66af95
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/Application.java
@@ -0,0 +1,46 @@
+package com.waylau.axon.cqrs;
+
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+import org.axonframework.config.Configuration;
+import org.axonframework.config.DefaultConfigurer;
+import org.axonframework.eventsourcing.eventstore.inmemory.InMemoryEventStorageEngine;
+import org.slf4j.Logger;
+
+import com.waylau.axon.cqrs.command.aggregates.BankAccount;
+import com.waylau.axon.cqrs.command.commands.CreateAccountCommand;
+import com.waylau.axon.cqrs.command.commands.WithdrawMoneyCommand;
+import com.waylau.axon.cqrs.common.domain.AccountId;
+
+/**
+ * 主应用入口.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class Application {
+ private static final Logger LOGGER = getLogger(Application.class);
+
+ public static void main(String args[]) throws InterruptedException{
+ LOGGER.info("Application is start.");
+ Configuration config = DefaultConfigurer.defaultConfiguration()
+ .configureAggregate(BankAccount.class)
+ .configureEmbeddedEventStore(c ->
+ new InMemoryEventStorageEngine())
+ .buildConfiguration();
+ config.start();
+ AccountId id = new AccountId();
+ config.commandGateway().send(new CreateAccountCommand(id,
+ "MyAccount",1000));
+ config.commandGateway().send(new WithdrawMoneyCommand(id, 500));
+ config.commandGateway().send(new WithdrawMoneyCommand(id, 500));
+ config.commandGateway().send(new WithdrawMoneyCommand(id, 500));
+
+ // 线程先睡五秒,等事件处理完
+ Thread.sleep(5000L);
+
+ LOGGER.info("Application is shutdown.");
+ }
+
+}
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/aggregates/BankAccount.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/aggregates/BankAccount.java
new file mode 100644
index 0000000..fc9d424
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/aggregates/BankAccount.java
@@ -0,0 +1,73 @@
+package com.waylau.axon.cqrs.command.aggregates;
+
+import static org.axonframework.commandhandling.model.AggregateLifecycle.apply;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.math.BigDecimal;
+
+import org.axonframework.commandhandling.CommandHandler;
+import org.axonframework.commandhandling.model.AggregateIdentifier;
+import org.axonframework.eventhandling.EventHandler;
+import org.slf4j.Logger;
+
+import com.waylau.axon.cqrs.command.commands.CreateAccountCommand;
+import com.waylau.axon.cqrs.command.commands.WithdrawMoneyCommand;
+import com.waylau.axon.cqrs.common.domain.AccountId;
+import com.waylau.axon.cqrs.common.events.CreateAccountEvent;
+import com.waylau.axon.cqrs.common.events.WithdrawMoneyEvent;
+
+/**
+ * Bank Account.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class BankAccount {
+
+ private static final Logger LOGGER = getLogger(BankAccount.class);
+
+ @AggregateIdentifier
+ private AccountId accountId;
+ private String accountName;
+ private BigDecimal balance;
+
+ public BankAccount() {
+ }
+
+ @CommandHandler
+ public BankAccount(CreateAccountCommand command){
+ LOGGER.debug("Construct a new BankAccount");
+ apply(new CreateAccountEvent(command.getAccountId(),
+ command.getAccountName(),
+ command.getAmount()));
+ }
+
+ @CommandHandler
+ public void handle(WithdrawMoneyCommand command){
+ apply(new WithdrawMoneyEvent(command.getAccountId(),
+ command.getAmount()));
+ }
+
+ @EventHandler
+ public void on(CreateAccountEvent event){
+ this.accountId = event.getAccountId();
+ this.accountName = event.getAccountName();
+ this.balance = new BigDecimal(event.getAmount());
+ LOGGER.info("Account {} is created with balance {}",
+ accountId,
+ this.balance);
+ }
+
+ @EventHandler
+ public void on(WithdrawMoneyEvent event){
+ BigDecimal result = this.balance.subtract(
+ new BigDecimal(event.getAmount()));
+ if(result.compareTo(BigDecimal.ZERO)<0)
+ LOGGER.error("Cannot withdraw more money than the balance!");
+ else {
+ this.balance = result;
+ LOGGER.info("Withdraw {} from account {}, balance result: {}",
+ event.getAmount(), accountId, balance);
+ }
+ }
+}
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/commands/CreateAccountCommand.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/commands/CreateAccountCommand.java
new file mode 100644
index 0000000..87e2104
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/commands/CreateAccountCommand.java
@@ -0,0 +1,36 @@
+package com.waylau.axon.cqrs.command.commands;
+
+import com.waylau.axon.cqrs.common.domain.AccountId;
+
+/**
+ * Create Account Command.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class CreateAccountCommand {
+
+ private AccountId accountId;
+ private String accountName;
+ private long amount;
+
+ public CreateAccountCommand(AccountId accountId,
+ String accountName,
+ long amount) {
+ this.accountId = accountId;
+ this.accountName = accountName;
+ this.amount = amount;
+ }
+
+ public AccountId getAccountId() {
+ return accountId;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public long getAmount() {
+ return amount;
+ }
+}
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/commands/WithdrawMoneyCommand.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/commands/WithdrawMoneyCommand.java
new file mode 100644
index 0000000..4d81335
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/command/commands/WithdrawMoneyCommand.java
@@ -0,0 +1,32 @@
+package com.waylau.axon.cqrs.command.commands;
+
+import org.axonframework.commandhandling.TargetAggregateIdentifier;
+
+import com.waylau.axon.cqrs.common.domain.AccountId;
+
+/**
+ * Withdraw Money Command.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class WithdrawMoneyCommand {
+
+ @TargetAggregateIdentifier
+ private AccountId accountId;
+ private long amount;
+
+
+ public WithdrawMoneyCommand(AccountId accountId, long amount) {
+ this.accountId = accountId;
+ this.amount = amount;
+ }
+
+ public AccountId getAccountId() {
+ return accountId;
+ }
+
+ public long getAmount() {
+ return amount;
+ }
+}
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/domain/AccountId.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/domain/AccountId.java
new file mode 100644
index 0000000..15b5a0b
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/domain/AccountId.java
@@ -0,0 +1,54 @@
+package com.waylau.axon.cqrs.common.domain;
+
+import org.axonframework.common.Assert;
+import org.axonframework.common.IdentifierFactory;
+
+import java.io.Serializable;
+
+/**
+ * Account Id.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class AccountId implements Serializable {
+
+ private static final long serialVersionUID = 7119961474083133148L;
+ private final String identifier;
+
+ private final int hashCode;
+
+ public AccountId() {
+ this.identifier =
+ IdentifierFactory.getInstance().generateIdentifier();
+ this.hashCode = identifier.hashCode();
+ }
+
+ public AccountId(String identifier) {
+ Assert.notNull(identifier, ()->"Identifier may not be null");
+ this.identifier = identifier;
+ this.hashCode = identifier.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ AccountId accountId = (AccountId) o;
+
+ return identifier.equals(accountId.identifier);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ @Override
+ public String toString() {
+ return identifier;
+ }
+
+}
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/events/CreateAccountEvent.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/events/CreateAccountEvent.java
new file mode 100644
index 0000000..9d8bd74
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/events/CreateAccountEvent.java
@@ -0,0 +1,34 @@
+package com.waylau.axon.cqrs.common.events;
+
+import com.waylau.axon.cqrs.common.domain.AccountId;
+
+/**
+ * Create Account Event.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class CreateAccountEvent {
+ private AccountId accountId;
+ private String accountName;
+ private long amount;
+
+ public CreateAccountEvent(AccountId accountId,
+ String accountName, long amount) {
+ this.accountId = accountId;
+ this.accountName = accountName;
+ this.amount = amount;
+ }
+
+ public AccountId getAccountId() {
+ return accountId;
+ }
+
+ public String getAccountName() {
+ return accountName;
+ }
+
+ public long getAmount() {
+ return amount;
+ }
+}
diff --git a/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/events/WithdrawMoneyEvent.java b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/events/WithdrawMoneyEvent.java
new file mode 100644
index 0000000..ad2e5fe
--- /dev/null
+++ b/samples/axon-cqrs/src/main/java/com/waylau/axon/cqrs/common/events/WithdrawMoneyEvent.java
@@ -0,0 +1,27 @@
+package com.waylau.axon.cqrs.common.events;
+
+import com.waylau.axon.cqrs.common.domain.AccountId;
+
+/**
+ * Withdraw Money Event.
+ *
+ * @since 1.0.0 2020年1月21日
+ * @author Way Lau
+ */
+public class WithdrawMoneyEvent {
+ private AccountId accountId;
+ private long amount;
+
+ public WithdrawMoneyEvent(AccountId accountId, long amount) {
+ this.accountId = accountId;
+ this.amount = amount;
+ }
+
+ public AccountId getAccountId() {
+ return accountId;
+ }
+
+ public long getAmount() {
+ return amount;
+ }
+}
diff --git a/samples/axon-cqrs/src/main/resources/log4j2.xml b/samples/axon-cqrs/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..2ae871f
--- /dev/null
+++ b/samples/axon-cqrs/src/main/resources/log4j2.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/cxf-rest/.classpath b/samples/cxf-rest/.classpath
new file mode 100644
index 0000000..3b70160
--- /dev/null
+++ b/samples/cxf-rest/.classpath
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/cxf-rest/.gitignore b/samples/cxf-rest/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/samples/cxf-rest/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/samples/cxf-rest/.settings/.jsdtscope b/samples/cxf-rest/.settings/.jsdtscope
new file mode 100644
index 0000000..f179e11
--- /dev/null
+++ b/samples/cxf-rest/.settings/.jsdtscope
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/cxf-rest/.settings/org.eclipse.jdt.core.prefs b/samples/cxf-rest/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..cac0df4
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/samples/cxf-rest/.settings/org.eclipse.m2e.core.prefs b/samples/cxf-rest/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/samples/cxf-rest/.settings/org.eclipse.wst.common.component b/samples/cxf-rest/.settings/org.eclipse.wst.common.component
new file mode 100644
index 0000000..3ce380e
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.wst.common.component
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/samples/cxf-rest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml b/samples/cxf-rest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
new file mode 100644
index 0000000..cc81385
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.wst.common.project.facet.core.prefs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/samples/cxf-rest/.settings/org.eclipse.wst.common.project.facet.core.xml b/samples/cxf-rest/.settings/org.eclipse.wst.common.project.facet.core.xml
new file mode 100644
index 0000000..04f221c
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.wst.common.project.facet.core.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/samples/cxf-rest/.settings/org.eclipse.wst.jsdt.ui.superType.container b/samples/cxf-rest/.settings/org.eclipse.wst.jsdt.ui.superType.container
new file mode 100644
index 0000000..3bd5d0a
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.wst.jsdt.ui.superType.container
@@ -0,0 +1 @@
+org.eclipse.wst.jsdt.launching.baseBrowserLibrary
\ No newline at end of file
diff --git a/samples/cxf-rest/.settings/org.eclipse.wst.jsdt.ui.superType.name b/samples/cxf-rest/.settings/org.eclipse.wst.jsdt.ui.superType.name
new file mode 100644
index 0000000..05bd71b
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.wst.jsdt.ui.superType.name
@@ -0,0 +1 @@
+Window
\ No newline at end of file
diff --git a/samples/cxf-rest/.settings/org.eclipse.wst.validation.prefs b/samples/cxf-rest/.settings/org.eclipse.wst.validation.prefs
new file mode 100644
index 0000000..04cad8c
--- /dev/null
+++ b/samples/cxf-rest/.settings/org.eclipse.wst.validation.prefs
@@ -0,0 +1,2 @@
+disabled=06target
+eclipse.preferences.version=1
diff --git a/samples/cxf-rest/pom.xml b/samples/cxf-rest/pom.xml
new file mode 100644
index 0000000..ab5c7f6
--- /dev/null
+++ b/samples/cxf-rest/pom.xml
@@ -0,0 +1,170 @@
+
+
+ 4.0.0
+ com.waylau.cxf
+ cxf-rest
+ Y
+ war
+ Simple CXF JAX-RS webapp service using spring configuration
+ Simple CXF JAX-RS webapp service using spring configuration
+
+ 1.8.6
+
+
+
+ org.apache.cxf
+ cxf-rt-frontend-jaxrs
+ 3.3.5
+
+
+ org.apache.cxf
+ cxf-rt-rs-client
+ 3.3.5
+
+
+ org.codehaus.jackson
+ jackson-core-asl
+ ${jackson.version}
+
+
+ org.codehaus.jackson
+ jackson-mapper-asl
+ ${jackson.version}
+
+
+ org.codehaus.jackson
+ jackson-jaxrs
+ ${jackson.version}
+
+
+ org.springframework
+ spring-web
+ 5.1.12.RELEASE
+
+
+ junit
+ junit
+ 4.13.1
+ test
+
+
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat7-maven-plugin
+ 2.0
+
+
+ default-cli
+
+ run
+
+
+ 13000
+ /jaxrs-service
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+ org.apache.maven.plugins
+ maven-eclipse-plugin
+
+ [artifactId]-[version]
+ true
+ true
+ 2.0
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 1.5
+
+
+ reserve-network-port
+
+ reserve-network-port
+
+ process-test-resources
+
+
+ test.server.port
+
+
+
+
+
+
+ org.apache.tomcat.maven
+ tomcat7-maven-plugin
+
+
+ start-tomcat
+
+ run-war
+
+ pre-integration-test
+
+ ${test.server.port}
+ /jaxrs-service
+ true
+ true
+
+
+
+ stop-tomcat
+
+ shutdown
+
+ post-integration-test
+
+ /jaxrs-service
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+ 2.22.2
+
+
+ integration-test
+
+ integration-test
+
+
+
+ http://localhost:${test.server.port}/jaxrs-service
+
+
+
+
+ verify
+
+ verify
+
+
+
+
+
+
+
diff --git a/samples/cxf-rest/src/main/java/com/waylau/cxf/HelloWorld.java b/samples/cxf-rest/src/main/java/com/waylau/cxf/HelloWorld.java
new file mode 100644
index 0000000..517dcb3
--- /dev/null
+++ b/samples/cxf-rest/src/main/java/com/waylau/cxf/HelloWorld.java
@@ -0,0 +1,29 @@
+package com.waylau.cxf;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Response;
+
+@Path("/hello")
+public class HelloWorld {
+
+ @GET
+ @Path("/echo/{input}")
+ @Produces("text/plain")
+ public String ping(@PathParam("input") String input) {
+ return input;
+ }
+
+ @POST
+ @Produces("application/json")
+ @Consumes("application/json")
+ @Path("/jsonBean")
+ public Response modifyJson(JsonBean input) {
+ input.setVal2(input.getVal1());
+ return Response.ok().entity(input).build();
+ }
+}
+
diff --git a/samples/cxf-rest/src/main/java/com/waylau/cxf/JsonBean.java b/samples/cxf-rest/src/main/java/com/waylau/cxf/JsonBean.java
new file mode 100644
index 0000000..8552532
--- /dev/null
+++ b/samples/cxf-rest/src/main/java/com/waylau/cxf/JsonBean.java
@@ -0,0 +1,24 @@
+package com.waylau.cxf;
+
+
+public class JsonBean {
+ private String val1;
+ private String val2;
+
+ public String getVal1() {
+ return val1;
+ }
+
+ public void setVal1(String val1) {
+ this.val1 = val1;
+ }
+
+ public String getVal2() {
+ return val2;
+ }
+
+ public void setVal2(String val2) {
+ this.val2 = val2;
+ }
+
+}
diff --git a/samples/cxf-rest/src/main/webapp/META-INF/context.xml b/samples/cxf-rest/src/main/webapp/META-INF/context.xml
new file mode 100644
index 0000000..d123dd3
--- /dev/null
+++ b/samples/cxf-rest/src/main/webapp/META-INF/context.xml
@@ -0,0 +1,2 @@
+
+
diff --git a/samples/cxf-rest/src/main/webapp/WEB-INF/beans.xml b/samples/cxf-rest/src/main/webapp/WEB-INF/beans.xml
new file mode 100644
index 0000000..651f11f
--- /dev/null
+++ b/samples/cxf-rest/src/main/webapp/WEB-INF/beans.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/cxf-rest/src/main/webapp/WEB-INF/web.xml b/samples/cxf-rest/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..5a395b2
--- /dev/null
+++ b/samples/cxf-rest/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,28 @@
+
+
+ JAX-RS Simple Service
+ JAX-RS Simple Service
+
+ contextConfigLocation
+ WEB-INF/beans.xml
+
+
+
+ org.springframework.web.context.ContextLoaderListener
+
+
+
+ CXFServlet
+
+ org.apache.cxf.transport.servlet.CXFServlet
+
+ 1
+
+
+ CXFServlet
+ /*
+
+
diff --git a/samples/cxf-rest/src/test/java/com/waylau/cxf/HelloWorldIT.java b/samples/cxf-rest/src/test/java/com/waylau/cxf/HelloWorldIT.java
new file mode 100644
index 0000000..dacde51
--- /dev/null
+++ b/samples/cxf-rest/src/test/java/com/waylau/cxf/HelloWorldIT.java
@@ -0,0 +1,53 @@
+package com.waylau.cxf;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.ws.rs.core.Response;
+
+import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.MappingJsonFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class HelloWorldIT {
+ private static String endpointUrl;
+
+ @BeforeClass
+ public static void beforeClass() {
+ endpointUrl = System.getProperty("service.url");
+ }
+
+ @Test
+ public void testPing() throws Exception {
+ WebClient client =
+ WebClient.create(endpointUrl + "/hello/echo/SierraTangoNevada");
+ Response r = client.accept("text/plain").get();
+ assertEquals(Response.Status.OK.getStatusCode(), r.getStatus());
+ String value = IOUtils.toString((InputStream)r.getEntity());
+ assertEquals("SierraTangoNevada", value);
+ }
+
+ @Test
+ public void testJsonRoundtrip() throws Exception {
+ List