stocks) {
47 | this.stocks = stocks;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return String.format("Investor [id=%s, name=%s, description=%s, stocks=%s]", id, name, description, stocks);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Chapter04/investor-services-v2/src/main/java/com/books/chapters/restfulapi/patterns/chap4/springboot/models/Stock.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap4.springboot.models;
2 |
3 | public class Stock {
4 | private String symbol;
5 | private int numberOfSharesHeld;
6 | private double tickerPrice = 0.0;
7 |
8 | Stock() {
9 | // default constructor, otherwise the spring boot runtime complains that
10 | // it can not instantiate this Stock class when we try to do POST to
11 | // insert a new Stock from the controller classes
12 | }
13 |
14 | public Stock(String symbol, int numberOfSharesHeld, double tickerPrice) {
15 |
16 | this.symbol = symbol;
17 | this.numberOfSharesHeld = numberOfSharesHeld;
18 | this.tickerPrice = tickerPrice;
19 | }
20 |
21 | public String getSymbol() {
22 | return symbol;
23 | }
24 |
25 | public void setSymbol(String symbol) {
26 | this.symbol = symbol;
27 | }
28 |
29 | public int getNumberOfSharesHeld() {
30 | return numberOfSharesHeld;
31 | }
32 |
33 | public void setNumberOfSharesHeld(int numberOfShares) {
34 | this.numberOfSharesHeld = numberOfShares;
35 | }
36 |
37 | public double getTickerPrice() {
38 | return tickerPrice;
39 | }
40 |
41 | public void setTickerPrice(double tickerPrice) {
42 | this.tickerPrice = tickerPrice;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | String pattern = "Stock [symbol: %s, numberOfSharesHeld: %d, tickerPrice: %6.2f]";
48 | return String.format(pattern, symbol, numberOfSharesHeld, tickerPrice);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Chapter04/investor-services-v2/src/main/java/com/books/chapters/restfulapi/patterns/chap4/springboot/models/errorsandexceptions/InvestorNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap4.springboot.models.errorsandexceptions;
2 |
3 | public class InvestorNotFoundException extends RuntimeException{
4 |
5 | private static final long serialVersionUID = 1L;
6 |
7 | public InvestorNotFoundException(String exception)
8 | {
9 | super(exception);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Chapter04/investor-services-v2/src/main/java/com/books/chapters/restfulapi/patterns/chap4/springboot/models/errorsandexceptions/VersionNotSupportedException.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap4.springboot.models.errorsandexceptions;
2 |
3 | public class VersionNotSupportedException extends Exception {
4 | private static final long serialVersionUID = 1L;
5 |
6 | public VersionNotSupportedException(String exception)
7 | {
8 | super(exception);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Chapter04/investor-services-v2/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=9090
--------------------------------------------------------------------------------
/Chapter04/investor-services-v2/src/test/java/com/books/chapters/restfulapi/patterns/chap4/springboot/InvestorServicesApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap4.springboot;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class InvestorServicesApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter04/investor-services-v2/src/test/java/com/books/chapters/restfulapi/patterns/chap4/springboot/controller/InvestorControllerTest.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap4.springboot.controller;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
7 | import org.springframework.boot.test.mock.mockito.MockBean;
8 | import org.springframework.http.MediaType;
9 | import org.springframework.mock.web.MockHttpServletResponse;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 | import org.springframework.test.web.servlet.MockMvc;
12 | import org.springframework.test.web.servlet.MvcResult;
13 | import org.springframework.test.web.servlet.RequestBuilder;
14 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
15 |
16 | import com.books.chapters.restfulapi.patterns.chap4.springboot.controller.InvestorController;
17 | import com.books.chapters.restfulapi.patterns.chap4.springboot.service.InvestorService;
18 |
19 | @RunWith(SpringRunner.class)
20 | @WebMvcTest(value = InvestorController.class, secure = false)
21 | public class InvestorControllerTest {
22 |
23 | @Autowired
24 | private MockMvc mockMvc;
25 |
26 | @MockBean
27 | private InvestorService investorService;
28 |
29 | @Test
30 | public void fetchAllInvestors() throws Exception{
31 | RequestBuilder requestBuilder = MockMvcRequestBuilders.get(
32 | "/investors").accept(
33 | MediaType.APPLICATION_JSON);
34 | MvcResult result = mockMvc.perform(requestBuilder).andReturn();
35 | MockHttpServletResponse response = result.getResponse();
36 | System.out.println("here "+response);
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.books.chapters.restfulapi.patterns.partTwo
7 | oauth2-sample
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | OAuth2 sample
12 | sample spring boot application for the the restful API patterns
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 2.0.5.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 | Finchley.SR1
26 |
27 |
28 |
29 |
30 | org.springframework.boot
31 | spring-boot-starter-security
32 |
33 |
34 | org.springframework.boot
35 | spring-boot-starter-web
36 |
37 |
38 | org.springframework.cloud
39 | spring-cloud-starter-oauth2
40 |
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-test
46 | test
47 |
48 |
49 | org.springframework.security
50 | spring-security-test
51 | test
52 |
53 |
54 | org.springframework.boot
55 | spring-boot-starter-thymeleaf
56 |
57 |
58 |
59 |
60 |
61 |
62 | org.springframework.cloud
63 | spring-cloud-dependencies
64 | ${spring-cloud.version}
65 | pom
66 | import
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | org.springframework.boot
75 | spring-boot-maven-plugin
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/java/com/books/chapters/restfulapi/patterns/advanced/oauth/AuthorizacionServerConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.advanced.oauth;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.beans.factory.annotation.Qualifier;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.context.annotation.Configuration;
7 | import org.springframework.security.authentication.AuthenticationManager;
8 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
9 | import org.springframework.security.crypto.password.PasswordEncoder;
10 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
11 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
12 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
13 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
14 | import org.springframework.security.oauth2.provider.token.TokenStore;
15 | import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
16 |
17 | @Configuration
18 | @EnableAuthorizationServer
19 | public class AuthorizacionServerConfiguration extends AuthorizationServerConfigurerAdapter {
20 |
21 | @Autowired
22 | @Qualifier("authenticationManagerBean")
23 | private AuthenticationManager authenticationManager;
24 |
25 | @Autowired
26 | private TokenStore tokenStore;
27 |
28 |
29 | @Override
30 | public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
31 |
32 | clients.inMemory()
33 | .withClient("client")
34 | .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
35 | .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT","USER")
36 | .scopes("read","write")
37 | .autoApprove(true)
38 | .secret(passwordEncoder().encode("client-secret1@3"));
39 |
40 | }
41 |
42 | @Bean
43 | public PasswordEncoder passwordEncoder() {
44 | return new BCryptPasswordEncoder();
45 | }
46 | @Override
47 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
48 | endpoints
49 | .authenticationManager(authenticationManager)
50 | .tokenStore(tokenStore);
51 | }
52 |
53 | @Bean
54 | public TokenStore tokenStore() {
55 | return new InMemoryTokenStore();
56 | }
57 | //
58 | }
59 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/java/com/books/chapters/restfulapi/patterns/advanced/oauth/ResourceServerConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.advanced.oauth;
2 |
3 |
4 |
5 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
6 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
7 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
8 | import org.springframework.web.bind.annotation.RequestMapping;
9 | import org.springframework.web.bind.annotation.RestController;
10 |
11 |
12 | @EnableResourceServer
13 | @RestController
14 | public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter
15 | {
16 | @RequestMapping("/try")
17 | public String welcome() {
18 | return "Welcome";
19 | }
20 | @RequestMapping("/userService")
21 | public String userService() {
22 | return "Users";
23 | }
24 | @RequestMapping("/admin")
25 | public String admin() {
26 | return "Administrator";
27 | }
28 | @Override
29 | public void configure(HttpSecurity http) throws Exception {
30 | http
31 | .authorizeRequests().antMatchers("/oauth/token", "/oauth/authorize**", "/try").permitAll();
32 | http.requestMatchers().antMatchers("/userService")
33 | .and().authorizeRequests()
34 | .antMatchers("/userService").access("hasRole('USER')")
35 | .and().requestMatchers().antMatchers("/admin")
36 | .and().authorizeRequests()
37 | .antMatchers("/admin").access("hasRole('ADMIN')");
38 | }
39 |
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/java/com/books/chapters/restfulapi/patterns/advanced/oauth/WebController.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.advanced.oauth;
2 |
3 | import org.springframework.stereotype.Controller;
4 | import org.springframework.web.bind.annotation.RequestMapping;
5 |
6 | @Controller
7 | public class WebController {
8 |
9 | @RequestMapping({"/","index"})
10 | public String index() {
11 | return "index";
12 | }
13 |
14 | @RequestMapping("/users")
15 | public String users() {
16 | return "users";
17 | }
18 | @RequestMapping("/welcome")
19 | public String welcome() {
20 | return "welcome";
21 | }
22 | @RequestMapping("/webadmin")
23 | public String admin() {
24 | return "admin";
25 | }
26 | @RequestMapping("/login")
27 | public String login() {
28 | return "login";
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/java/com/books/chapters/restfulapi/patterns/advanced/oauth/WebSecurityConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.advanced.oauth;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.Bean;
6 | import org.springframework.security.authentication.AuthenticationManager;
7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
8 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
9 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
10 | import org.springframework.security.core.userdetails.User;
11 | import org.springframework.security.core.userdetails.UserDetails;
12 | import org.springframework.security.core.userdetails.UserDetailsService;
13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
14 | import org.springframework.security.crypto.password.PasswordEncoder;
15 | import org.springframework.security.provisioning.InMemoryUserDetailsManager;
16 |
17 |
18 | @SpringBootApplication
19 | @EnableWebSecurity
20 | public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
21 |
22 | public static void main(String[] args) {
23 | SpringApplication.run(WebSecurityConfiguration.class, args);
24 | }
25 |
26 | @Bean
27 | @Override
28 | public AuthenticationManager authenticationManagerBean() throws Exception {
29 | return super.authenticationManagerBean();
30 | }
31 |
32 | @Bean
33 | @Override
34 | public UserDetailsService userDetailsService() {
35 |
36 | UserDetails user1=User.builder().username("user1").password(passwordEncoder().encode("secret!23")).
37 | roles("USER").build();
38 | UserDetails user2=User.builder().username("user2").password(passwordEncoder().encode("secret1@3")).
39 | roles("USER").build();
40 | UserDetails adminUser=User.builder().username("admin").password(passwordEncoder().encode("secret@dmin")).
41 | roles("ADMIN").build();
42 | return new InMemoryUserDetailsManager(user1, user2, adminUser);
43 | }
44 | @Bean
45 | public PasswordEncoder passwordEncoder() {
46 | return new BCryptPasswordEncoder();
47 | }
48 |
49 |
50 | @Override
51 | protected void configure(HttpSecurity http) throws Exception {
52 | http
53 | .csrf().disable()
54 | .authorizeRequests()
55 | .antMatchers("/","/index","/welcome").permitAll()
56 | .antMatchers("/users").authenticated()
57 | .antMatchers("/webadmin").hasRole("ADMIN").and()
58 | .formLogin()
59 | .loginPage("/login")
60 | .permitAll()
61 | .and()
62 | .logout()
63 | .permitAll();
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/application.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Hands-On-RESTful-API-Design-Patterns-and-Best-Practices/92544a10bee84b777c98b3fc6cd38a5a8e886066/Chapter06/oauth2-sample/src/main/resources/application.properties
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/application1.yml:
--------------------------------------------------------------------------------
1 | security:
2 | oauth2:
3 | client:
4 | client-id: client
5 | client-secret: client-secret1@3
6 | scope: read,write
7 | auto-approve-scopes: '.*'
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/templates/admin.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | OAuth2 sample
6 |
7 |
8 | OAuth 2 Sample
9 | you are viewing a administrator page as you are using your administrator credentials
10 |
11 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | OAuth 2 Sample
6 |
7 |
8 | Home
9 | Please here to see a public page.
10 | Noraml user click here to see your allowed pages
11 | Administrator user click here to go to admin section
12 |
13 | Hello
someone
14 |
logout
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/templates/login.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | Spring Security Example
6 |
7 |
8 |
9 | Invalid username and password.
10 |
11 |
12 | You have been logged out.
13 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/templates/users.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | OAuth2 sample
6 |
7 |
8 | user page
9 | you are viewing a your (private) page as you are using your user credentials
10 |
11 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/main/resources/templates/welcome.html:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | OAtuh2 sample
6 |
7 |
8 | Welcome
9 | you are viewing a welcome page and this page doesen't need any credentials
10 |
11 |
--------------------------------------------------------------------------------
/Chapter06/oauth2-sample/src/test/java/com/books/chapters/restfulapi/patterns/advanced/oauth/WebSecurityConfigurationTests.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.advanced.oauth;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class WebSecurityConfigurationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Chapter06/test.txt:
--------------------------------------------------------------------------------
1 | initial commit
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.books.chapters.restfulapi.patterns.parttwo
6 | amqp-adapter-module
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | amqp-adapter-module
11 | http://maven.apache.org
12 |
13 |
14 | UTF-8
15 | 1.8
16 | 1.8
17 | 1.8
18 | 2.0.2.RELEASE
19 | 3.8.1
20 | 2.1
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-starter-parent
25 | 1.4.4.RELEASE
26 |
27 |
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-dependencies
33 | ${springBoot.version}
34 | pom
35 | import
36 |
37 |
38 |
39 |
40 |
41 |
42 | org.springframework.boot
43 | spring-boot-starter-actuator
44 |
45 |
46 |
47 | org.springframework.boot
48 | spring-boot-starter-amqp
49 |
50 |
51 | org.apache.commons
52 | commons-lang3
53 |
54 |
55 | javax.validation
56 | validation-api
57 |
58 |
59 | junit
60 | junit
61 |
62 |
63 | javax.ws.rs
64 | javax.ws.rs-api
65 | ${ws.rs.api.version}
66 |
67 |
68 |
69 |
70 |
71 | org.jsonschema2pojo
72 | jsonschema2pojo-maven-plugin
73 | 0.5.1
74 |
75 | true
76 | ${basedir}/src/main/resources/schemas
77 | com.books.chapters.restfulapi.patterns.parttwo.adapter.entity
78 | ${basedir}/generated-src
79 | true
80 | true
81 | true
82 | true
83 |
84 |
85 |
86 |
87 | generate
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/App.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo;
2 |
3 | /**
4 | * Hello world!
5 | *
6 | */
7 | public class App
8 | {
9 | public static void main( String[] args )
10 | {
11 | System.out.println( "Hello World!" );
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/consumer/AmqpSubscriber.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.consumer;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 |
8 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest;
9 |
10 | public class AmqpSubscriber {
11 | private static final Logger LOG = LoggerFactory.getLogger(AmqpSubscriber.class);
12 |
13 | @Autowired
14 | EventHandler eventHandler;
15 |
16 | @RabbitListener(queues = "#{eventQueue.name}")
17 | public void process(ServiceRequest request) {
18 | LOG.trace("Subscribed event: {}", request);
19 | LOG.trace("Handled by: {}", eventHandler.getClass());
20 | eventHandler.processEvent(request);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/consumer/Configurations.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.consumer;
2 |
3 | import java.util.HashMap;
4 | import java.util.List;
5 | import java.util.Map;
6 | import java.util.stream.Collectors;
7 | import java.util.stream.Stream;
8 |
9 | import org.springframework.amqp.core.Binding;
10 | import org.springframework.amqp.core.BindingBuilder;
11 | import org.springframework.amqp.core.Queue;
12 | import org.springframework.amqp.core.TopicExchange;
13 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
14 | import org.springframework.amqp.support.converter.MessageConverter;
15 | import org.springframework.beans.factory.annotation.Autowired;
16 | import org.springframework.context.annotation.Bean;
17 | import org.springframework.context.annotation.Configuration;
18 | import org.springframework.context.annotation.Profile;
19 |
20 |
21 | @Profile({ "amqp-consumer" })
22 | @Configuration
23 | public class Configurations {
24 | private Map exchanegMap = new HashMap<>();
25 |
26 | @Autowired
27 | RabbitMqConfig rabbitMqConfig;
28 |
29 | @Bean
30 | public MessageConverter jsonMessageConverter() {
31 | return new Jackson2JsonMessageConverter();
32 | }
33 |
34 | @Bean
35 | public Queue serviceQueue() {
36 | return new Queue(rabbitMqConfig.getServiceQueueName());
37 | }
38 |
39 | @Bean
40 | public List exchanges() {
41 | return Stream.concat(serviceExchanges().stream(), eventExchanges().stream()).collect(Collectors.toList());
42 | }
43 |
44 | @Bean
45 | public List bindings() {
46 | return Stream.concat(serviceBindings().stream(), eventBindings().stream()).collect(Collectors.toList());
47 | }
48 |
49 | @Bean
50 | public RpcServer server() {
51 | return new RpcServer();
52 | }
53 |
54 | @Bean
55 | public Queue eventQueue() {
56 | return new Queue(rabbitMqConfig.getEventQueueName());
57 | }
58 |
59 | @Bean
60 | public AmqpSubscriber subscriber() {
61 | return new AmqpSubscriber();
62 | }
63 |
64 | private List serviceExchanges() {
65 | return rabbitMqConfig.getServiceRoutings().stream().map(rabbitMqConfig::getExchangeName).map(e -> {
66 | TopicExchange exchange = new TopicExchange(e);
67 | exchanegMap.put(e, exchange);
68 | return exchange;
69 | }).collect(Collectors.toList());
70 | }
71 |
72 | private List eventExchanges() {
73 | return rabbitMqConfig.getEventRoutings().stream().map(rabbitMqConfig::getExchangeName).map(e -> {
74 | TopicExchange exchange = new TopicExchange(e);
75 | exchanegMap.put(e, exchange);
76 | return exchange;
77 | }).collect(Collectors.toList());
78 | }
79 |
80 | private List serviceBindings() {
81 | return rabbitMqConfig
82 | .getServiceRoutings().stream().map(r -> BindingBuilder.bind(serviceQueue())
83 | .to(exchanegMap.get(rabbitMqConfig.getExchangeName(r))).with(rabbitMqConfig.getRoutingKey(r)))
84 | .collect(Collectors.toList());
85 | }
86 |
87 | private List eventBindings() {
88 | return rabbitMqConfig
89 | .getEventRoutings().stream().map(r -> BindingBuilder.bind(eventQueue())
90 | .to(exchanegMap.get(rabbitMqConfig.getExchangeName(r))).with(rabbitMqConfig.getRoutingKey(r)))
91 | .collect(Collectors.toList());
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/consumer/EventHandler.java:
--------------------------------------------------------------------------------
1 |
2 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.consumer;
3 |
4 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest;
5 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
6 |
7 |
8 | public interface EventHandler {
9 | public ServiceResponse processRequest(ServiceRequest request);
10 |
11 | public void processEvent(ServiceRequest request);
12 | }
13 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/consumer/RabbitMqConfig.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.consumer;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import org.springframework.boot.context.properties.ConfigurationProperties;
7 | import org.springframework.context.annotation.Configuration;
8 |
9 | @Configuration
10 | @ConfigurationProperties(prefix = "spring.rabbitmq")
11 | public class RabbitMqConfig {
12 | private static final String DEFAULT_EVENT_QUEUE = "DefaultEventQueue";
13 | private static final String DEFAULT_SERVICE_QUEUE = "DefaultServiceQueue";
14 | private List serviceRoutings = new ArrayList<>();
15 | private List eventRoutings = new ArrayList<>();
16 |
17 | public List getServiceRoutings() {
18 | return this.serviceRoutings;
19 | }
20 |
21 | public List getEventRoutings() {
22 | return this.eventRoutings;
23 | }
24 |
25 | public String getServiceQueueName() {
26 | return serviceRoutings.stream().findFirst().map(this::getQueue).orElse(DEFAULT_SERVICE_QUEUE);
27 | }
28 |
29 | public String getEventQueueName() {
30 | return eventRoutings.stream().findFirst().map(this::getQueue).orElse(DEFAULT_EVENT_QUEUE);
31 | }
32 |
33 | public String getExchangeName(String routing) {
34 | return routing.split("->")[0];
35 | }
36 |
37 | public String getRoutingKey(String routing) {
38 | return routing.split("->")[1];
39 | }
40 |
41 | public String getQueue(String routing) {
42 | return routing.split("->")[2];
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/consumer/RpcServer.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.consumer;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.amqp.rabbit.annotation.RabbitListener;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 |
8 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest;
9 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
10 |
11 | public class RpcServer {
12 | private static final Logger LOG = LoggerFactory.getLogger(RpcServer.class);
13 |
14 | @Autowired
15 | EventHandler eventHandler;
16 |
17 | @RabbitListener(queues = "#{serviceQueue.name}")
18 | public ServiceResponse process(ServiceRequest request) {
19 | LOG.trace("RPC service request: {}", request);
20 | LOG.trace("Handled by: {}", eventHandler.getClass());
21 | return eventHandler.processRequest(request);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/producer/AmqpPublisher.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer;
2 |
3 | import org.slf4j.Logger;
4 | import org.slf4j.LoggerFactory;
5 | import org.springframework.amqp.core.TopicExchange;
6 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 |
9 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest;
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
11 |
12 | public class AmqpPublisher {
13 | private static final Logger LOG = LoggerFactory.getLogger(AmqpPublisher.class);
14 |
15 | @Autowired
16 | private RabbitTemplate template;
17 |
18 | @Autowired
19 | private TopicExchange pubExchange;
20 |
21 | public void publishEvent(ServiceRequest request) {
22 | LOG.trace("Exchange: {} ", pubExchange);
23 | LOG.trace("Service Request: {}", request);
24 | String routingKey = request.getServiceName() + "." + request.getServiceAction();
25 | template.convertAndSend(pubExchange.getName(), routingKey, request);
26 | }
27 |
28 | public void publishError(ServiceResponse errorResponse, String routingKey) {
29 | LOG.trace("Exchange: {}", pubExchange);
30 | LOG.trace("Service Error: {}", errorResponse);
31 | template.convertAndSend(pubExchange.getName(), routingKey, errorResponse);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/producer/ProducerConfigurations.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer;
2 |
3 | import org.springframework.amqp.core.TopicExchange;
4 | import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
5 | import org.springframework.amqp.support.converter.MessageConverter;
6 | import org.springframework.beans.factory.annotation.Value;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.context.annotation.Profile;
10 |
11 | @Profile({ "amqp-producer" })
12 | @Configuration
13 | public class ProducerConfigurations {
14 | @Value("${spring.rabbitmq.exchange.rpc}")
15 | private String exchangeRpc;
16 |
17 | @Value("${spring.rabbitmq.exchange.pub}")
18 | public String exchangePub;
19 |
20 | @Bean
21 | public TopicExchange rpcExchange() {
22 | return new TopicExchange(exchangeRpc);
23 | }
24 |
25 | @Bean
26 | public RpcClient rpcClient() {
27 | return new RpcClient();
28 | }
29 |
30 | @Bean
31 | public TopicExchange pubExchange() {
32 | return new TopicExchange(exchangePub);
33 | }
34 |
35 | @Bean
36 | public AmqpPublisher pubClient() {
37 | return new AmqpPublisher();
38 |
39 | }
40 |
41 | @Bean
42 | public MessageConverter jsonMessageConverter() {
43 | return new Jackson2JsonMessageConverter();
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/adapter/amqp/producer/RpcClient.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer;
2 |
3 | import java.util.Date;
4 | import java.util.Optional;
5 | import java.util.UUID;
6 |
7 | import javax.ws.rs.core.Response;
8 |
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.amqp.core.TopicExchange;
12 | import org.springframework.amqp.rabbit.core.RabbitTemplate;
13 | import org.springframework.beans.factory.annotation.Autowired;
14 |
15 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ErrorMessage;
16 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest;
17 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
18 |
19 | public class RpcClient {
20 | private static final Logger LOG = LoggerFactory.getLogger(RpcClient.class);
21 |
22 | @Autowired
23 | private RabbitTemplate template;
24 |
25 | @Autowired
26 | private TopicExchange rpcExchange;
27 |
28 | public ServiceResponse invokeService(ServiceRequest request) {
29 | LOG.trace("Exchange: {} ", rpcExchange);
30 | LOG.trace("Service Request: {}", request);
31 | String routingKey = request.getServiceName() + "." + request.getServiceAction();
32 | ServiceResponse response = (ServiceResponse) template.convertSendAndReceive(rpcExchange.getName(), routingKey,
33 | request);
34 | LOG.trace("Service Response: {}", response);
35 | return Optional.ofNullable(response).orElse(generateTimedoutResponse(request));
36 | }
37 |
38 | private ServiceResponse generateTimedoutResponse(ServiceRequest request) {
39 | ServiceResponse response = new ServiceResponse().withId(UUID.randomUUID().toString()).withCreatedBy("System")
40 | .withCreatedDate(new Date())
41 | .withErrorMessage(new ErrorMessage().withCode("ERR_SERVICE_UNAVAIL").withMessage("Service Unavaialble")
42 | .withDetails("Internal Error: we are sorry, the " + request.getServiceName()
43 | + " is not reachable. Please try again later."))
44 | .withStatusCode(Response.Status.SERVICE_UNAVAILABLE.toString()).withRelatedRequest(request.getId());
45 | LOG.trace("Service timeout response: {}", response);
46 | return response;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/resources/schemas/BusinessEntity.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "id": "BusinessEntity.json",
4 | "title": "BusinessEntity",
5 | "description": "Business entity model",
6 | "type": "object",
7 | "javaType": "com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity",
8 | "additionalProperties": false,
9 | "properties": {
10 | "id": {
11 | "type": "string"
12 | },
13 | "entityType": {
14 | "type": "string"
15 | },
16 | "entitySpecification": {
17 | "type": "string"
18 | },
19 | "name": {
20 | "type": "string"
21 | },
22 | "status": {
23 | "type": "string"
24 | },
25 | "relatedEntities": {
26 | "type": "array",
27 | "items": {
28 | "$ref": "BusinessEntity.json#"
29 | }
30 | }
31 | },
32 | "required": [
33 | "id"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/resources/schemas/ErrorMessage.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "id": "ErrorMessage.json",
4 | "title": "ErrorMessage",
5 | "description": "Errors",
6 | "type": "object",
7 | "javaType": "com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ErrorMessage",
8 | "additionalProperties": false,
9 | "properties": {
10 | "code": {
11 | "type": "string",
12 | "description": "error code short desc."
13 | },
14 | "message": {
15 | "type": "string",
16 | "description": "error message."
17 | },
18 | "details": {
19 | "type": "string",
20 | "description": "error description."
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/resources/schemas/ServiceRequest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "id": "ServiceRequest.json",
4 | "title": "Service Request",
5 | "type": "object",
6 | "javaType": "com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest",
7 | "additionalProperties": false,
8 | "properties": {
9 | "id": {
10 | "type": "string"
11 | },
12 | "serviceName": {
13 | "type": "string"
14 | },
15 | "serviceAction": {
16 | "type": "string"
17 | },
18 | "createdDate": {
19 | "type": "string",
20 | "format": "date-time"
21 | },
22 | "createdBy": {
23 | "type": "string",
24 | "description": "The user or system who created this request"
25 | },
26 | "items": {
27 | "type": "array",
28 | "items": {
29 | "$ref": "BusinessEntity.json#"
30 | }
31 | }
32 | },
33 | "required": [
34 | "id",
35 | "serviceName",
36 | "serviceAction",
37 | "items"
38 | ]
39 | }
40 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/main/resources/schemas/ServiceResponse.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-06/schema#",
3 | "id": "ServiceResponse.json",
4 | "title": "Service Response",
5 | "type": "object",
6 | "javaType": "com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse",
7 | "additionalProperties": false,
8 | "properties": {
9 | "id": {
10 | "type": "string"
11 | },
12 | "relatedRequest": {
13 | "type": "string"
14 | },
15 | "createdDate": {
16 | "type": "string",
17 | "format": "date-time"
18 | },
19 | "createdBy": {
20 | "type": "string",
21 | "description": "The user or system who created this response"
22 | },
23 | "statusCode": {
24 | "type": "string",
25 | "description": "The status code indicating service invocation is successful or not"
26 | },
27 | "errorMessage": {
28 | "$ref": "ErrorMessage.json#"
29 | },
30 | "items": {
31 | "type": "array",
32 | "items": {
33 | "$ref": "BusinessEntity.json#"
34 | }
35 | }
36 | },
37 | "required": [
38 | "id",
39 | "relatedRequest"
40 | ]
41 | }
42 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/amqp-adapter-module/src/test/java/com/books/chapters/restfulapi/patterns/parttwo/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/pom.xml:
--------------------------------------------------------------------------------
1 |
5 | 4.0.0
6 |
7 | com.books.chapters.restfulapi.patterns.parttwo
8 | event-driven-service-orchestration
9 | pom
10 | 1.0-SNAPSHOT
11 | Event driven service orchestration
12 |
13 |
14 | amqp-adapter-module
15 | service-stubs-module
16 | shopping-cart
17 |
18 |
19 |
20 |
21 |
22 |
23 | org.apache.maven.plugins
24 | maven-compiler-plugin
25 |
26 | 1.8
27 | 1.8
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | junit
37 | junit
38 | 3.8.1
39 | test
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/service-stubs-module/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.books.chapters.restfulapi.patterns.parttwo
6 | service-stubs-modules
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | service-stubs-modules
11 | http://maven.apache.org
12 |
13 |
14 | UTF-8
15 | 2.0.2.RELEASE
16 | 3.8.1
17 |
18 |
19 | org.springframework.boot
20 | spring-boot-starter-parent
21 | 1.4.4.RELEASE
22 |
23 |
24 |
25 |
26 |
27 | org.springframework.boot
28 | spring-boot-dependencies
29 | ${springBoot.version}
30 | pom
31 | import
32 |
33 |
34 |
35 |
36 |
37 | junit
38 | junit
39 | test
40 |
41 |
42 | com.books.chapters.restfulapi.patterns.parttwo
43 | amqp-adapter-module
44 | 0.0.1-SNAPSHOT
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/service-stubs-module/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/stub/StubServiceApplication.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.stub;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 | import org.springframework.context.annotation.ComponentScan;
6 |
7 | @SpringBootApplication
8 | @ComponentScan("com.books.chapters.restfulapi.patterns.parttwo")
9 | public class StubServiceApplication {
10 |
11 | public static void main(String[] args) {
12 | SpringApplication.run(StubServiceApplication.class, args);
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/service-stubs-module/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | spring:
2 | profiles: default
3 | rabbitmq:
4 | host: localhost
5 | port: 5777
6 | username: test
7 | password: test
8 |
9 | ---
10 |
11 | spring:
12 | profiles: location
13 | include:
14 | - default
15 | rabbitmq:
16 | serviceRoutings:
17 | - shoppingcart.rpc->LocationService.*->LocationServiceQueue
18 | - customer.rpc->LocationService.*->LocationServiceQueue
19 | eventRoutings:
20 | - shoppingcart.pub->LocationService.*->LocationEventQueue
21 | - customer.pub->LocationService.*->LocationEventQueue
22 |
23 | ---
24 |
25 | spring:
26 | profiles: payment
27 | include:
28 | - default
29 | rabbitmq:
30 | serviceRoutings:
31 | - shoppingcart.rpc->PaymentService.*->PaymentServiceQueue
32 | - customer.rpc->PaymentService.*->PaymentServiceQueue
33 |
34 | ---
35 |
36 | spring:
37 | profiles: inventory
38 | include:
39 | - default
40 | rabbitmq:
41 | serviceRoutings:
42 | - shoppingcart.rpc->InventoryService.*->InventoryServiceQueue
43 | - catalog.rpc->InventoryService.*->InventoryServiceQueue
44 |
45 | ---
46 |
47 | spring:
48 | profiles: order
49 | include:
50 | - default
51 | rabbitmq:
52 | serviceRoutings:
53 | - shoppingcart.rpc->OrderService.*->OrderServiceQueue
54 | - customer.rpc->OrderService.*->OrderServiceQueue
55 |
56 | ---
57 |
58 | spring:
59 | profiles: customer
60 | include:
61 | - default
62 | rabbitmq:
63 | serviceRoutings:
64 | - shoppingcart.rpc->CustomerService.*->CustomerServiceQueue
65 | eventRoutings:
66 | - shoppingcart.pub->CustomerService.*->CustomerEventQueue
67 |
68 | ---
69 |
70 | spring:
71 | profiles: backoffice
72 | include:
73 | - default
74 | rabbitmq:
75 | eventRoutings:
76 | - shoppingcart.pub->BackofficeService.notify->BackofficeEventQueue
77 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/service-stubs-module/src/test/java/com/books/chapters/restfulapi/patterns/parttwo/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.books.chapters.restfulapi.patterns.parttwo
6 | shopping-cart
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | shopping-cart
11 | http://maven.apache.org
12 |
13 |
14 | UTF-8
15 | 2.1.1.RELEASE
16 | 3.8.1
17 | 2.3.0
18 | 3.8.0
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-parent
23 | 1.4.4.RELEASE
24 |
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-dependencies
31 | ${springBoot.version}
32 | pom
33 | import
34 |
35 |
36 |
37 |
38 |
39 |
40 | com.books.chapters.restfulapi.patterns.parttwo
41 | amqp-adapter-module
42 | 0.0.1-SNAPSHOT
43 |
44 |
45 | org.camunda.bpm.springboot
46 | camunda-bpm-spring-boot-starter-webapp
47 | ${camundaSpringBoot.version}
48 |
49 |
50 | com.h2database
51 | h2
52 |
53 |
54 | org.camunda.bpm.springboot
55 | camunda-bpm-spring-boot-starter-rest
56 | ${camundaSpringBoot.version}
57 |
58 |
59 | org.springframework.boot
60 | spring-boot-starter-data-jpa
61 |
62 |
63 |
64 |
65 |
66 |
67 | org.apache.maven.plugins
68 | maven-compiler-plugin
69 | ${maven.compiler.plugin.version}
70 |
71 | 1.8
72 | 1.8
73 |
74 |
75 |
76 | org.springframework.boot
77 | spring-boot-maven-plugin
78 | ${springBoot.version}
79 |
80 |
81 |
82 | repackage
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/ShoppingCartServiceApp.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo;
2 |
3 | import org.camunda.bpm.spring.boot.starter.annotation.EnableProcessApplication;
4 | import org.springframework.boot.SpringApplication;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 |
7 | @SpringBootApplication
8 | @EnableProcessApplication
9 | public class ShoppingCartServiceApp {
10 |
11 | public static void main(String... args) {
12 | SpringApplication.run(ShoppingCartServiceApp.class, args);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/AllocateInventoryActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 |
15 | @Component
16 | public class AllocateInventoryActivity implements JavaDelegate {
17 | private static final Logger LOG = LoggerFactory.getLogger(AllocateInventoryActivity.class);
18 |
19 | public static final String SERVICE_ACTION = "allocate";
20 |
21 | @Autowired
22 | RpcClient rpcClient;
23 |
24 | @Override
25 | public void execute(DelegateExecution execution) throws Exception {
26 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_INVENTORY, SERVICE_ACTION);
27 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
28 | ServiceResponse response = rpcClient.invokeService(
29 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_INVENTORY, SERVICE_ACTION));
30 | ProcessUtil.processResponse(execution, response);
31 | execution.setVariable(ProcessConstants.VAR_INVENTORY_ALLOCATED, true);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/CancelOrderActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 |
15 | @Component
16 | public class CancelOrderActivity implements JavaDelegate {
17 | private static final Logger LOG = LoggerFactory.getLogger(CancelOrderActivity.class);
18 |
19 | public static final String SERVICE_ACTION = "cancel";
20 |
21 | @Autowired
22 | RpcClient rpcClient;
23 |
24 | @Override
25 | public void execute(DelegateExecution execution) throws Exception {
26 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_ORDER, SERVICE_ACTION);
27 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
28 | ServiceResponse response = rpcClient.invokeService(
29 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_ORDER, SERVICE_ACTION));
30 | ProcessUtil.processResponse(execution, response);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/CloseShoppingCartActivity.java:
--------------------------------------------------------------------------------
1 |
2 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
3 |
4 | import org.camunda.bpm.engine.delegate.DelegateExecution;
5 | import org.camunda.bpm.engine.delegate.JavaDelegate;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.stereotype.Component;
10 |
11 | import com.books.chapters.restfulapi.patterns.parttwo.dataaccess.ShoppingCartManager;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
13 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
14 |
15 |
16 | @Component
17 | public class CloseShoppingCartActivity implements JavaDelegate {
18 | private static final Logger LOG = LoggerFactory.getLogger(CloseShoppingCartActivity.class);
19 | public static final String SERVICE_ACTION = "close";
20 |
21 | @Autowired
22 | ShoppingCartManager shoppingCartManager;
23 |
24 | @Override
25 | public void execute(DelegateExecution ctx) throws Exception {
26 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_SHOPPINGCART, SERVICE_ACTION);
27 | BusinessEntity sc = (BusinessEntity) ctx.getVariable(ProcessConstants.VAR_SC);
28 | ServiceResponse response = shoppingCartManager.closeShoppingCart(sc);
29 | ProcessUtil.processResponse(ctx, response);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/NotifyCustomerActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.AmqpPublisher;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 |
13 |
14 | @Component
15 | public class NotifyCustomerActivity implements JavaDelegate {
16 | private static final Logger LOG = LoggerFactory.getLogger(NotifyCustomerActivity.class);
17 |
18 | public static final String SERVICE_ACTION = "notify";
19 |
20 | @Autowired
21 | AmqpPublisher amqpPubClient;
22 |
23 | @Override
24 | public void execute(DelegateExecution execution) throws Exception {
25 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_CUSTOMER, SERVICE_ACTION);
26 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
27 | amqpPubClient.publishEvent(
28 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_CUSTOMER, SERVICE_ACTION));
29 | execution.setVariable(ProcessConstants.VAR_RESPONSE, sc);
30 | ProcessContext ctx = (ProcessContext) execution.getVariable(ProcessConstants.VAR_CTX);
31 | ctx.setResponse(sc);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/PlaceOrderActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 |
15 | @Component
16 | public class PlaceOrderActivity implements JavaDelegate {
17 | private static final Logger LOG = LoggerFactory.getLogger(PlaceOrderActivity.class);
18 |
19 | public static final String SERVICE_ACTION = "initiate";
20 |
21 | @Autowired
22 | RpcClient rpcClient;
23 |
24 | @Override
25 | public void execute(DelegateExecution execution) throws Exception {
26 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_ORDER, SERVICE_ACTION);
27 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
28 | ServiceResponse response = rpcClient.invokeService(
29 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_ORDER, SERVICE_ACTION));
30 | ProcessUtil.processResponse(execution, response);
31 | execution.setVariable(ProcessConstants.VAR_ORDER_PLACED, true);
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ProcessConstants.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | public final class ProcessConstants {
4 |
5 | public static final String PROCESS_KEY_SUBMIT_SC = "submitShoppingCart";
6 |
7 | public static final String VAR_CTX = "context";
8 | public static final String VAR_SC_ID = "shoppingCartId";
9 | public static final String VAR_ADDRESS = "address";
10 | public static final String VAR_PAYMENT = "payment";
11 | public static final String VAR_SC = "shoppingCart";
12 | public static final String VAR_PRODUCT = "product";
13 | public static final String VAR_RESPONSE = "response";
14 | public static final String VAR_PAYMENT_RESERVED = "paymentReserved";
15 | public static final String VAR_INVENTORY_ALLOCATED = "inventoryAllocated";
16 | public static final String VAR_ORDER_PLACED = "orderPlaced";
17 |
18 | public static final String SERVICE_NAME_LOCATION = "LocationService";
19 | public static final String SERVICE_NAME_PAYMENT = "PaymentService";
20 | public static final String SERVICE_NAME_INVENTORY = "InventoryService";
21 | public static final String SERVICE_NAME_ORDER = "OrderService";
22 | public static final String SERVICE_NAME_CUSTOMER = "CustomerService";
23 | public static final String SERVICE_NAME_BACKOFFICE = "BackofficeService";
24 | public static final String SERVICE_NAME_SHOPPINGCART = "ShoppingCartService";
25 |
26 | public static final String ENTITY_TYPE_SHOPPINGCART = "SHOPPINGCART";
27 | public static final String ENTITY_TYPE_LOCATION = "LOCATION";
28 | public static final String ENTITY_TYPE_PAYMENT = "PAYMENT";
29 | public static final String ENTITY_TYPE_PRODUCT = "PRODUCT";
30 | public static final String ENTITY_TYPE_ERROR = "ERROR";
31 |
32 | public static final String SC_STATUS_OPEN = "OPEN";
33 | public static final String SC_STATUS_CLOSED = "CLOSED";
34 |
35 | public static final String UNKNOWN = "UNKNOWN";
36 |
37 | private ProcessConstants() {
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ProcessContext.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import java.io.Serializable;
4 |
5 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
6 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ErrorMessage;
7 |
8 | public class ProcessContext implements Serializable {
9 | private static final long serialVersionUID = 1L;
10 | private BusinessEntity response;
11 |
12 | public BusinessEntity getResponse() {
13 | return response;
14 | }
15 |
16 | public void setResponse(BusinessEntity response) {
17 | this.response = response;
18 | }
19 |
20 | public ErrorMessage getError() {
21 | return error;
22 | }
23 |
24 | public void setError(ErrorMessage error) {
25 | this.error = error;
26 | }
27 |
28 | private ErrorMessage error;
29 | }
30 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ProcessUtil.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Date;
5 | import java.util.List;
6 | import java.util.stream.Collectors;
7 |
8 | import javax.ws.rs.core.Response;
9 |
10 | import org.camunda.bpm.engine.delegate.BpmnError;
11 | import org.camunda.bpm.engine.delegate.DelegateExecution;
12 |
13 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
14 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceRequest;
15 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
16 |
17 | public class ProcessUtil {
18 | private static final String SC_ERROR = "SC_ERROR";
19 |
20 | private ProcessUtil() {
21 | }
22 |
23 | public static ServiceRequest buildServiceRequest(BusinessEntity shoppingCart, String serviceName,
24 | String serviceAction) {
25 | ServiceRequest sr = new ServiceRequest().withId(shoppingCart.getId()).withCreatedBy(serviceName)
26 | .withCreatedDate(new Date()).withServiceName(serviceName).withServiceAction(serviceAction);
27 | String entityType = getEntityTypeForService(serviceName);
28 | if (ProcessConstants.ENTITY_TYPE_SHOPPINGCART.equals(entityType)) {
29 | List items = new ArrayList<>();
30 | items.add(shoppingCart);
31 | sr.setItems(items);
32 | } else {
33 | List items = shoppingCart.getRelatedEntities().stream()
34 | .filter(e -> entityType.equals(e.getEntityType())).collect(Collectors.toList());
35 | sr.setItems(items);
36 | }
37 | return sr;
38 | }
39 |
40 | public static void processResponse(DelegateExecution ctx, ServiceResponse serviceResponse) throws Exception {
41 | ctx.setVariable(ProcessConstants.VAR_RESPONSE, serviceResponse);
42 | if (!Response.Status.OK.toString().equals(serviceResponse.getStatusCode())) {
43 | ProcessContext pctx = (ProcessContext) ctx.getVariable(ProcessConstants.VAR_CTX);
44 | pctx.setError(serviceResponse.getErrorMessage());
45 | throw new BpmnError(SC_ERROR);
46 | }
47 | }
48 |
49 | private static String getEntityTypeForService(String serviceName) {
50 | if (ProcessConstants.SERVICE_NAME_LOCATION.equals(serviceName)) {
51 | return ProcessConstants.ENTITY_TYPE_LOCATION;
52 | } else if (ProcessConstants.SERVICE_NAME_PAYMENT.equals(serviceName)) {
53 | return ProcessConstants.ENTITY_TYPE_PAYMENT;
54 | } else if (ProcessConstants.SERVICE_NAME_INVENTORY.equals(serviceName)) {
55 | return ProcessConstants.ENTITY_TYPE_PRODUCT;
56 | } else if (ProcessConstants.SERVICE_NAME_ORDER.equals(serviceName)) {
57 | return ProcessConstants.ENTITY_TYPE_PRODUCT;
58 | } else if (ProcessConstants.SERVICE_NAME_CUSTOMER.equals(serviceName)) {
59 | return ProcessConstants.ENTITY_TYPE_SHOPPINGCART;
60 | } else {
61 | return ProcessConstants.UNKNOWN;
62 | }
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ReleaseInventoryActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 | @Component
15 | public class ReleaseInventoryActivity implements JavaDelegate {
16 | private static final Logger LOG = LoggerFactory.getLogger(ReleaseInventoryActivity.class);
17 | public static final String SERVICE_ACTION = "release";
18 |
19 | @Autowired
20 | RpcClient rpcClient;
21 |
22 | @Override
23 | public void execute(DelegateExecution execution) throws Exception {
24 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_INVENTORY, SERVICE_ACTION);
25 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
26 | ServiceResponse response = rpcClient.invokeService(
27 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_INVENTORY, SERVICE_ACTION));
28 | ProcessUtil.processResponse(execution, response);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ReleasePaymentActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 | @Component
15 | public class ReleasePaymentActivity implements JavaDelegate {
16 | private static final Logger LOG = LoggerFactory.getLogger(ReleasePaymentActivity.class);
17 | public static final String SERVICE_ACTION = "release";
18 |
19 | @Autowired
20 | RpcClient rpcClient;
21 |
22 | @Override
23 | public void execute(DelegateExecution execution) throws Exception {
24 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_PAYMENT, SERVICE_ACTION);
25 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
26 | ServiceResponse response = rpcClient.invokeService(
27 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_PAYMENT, SERVICE_ACTION));
28 | ProcessUtil.processResponse(execution, response);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ReservePaymentActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 | @Component
15 | public class ReservePaymentActivity implements JavaDelegate {
16 | private static final Logger LOG = LoggerFactory.getLogger(ReservePaymentActivity.class);
17 | public static final String SERVICE_ACTION = "reserve";
18 |
19 | @Autowired
20 | RpcClient rpcClient;
21 |
22 | @Override
23 | public void execute(DelegateExecution execution) throws Exception {
24 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_PAYMENT, SERVICE_ACTION);
25 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
26 | ServiceResponse response = rpcClient.invokeService(
27 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_PAYMENT, SERVICE_ACTION));
28 | ProcessUtil.processResponse(execution, response);
29 | execution.setVariable(ProcessConstants.VAR_PAYMENT_RESERVED, true);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/RetrieveShoppingCartActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
12 | import com.books.chapters.restfulapi.patterns.parttwo.dataaccess.ShoppingCartManager;
13 |
14 | @Component
15 | public class RetrieveShoppingCartActivity implements JavaDelegate {
16 | private static final Logger LOG = LoggerFactory.getLogger(RetrieveShoppingCartActivity.class);
17 | public static final String SERVICE_ACTION = "retrieve";
18 |
19 | @Autowired
20 | ShoppingCartManager shoppingCartManager;
21 |
22 | @Override
23 | public void execute(DelegateExecution ctx) throws Exception {
24 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_SHOPPINGCART, SERVICE_ACTION);
25 | String scId = (String) ctx.getVariable(ProcessConstants.VAR_SC_ID);
26 | ServiceResponse response = shoppingCartManager.getShoppingCart(scId);
27 | ProcessUtil.processResponse(ctx, response);
28 | BusinessEntity sc = response.getItems().get(0);
29 | ctx.setVariable(ProcessConstants.VAR_SC, sc);
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/SubmitErrorActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.AmqpPublisher;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
12 |
13 | @Component
14 | public class SubmitErrorActivity implements JavaDelegate {
15 | private static final Logger LOG = LoggerFactory.getLogger(SubmitErrorActivity.class);
16 | public static final String SERVICE_ACTION = "notify";
17 |
18 | @Autowired
19 | AmqpPublisher amqpPubClient;
20 |
21 | @Override
22 | public void execute(DelegateExecution execution) throws Exception {
23 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_BACKOFFICE, SERVICE_ACTION);
24 | ServiceResponse errorResponse = (ServiceResponse) execution.getVariable(ProcessConstants.VAR_RESPONSE);
25 | amqpPubClient.publishError(errorResponse, ProcessConstants.SERVICE_NAME_BACKOFFICE + "." + SERVICE_ACTION);
26 | ProcessContext ctx = (ProcessContext) execution.getVariable(ProcessConstants.VAR_CTX);
27 | ctx.setError(errorResponse.getErrorMessage());
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/bpm/ValidateAddressActivity.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.bpm;
2 |
3 | import org.camunda.bpm.engine.delegate.DelegateExecution;
4 | import org.camunda.bpm.engine.delegate.JavaDelegate;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.stereotype.Component;
9 |
10 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.amqp.producer.RpcClient;
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.ServiceResponse;
13 |
14 | @Component
15 | public class ValidateAddressActivity implements JavaDelegate {
16 | private static final Logger LOG = LoggerFactory.getLogger(ValidateAddressActivity.class);
17 | public static final String SERVICE_ACTION = "validate";
18 |
19 | @Autowired
20 | RpcClient rpcClient;
21 |
22 | @Override
23 | public void execute(DelegateExecution execution) throws Exception {
24 | LOG.info("execute {} - {}", ProcessConstants.SERVICE_NAME_LOCATION, SERVICE_ACTION);
25 | BusinessEntity sc = (BusinessEntity) execution.getVariable(ProcessConstants.VAR_SC);
26 | ServiceResponse response = rpcClient.invokeService(
27 | ProcessUtil.buildServiceRequest(sc, ProcessConstants.SERVICE_NAME_LOCATION, SERVICE_ACTION));
28 | ProcessUtil.processResponse(execution, response);
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/dataaccess/BusinessEntityJpa.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.dataaccess;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import javax.persistence.CascadeType;
7 | import javax.persistence.Column;
8 | import javax.persistence.Entity;
9 | import javax.persistence.FetchType;
10 | import javax.persistence.Id;
11 | import javax.persistence.JoinColumn;
12 | import javax.persistence.JoinTable;
13 | import javax.persistence.ManyToMany;
14 | import javax.persistence.Table;
15 |
16 | @Entity
17 | @Table(name = "BusinessEntity")
18 | public class BusinessEntityJpa {
19 |
20 | @Id
21 | private String id;
22 |
23 | @Column(nullable = false)
24 | private String entityType;
25 |
26 | @Column(nullable = false)
27 | private String entitySpecification;
28 |
29 | private String name;
30 |
31 | private String status;
32 |
33 | @JoinTable(name = "entityRelation", joinColumns = {
34 | @JoinColumn(name = "referencingEntity", referencedColumnName = "id", nullable = false) }, inverseJoinColumns = {
35 | @JoinColumn(name = "referencedEntity", referencedColumnName = "id", nullable = false) })
36 | @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
37 | private List relatedEntities = new ArrayList();
38 |
39 | public String getId() {
40 | return id;
41 | }
42 |
43 | public void setId(String id) {
44 | this.id = id;
45 | }
46 |
47 | public BusinessEntityJpa withId(String id) {
48 | this.id = id;
49 | return this;
50 | }
51 |
52 | public String getEntityType() {
53 | return entityType;
54 | }
55 |
56 | public void setEntityType(String entityType) {
57 | this.entityType = entityType;
58 | }
59 |
60 | public BusinessEntityJpa withEntityType(String entityType) {
61 | this.entityType = entityType;
62 | return this;
63 | }
64 |
65 | public String getEntitySpecification() {
66 | return entitySpecification;
67 | }
68 |
69 | public void setEntitySpecification(String entitySpecification) {
70 | this.entitySpecification = entitySpecification;
71 | }
72 |
73 | public BusinessEntityJpa withEntitySpecification(String entitySpecification) {
74 | this.entitySpecification = entitySpecification;
75 | return this;
76 | }
77 |
78 | public String getName() {
79 | return name;
80 | }
81 |
82 | public void setName(String name) {
83 | this.name = name;
84 | }
85 |
86 | public BusinessEntityJpa withName(String name) {
87 | this.name = name;
88 | return this;
89 | }
90 |
91 | public String getStatus() {
92 | return status;
93 | }
94 |
95 | public void setStatus(String status) {
96 | this.status = status;
97 | }
98 |
99 | public BusinessEntityJpa withStatus(String status) {
100 | this.status = status;
101 | return this;
102 | }
103 |
104 | public List getRelatedEntities() {
105 | return relatedEntities;
106 | }
107 |
108 | public void setRelatedEntities(List relatedEntities) {
109 | this.relatedEntities = relatedEntities;
110 | }
111 |
112 | public BusinessEntityJpa withRelatedEntities(List relatedEntities) {
113 | this.relatedEntities = relatedEntities;
114 | return this;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/dataaccess/BusinessEntityRepository.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.dataaccess;
2 |
3 | import org.springframework.data.repository.CrudRepository;
4 |
5 | public interface BusinessEntityRepository extends CrudRepository {
6 | }
7 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/dataaccess/BusinessEntityTranslator.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.dataaccess;
2 |
3 | import java.util.Collection;
4 | import java.util.Collections;
5 | import java.util.List;
6 | import java.util.Objects;
7 | import java.util.Optional;
8 | import java.util.function.Function;
9 | import java.util.stream.Collectors;
10 |
11 | import com.books.chapters.restfulapi.patterns.parttwo.adapter.entity.BusinessEntity;
12 |
13 | public class BusinessEntityTranslator {
14 | private BusinessEntityTranslator() {
15 | }
16 |
17 | public static BusinessEntity fromJpa(BusinessEntityJpa jpaEntity) {
18 | if (jpaEntity == null) {
19 | return null;
20 | }
21 |
22 | return new BusinessEntity().withId(jpaEntity.getId()).withName(jpaEntity.getName())
23 | .withStatus(jpaEntity.getStatus()).withEntitySpecification(jpaEntity.getEntitySpecification())
24 | .withEntityType(jpaEntity.getEntityType()).withRelatedEntities(
25 | translateToList(jpaEntity.getRelatedEntities(), BusinessEntityTranslator::fromJpa));
26 | }
27 |
28 | public static BusinessEntityJpa toJpa(BusinessEntity entity) {
29 | if (entity == null) {
30 | return null;
31 | }
32 |
33 | return new BusinessEntityJpa().withId(entity.getId()).withName(entity.getName()).withStatus(entity.getStatus())
34 | .withEntitySpecification(entity.getEntitySpecification()).withEntityType(entity.getEntityType())
35 | .withRelatedEntities(translateToList(entity.getRelatedEntities(), BusinessEntityTranslator::toJpa));
36 | }
37 |
38 | public static List translateToList(Collection froms, Function translate) {
39 | return Optional.ofNullable(froms).orElse(Collections.emptyList()).stream().map(translate)
40 | .filter(Objects::nonNull).collect(Collectors.toList());
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/java/com/books/chapters/restfulapi/patterns/parttwo/rest/ShoppingCartRestController.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo.rest;
2 |
3 | import org.camunda.bpm.engine.ProcessEngine;
4 | import org.camunda.bpm.engine.runtime.ProcessInstance;
5 | import org.camunda.bpm.engine.variable.Variables;
6 | import org.springframework.beans.factory.annotation.Autowired;
7 | import org.springframework.http.HttpStatus;
8 | import org.springframework.http.ResponseEntity;
9 | import org.springframework.web.bind.annotation.PathVariable;
10 | import org.springframework.web.bind.annotation.RequestMapping;
11 | import org.springframework.web.bind.annotation.RequestMethod;
12 | import org.springframework.web.bind.annotation.RestController;
13 |
14 | import com.books.chapters.restfulapi.patterns.parttwo.bpm.ProcessConstants;
15 | import com.books.chapters.restfulapi.patterns.parttwo.bpm.ProcessContext;
16 |
17 | @RestController
18 | @RequestMapping("/shoppingCart")
19 | public class ShoppingCartRestController {
20 |
21 | @Autowired
22 | private ProcessEngine camunda;
23 |
24 | @RequestMapping(value = "/{scId}/submit", method = RequestMethod.POST)
25 | public ResponseEntity> placeOrderPOST(@PathVariable("scId") String scId) {
26 | ProcessContext context = new ProcessContext();
27 | submitShoppingCart(scId, context);
28 | if (context.getError() != null) {
29 | return new ResponseEntity<>(context.getError(), HttpStatus.FORBIDDEN);
30 | }
31 | return new ResponseEntity<>(context.getResponse(), HttpStatus.OK);
32 |
33 | }
34 |
35 | private ProcessInstance submitShoppingCart(String scId, ProcessContext context) {
36 | return camunda.getRuntimeService().startProcessInstanceByKey(//
37 | "submitShoppingCart", //
38 | Variables //
39 | .putValue(ProcessConstants.VAR_SC_ID, scId).putValue(ProcessConstants.VAR_CTX, context));
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/resources/META-INF/processes.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Hands-On-RESTful-API-Design-Patterns-and-Best-Practices/92544a10bee84b777c98b3fc6cd38a5a8e886066/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/resources/META-INF/processes.xml
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/main/resources/application.yaml:
--------------------------------------------------------------------------------
1 | camunda.bpm:
2 | admin-user:
3 | id: admin
4 | password: admin
5 | firstName: Admin
6 | filter:
7 | create: All tasks
8 |
9 | spring:
10 | datasource:
11 | url: jdbc:h2:~/camunda;DB_CLOSE_ON_EXIT=false
12 | rabbitmq:
13 | host: localhost
14 | port: 5777
15 | username: test
16 | password: test
17 | exchange:
18 | rpc: shoppingcart.rpc
19 | pub: shoppingcart.pub
--------------------------------------------------------------------------------
/Chapter07/event-driven-service-orchestration/shopping-cart/src/test/java/com/books/chapters/restfulapi/patterns/parttwo/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.parttwo;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/investor-services/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.books.chapters.restfulapi.patterns.partOne
7 | investor-services
8 | 0.0.1-SNAPSHOT
9 | jar
10 |
11 | investor-services
12 | sample spring boot application for the the restful API patterns chapter part one
13 |
14 |
15 | org.springframework.boot
16 | spring-boot-starter-parent
17 | 1.4.4.RELEASE
18 |
19 |
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 |
26 |
27 |
28 |
29 | org.springframework.boot
30 | spring-boot-starter-actuator
31 |
32 |
33 | org.springframework.boot
34 | spring-boot-starter-web
35 |
36 |
37 | com.fasterxml.jackson.dataformat
38 | jackson-dataformat-xml
39 |
40 |
41 | org.springframework.boot
42 | spring-boot-starter-test
43 | test
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | org.springframework.boot
52 | spring-boot-maven-plugin
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/investor-services/scripts/buildMyExamples.bat:
--------------------------------------------------------------------------------
1 | mkdir bookexamples
2 | cd bookexamples
3 | mkdir ch03
4 | cd ch03
5 | git clone https://github.com/PacktPublishing/Hands-On-RESTful-API-Design-Patterns-and-Best-Practices.git
6 | cd Hands-On-RESTful-API-Design-Patterns-and-Best-Practices
7 | cd investor-services
8 | mvn clean package
--------------------------------------------------------------------------------
/investor-services/scripts/runMyExamples.bat:
--------------------------------------------------------------------------------
1 | java -jar bookexamples/ch03/Hands-On-RESTful-API-Design-Patterns-and-Best-Practices/investor-services/target/investor-services-0.0.1-SNAPSHOT.jar
--------------------------------------------------------------------------------
/investor-services/src/main/java/com/books/chapters/restfulapi/patterns/chap3/springboot/InvestorServicesApplication.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class InvestorServicesApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(InvestorServicesApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/investor-services/src/main/java/com/books/chapters/restfulapi/patterns/chap3/springboot/models/IndividualInvestorPortfolio.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot.models;
2 |
3 | public class IndividualInvestorPortfolio {
4 | private String investorId;
5 | private int stocksHoldCount;
6 |
7 | public IndividualInvestorPortfolio(String investorId, int stocksHoldCount){
8 | this.investorId = investorId;
9 | this.stocksHoldCount = stocksHoldCount;
10 | }
11 |
12 | public String getInvestorId() {
13 | return investorId;
14 | }
15 | public void setInvestorId(String investorId) {
16 | this.investorId = investorId;
17 | }
18 | public int getStocksHoldCount() {
19 | return stocksHoldCount;
20 | }
21 | public void setStocksHoldCount(int stocksCount) {
22 | stocksHoldCount = stocksCount;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/investor-services/src/main/java/com/books/chapters/restfulapi/patterns/chap3/springboot/models/Investor.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot.models;
2 |
3 | import java.util.List;
4 |
5 | public class Investor {
6 | private String id;
7 | private String name;
8 | private String description;
9 | private List stocks;
10 |
11 | public Investor(String id, String name, String description, List stocks) {
12 | this.id = id;
13 | this.name = name;
14 | this.description = description;
15 | this.stocks = stocks;
16 | }
17 |
18 | public String getId() {
19 | return id;
20 | }
21 |
22 | public void setId(String id) {
23 | this.id = id;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public String getDescription() {
35 | return description;
36 | }
37 |
38 | public void setDescription(String description) {
39 | this.description = description;
40 | }
41 |
42 | public List getStocks() {
43 | return stocks;
44 | }
45 |
46 | public void setStocks(List stocks) {
47 | this.stocks = stocks;
48 | }
49 |
50 | @Override
51 | public String toString() {
52 | return String.format("Investor [id=%s, name=%s, description=%s, stocks=%s]", id, name, description, stocks);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/investor-services/src/main/java/com/books/chapters/restfulapi/patterns/chap3/springboot/models/Stock.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot.models;
2 |
3 | public class Stock {
4 | private String symbol;
5 | private int numberOfSharesHeld;
6 | private double tickerPrice = 0.0;
7 |
8 | Stock() {
9 | // default constructor, otherwise the spring boot runtime complains that
10 | // it can not instantiate this Stock class when we try to do POST to
11 | // insert a new Stock from the controller classes
12 | }
13 |
14 | public Stock(String symbol, int numberOfSharesHeld, double tickerPrice) {
15 |
16 | this.symbol = symbol;
17 | this.numberOfSharesHeld = numberOfSharesHeld;
18 | this.tickerPrice = tickerPrice;
19 | }
20 |
21 | public String getSymbol() {
22 | return symbol;
23 | }
24 |
25 | public void setSymbol(String symbol) {
26 | this.symbol = symbol;
27 | }
28 |
29 | public int getNumberOfSharesHeld() {
30 | return numberOfSharesHeld;
31 | }
32 |
33 | public void setNumberOfSharesHeld(int numberOfShares) {
34 | this.numberOfSharesHeld = numberOfShares;
35 | }
36 |
37 | public double getTickerPrice() {
38 | return tickerPrice;
39 | }
40 |
41 | public void setTickerPrice(double tickerPrice) {
42 | this.tickerPrice = tickerPrice;
43 | }
44 |
45 | @Override
46 | public String toString() {
47 | String pattern = "Stock [symbol: %s, numberOfSharesHeld: %d, tickerPrice: %6.2f]";
48 | return String.format(pattern, symbol, numberOfSharesHeld, tickerPrice);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/investor-services/src/main/java/com/books/chapters/restfulapi/patterns/chap3/springboot/models/errorsandexceptions/InvestorNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot.models.errorsandexceptions;
2 |
3 | public class InvestorNotFoundException extends RuntimeException{
4 |
5 | private static final long serialVersionUID = 1L;
6 |
7 | public InvestorNotFoundException(String exception)
8 | {
9 | super(exception);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/investor-services/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=9090
--------------------------------------------------------------------------------
/investor-services/src/test/java/com/books/chapters/restfulapi/patterns/chap3/springboot/InvestorServicesApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.boot.test.context.SpringBootTest;
6 | import org.springframework.test.context.junit4.SpringRunner;
7 |
8 | @RunWith(SpringRunner.class)
9 | @SpringBootTest
10 | public class InvestorServicesApplicationTests {
11 |
12 | @Test
13 | public void contextLoads() {
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/investor-services/src/test/java/com/books/chapters/restfulapi/patterns/chap3/springboot/controller/InvestorControllerTest.java:
--------------------------------------------------------------------------------
1 | package com.books.chapters.restfulapi.patterns.chap3.springboot.controller;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
7 | import org.springframework.boot.test.mock.mockito.MockBean;
8 | import org.springframework.http.MediaType;
9 | import org.springframework.mock.web.MockHttpServletResponse;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 | import org.springframework.test.web.servlet.MockMvc;
12 | import org.springframework.test.web.servlet.MvcResult;
13 | import org.springframework.test.web.servlet.RequestBuilder;
14 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
15 |
16 | import com.books.chapters.restfulapi.patterns.chap3.springboot.controller.InvestorController;
17 | import com.books.chapters.restfulapi.patterns.chap3.springboot.service.InvestorService;
18 |
19 | @RunWith(SpringRunner.class)
20 | @WebMvcTest(value = InvestorController.class, secure = false)
21 | public class InvestorControllerTest {
22 |
23 | @Autowired
24 | private MockMvc mockMvc;
25 |
26 | @MockBean
27 | private InvestorService studentService;
28 |
29 | @Test
30 | public void fetchAllInvestors() throws Exception{
31 | RequestBuilder requestBuilder = MockMvcRequestBuilders.get(
32 | "/investors").accept(
33 | MediaType.APPLICATION_JSON);
34 | MvcResult result = mockMvc.perform(requestBuilder).andReturn();
35 | MockHttpServletResponse response = result.getResponse();
36 | System.out.println("here "+response);
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/scripts/buildMyExamples.bat:
--------------------------------------------------------------------------------
1 | git config --system core.longpaths true
2 | git clone https://github.com/PacktPublishing/Hands-On-RESTful-API-Design-Patterns-and-Best-Practices.git
3 | cd Hands-On-RESTful-API-Design-Patterns-and-Best-Practices\chapter-3\investor-services
4 | mvn clean package
5 |
--------------------------------------------------------------------------------
/scripts/runMyExamples.bat:
--------------------------------------------------------------------------------
1 | java -jar Hands-On-RESTful-API-Design-Patterns-and-Best-Practices/chapter-3/investor-services/target/investor-services-0.0.1-SNAPSHOT.jar
2 |
--------------------------------------------------------------------------------