From c1b9675c4317b525a5c9e935b82517ba8391b974 Mon Sep 17 00:00:00 2001 From: tschiman Date: Sat, 11 Feb 2017 11:52:16 -0700 Subject: [PATCH 01/10] BAEL-684 Adding spring JPA to resource servers --- .../gateway/GatewayApplicationLiveTest.java | 69 ------ .../bootstrap/gateway/IntegrationTest.java | 201 ++++++++++++++++++ .../spring-cloud-bootstrap/svc-book/pom.xml | 11 + .../svcbook/BookServiceApplication.java | 24 --- .../bootstrap/svcbook/SecurityConfig.java | 8 +- .../bootstrap/svcbook/{ => book}/Book.java | 19 +- .../svcbook/book/BookController.java | 40 ++++ .../svcbook/book/BookNotFoundException.java | 11 + .../svcbook/book/BookRepository.java | 6 + .../bootstrap/svcbook/book/BookService.java | 55 +++++ .../spring-cloud-bootstrap/svc-rating/pom.xml | 11 + .../svcrating/RatingServiceApplication.java | 28 --- .../bootstrap/svcrating/SecurityConfig.java | 8 +- .../svcrating/{ => rating}/Rating.java | 14 +- .../svcrating/rating/RatingController.java | 38 ++++ .../rating/RatingNotFoundException.java | 11 + .../svcrating/rating/RatingRepository.java | 9 + .../svcrating/rating/RatingService.java | 57 +++++ 18 files changed, 487 insertions(+), 133 deletions(-) delete mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplicationLiveTest.java create mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java rename spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/{ => book}/Book.java (57%) create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookNotFoundException.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookRepository.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java rename spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/{ => rating}/Rating.java (62%) create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingNotFoundException.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingRepository.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplicationLiveTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplicationLiveTest.java deleted file mode 100644 index aa39232bb2..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplicationLiveTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.gateway; - -import org.junit.Assert; -import org.junit.Test; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.*; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -public class GatewayApplicationLiveTest { - - @Test - public void testAccess() throws Exception { - TestRestTemplate testRestTemplate = new TestRestTemplate(); - String testUrl = "http://localhost:8080"; - - ResponseEntity response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //try the protected resource and confirm the redirect to login - response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class); - Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode()); - Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0)); - - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "user"); - form.add("password", "password"); - response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - HttpEntity httpEntity = new HttpEntity<>(headers); - - //request the protected resource - response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //request the admin protected resource to determine it is still protected - response = testRestTemplate.exchange(testUrl + "/rating-service/ratings/all", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); - - //login as the admin - form.clear(); - form.add("username", "admin"); - form.add("password", "admin"); - response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - httpEntity = new HttpEntity<>(headers); - - //request the protected resource - response = testRestTemplate.exchange(testUrl + "/rating-service/ratings/all", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //request the discovery resources as the admin - response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - } - -} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java new file mode 100644 index 0000000000..16057edc48 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java @@ -0,0 +1,201 @@ +package com.baeldung.spring.cloud.bootstrap.gateway; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.apache.http.entity.ContentType; +import org.junit.Assert; +import org.junit.Test; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.*; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; + +public class IntegrationTest { + + private TestRestTemplate testRestTemplate = new TestRestTemplate(); + private String testUrl = "http://localhost:8080"; + + @Test + public void testAccess() throws Exception { + ResponseEntity response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class); + Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); + Assert.assertNotNull(response.getBody()); + + //try the protected resource and confirm the redirect to login + response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class); + Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode()); + Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0)); + + //login as user/password + MultiValueMap form = new LinkedMultiValueMap<>(); + form.add("username", "user"); + form.add("password", "password"); + response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); + + //extract the session from the cookie and propagate it to the next request + String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; + HttpHeaders headers = new HttpHeaders(); + headers.add("Cookie", sessionCookie); + HttpEntity httpEntity = new HttpEntity<>(headers); + + addBook(); + + //request the protected resource + response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class); + Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); + Assert.assertNotNull(response.getBody()); + + addRatings(); + + //request the admin protected resource to determine it is still protected + response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class); + Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); + + //login as the admin + form.clear(); + form.add("username", "admin"); + form.add("password", "admin"); + response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); + + //extract the session from the cookie and propagate it to the next request + sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; + headers = new HttpHeaders(); + headers.add("Cookie", sessionCookie); + httpEntity = new HttpEntity<>(headers); + + //request the protected resource + response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class); + Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); + Assert.assertNotNull(response.getBody()); + + //request the discovery resources as the admin + response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class); + Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); + } + + private void addRatings() { + //login as user/password + MultiValueMap form = new LinkedMultiValueMap<>(); + form.add("username", "user"); + form.add("password", "password"); + ResponseEntity response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); + + //extract the session from the cookie and propagate it to the next request + String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; + HttpHeaders headers = new HttpHeaders(); + headers.add("Cookie", sessionCookie); + headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType()); + Rating rating = new Rating(1L, 4); + + HttpEntity httpEntity = new HttpEntity<>(rating, headers); + + //request the protected resource + ResponseEntity bookResponse = testRestTemplate.postForEntity(testUrl + "/rating-service/ratings", httpEntity, Rating.class); + Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode()); + Assert.assertEquals(rating.getBookId(), bookResponse.getBody().getBookId()); + Assert.assertEquals(rating.getStars(), bookResponse.getBody().getStars()); + } + + private void addBook(){ + //login as user/password + MultiValueMap form = new LinkedMultiValueMap<>(); + form.add("username", "admin"); + form.add("password", "admin"); + ResponseEntity response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); + + //extract the session from the cookie and propagate it to the next request + String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; + HttpHeaders headers = new HttpHeaders(); + headers.add("Cookie", sessionCookie); + headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType()); + Book book = new Book("Baeldung", "How to spring cloud"); + + HttpEntity httpEntity = new HttpEntity<>(book, headers); + + //request the protected resource + ResponseEntity bookResponse = testRestTemplate.postForEntity(testUrl + "/book-service/books", httpEntity, Book.class); + Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode()); + Assert.assertEquals(book.getAuthor(), bookResponse.getBody().getAuthor()); + Assert.assertEquals(book.getTitle(), bookResponse.getBody().getTitle()); + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Book { + + private Long id; + private String author; + private String title; + + public Book() { + } + + public Book(String author, String title) { + this.author = author; + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Rating { + private Long id; + private Long bookId; + private int stars; + + public Rating() { + } + + public Rating(Long bookId, int stars) { + this.bookId = bookId; + this.stars = stars; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getBookId() { + return bookId; + } + + public void setBookId(Long bookId) { + this.bookId = bookId; + } + + public int getStars() { + return stars; + } + + public void setStars(int stars) { + this.stars = stars; + } + } + + +} \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml index 9a99054ed5..c351c444f6 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml @@ -42,6 +42,17 @@ spring-boot-starter-data-redis + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java index 25ad2a83b2..c5499cd924 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java @@ -3,35 +3,11 @@ package com.baeldung.spring.cloud.bootstrap.svcbook; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Arrays; -import java.util.List; @SpringBootApplication @EnableEurekaClient -@RestController -@RequestMapping("/books") public class BookServiceApplication { public static void main(String[] args) { SpringApplication.run(BookServiceApplication.class, args); } - - private List bookList = Arrays.asList( - new Book(1L, "Baeldung goes to the market", "Tim Schimandle"), - new Book(2L, "Baeldung goes to the park", "Slavisa") - ); - - @GetMapping("") - public List findAllBooks() { - return bookList; - } - - @GetMapping("/{bookId}") - public Book findBook(@PathVariable Long bookId) { - return bookList.stream().filter(b -> b.getId().equals(bookId)).findFirst().orElse(null); - } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java index 300b4d7c5a..6aa996c575 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/SecurityConfig.java @@ -2,6 +2,7 @@ package com.baeldung.spring.cloud.bootstrap.svcbook; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -22,8 +23,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { http.httpBasic() .disable() .authorizeRequests() - .antMatchers("/books").permitAll() - .antMatchers("/books/*").hasAnyRole("USER", "ADMIN") + .antMatchers(HttpMethod.GET, "/books").permitAll() + .antMatchers(HttpMethod.GET, "/books/*").permitAll() + .antMatchers(HttpMethod.POST, "/books").hasRole("ADMIN") + .antMatchers(HttpMethod.PATCH, "/books/*").hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE, "/books/*").hasRole("ADMIN") .anyRequest().authenticated() .and() .csrf() diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/Book.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/Book.java similarity index 57% rename from spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/Book.java rename to spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/Book.java index e652437454..33ea8dcb81 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/Book.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/Book.java @@ -1,16 +1,21 @@ -package com.baeldung.spring.cloud.bootstrap.svcbook; +package com.baeldung.spring.cloud.bootstrap.svcbook.book; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +@JsonIgnoreProperties(ignoreUnknown = true) public class Book { + @Id + @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private String author; private String title; - public Book(Long id, String title, String author) { - this.id = id; - this.author = author; - this.title = title; - } - public Book() { } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java new file mode 100644 index 0000000000..d00f114b8c --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookController.java @@ -0,0 +1,40 @@ +package com.baeldung.spring.cloud.bootstrap.svcbook.book; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/books") +public class BookController { + + @Autowired + private BookService bookService; + + @GetMapping("") + public List findAllBooks() { + return bookService.findAllBooks(); + } + + @GetMapping("/{bookId}") + public Book findBook(@PathVariable Long bookId) { + return bookService.findBookById(bookId); + } + + @PostMapping("") + public Book createBook(@RequestBody Book book) { + return bookService.createBook(book); + } + + @DeleteMapping("/{bookId}") + public void deleteBook(@PathVariable Long bookId) { + bookService.deleteBook(bookId); + } + + @PatchMapping("/{bookId") + public Book updateBook(@RequestBody Map updates, @PathVariable Long bookId) { + return bookService.updateBook(updates, bookId); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookNotFoundException.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookNotFoundException.java new file mode 100644 index 0000000000..f0a4797387 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookNotFoundException.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.cloud.bootstrap.svcbook.book; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +class BookNotFoundException extends RuntimeException { + BookNotFoundException(String message) { + super(message); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookRepository.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookRepository.java new file mode 100644 index 0000000000..66fd3880c5 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookRepository.java @@ -0,0 +1,6 @@ +package com.baeldung.spring.cloud.bootstrap.svcbook.book; + +import org.springframework.data.jpa.repository.JpaRepository; + +interface BookRepository extends JpaRepository{ +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java new file mode 100644 index 0000000000..cfcbf15757 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/book/BookService.java @@ -0,0 +1,55 @@ +package com.baeldung.spring.cloud.bootstrap.svcbook.book; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Service +@Transactional(readOnly = true) +public class BookService { + + @Autowired + private BookRepository bookRepository; + + public List findAllBooks() { + return bookRepository.findAll(); + } + + public Book findBookById(Long bookId) { + return Optional.ofNullable(bookRepository.findOne(bookId)) + .orElseThrow(() -> new BookNotFoundException("Book not found. ID: " + bookId)); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Book createBook(Book book) { + Book newBook = new Book(); + newBook.setTitle(book.getTitle()); + newBook.setAuthor(book.getAuthor()); + return bookRepository.save(newBook); + } + + @Transactional(propagation = Propagation.REQUIRED) + public void deleteBook(Long bookId) { + bookRepository.delete(bookId); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Book updateBook(Map updates, Long bookId) { + Book book = findBookById(bookId); + updates.keySet().forEach(key -> { + switch (key) { + case "author": + book.setAuthor(updates.get(key)); + break; + case "title": + book.setTitle(updates.get(key)); + } + }); + return bookRepository.save(book); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml index 35da8beba8..2285286812 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml @@ -42,6 +42,17 @@ spring-boot-starter-data-redis + + org.springframework.boot + spring-boot-starter-data-jpa + + + + com.h2database + h2 + runtime + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java index 11fb5f06b6..61074e0bcc 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java @@ -3,39 +3,11 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; @SpringBootApplication @EnableEurekaClient -@RestController -@RequestMapping("/ratings") public class RatingServiceApplication { public static void main(String[] args) { SpringApplication.run(RatingServiceApplication.class, args); } - - private List ratingList = Arrays.asList( - new Rating(1L, 1L, 2), - new Rating(2L, 1L, 3), - new Rating(3L, 2L, 4), - new Rating(4L, 2L, 5) - ); - - @GetMapping("") - public List findRatingsByBookId(@RequestParam Long bookId) { - return bookId == null || bookId.equals(0L) ? Collections.EMPTY_LIST : ratingList.stream().filter(r -> r.getBookId().equals(bookId)).collect(Collectors.toList()); - } - - @GetMapping("/all") - public List findAllRatings() { - return ratingList; - } } \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java index 371dc810d5..171fbba7af 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SecurityConfig.java @@ -2,6 +2,7 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -22,8 +23,11 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { http.httpBasic() .disable() .authorizeRequests() - .antMatchers("/ratings").hasRole("USER") - .antMatchers("/ratings/all").hasRole("ADMIN") + .regexMatchers("^/ratings\\?bookId.*$").authenticated() + .antMatchers(HttpMethod.POST,"/ratings").authenticated() + .antMatchers(HttpMethod.PATCH,"/ratings/*").hasRole("ADMIN") + .antMatchers(HttpMethod.DELETE,"/ratings/*").hasRole("ADMIN") + .antMatchers(HttpMethod.GET,"/ratings").hasRole("ADMIN") .anyRequest().authenticated() .and() .csrf() diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/Rating.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java similarity index 62% rename from spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/Rating.java rename to spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java index 5dd3572098..ae44f9ae2e 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/Rating.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java @@ -1,6 +1,18 @@ -package com.baeldung.spring.cloud.bootstrap.svcrating; +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +@Entity +@JsonIgnoreProperties(ignoreUnknown = true) public class Rating { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private Long bookId; private int stars; diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java new file mode 100644 index 0000000000..83452ad747 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingController.java @@ -0,0 +1,38 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/ratings") +public class RatingController { + + @Autowired + private RatingService ratingService; + + @GetMapping("") + public List findRatingsByBookId(@RequestParam(required = false, defaultValue = "0") Long bookId) { + if (bookId.equals(0L)) { + return ratingService.findAllRatings(); + } + return ratingService.findRatingsByBookId(bookId); + } + + @PostMapping("") + public Rating createRating(@RequestBody Rating rating) { + return ratingService.createRating(rating); + } + + @DeleteMapping("/{ratingId}") + public void deleteRating(@PathVariable Long ratingId) { + ratingService.deleteRating(ratingId); + } + + @PatchMapping("/{ratingId") + public Rating updateRating(@RequestBody Map updates, @PathVariable Long ratingId) { + return ratingService.updateRating(updates, ratingId); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingNotFoundException.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingNotFoundException.java new file mode 100644 index 0000000000..473d636a71 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingNotFoundException.java @@ -0,0 +1,11 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(HttpStatus.NOT_FOUND) +class RatingNotFoundException extends RuntimeException { + RatingNotFoundException(String message) { + super(message); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingRepository.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingRepository.java new file mode 100644 index 0000000000..08d781b5a3 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingRepository.java @@ -0,0 +1,9 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +interface RatingRepository extends JpaRepository{ + List findRatingsByBookId(Long bookId); +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java new file mode 100644 index 0000000000..a2360b7be5 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingService.java @@ -0,0 +1,57 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +@Service +@Transactional(readOnly = true) +public class RatingService { + + @Autowired + private RatingRepository ratingRepository; + + public Rating findRatingById(Long ratingId) { + return Optional.ofNullable(ratingRepository.findOne(ratingId)) + .orElseThrow(() -> new RatingNotFoundException("Rating not found. ID: " + ratingId)); + } + + public List findRatingsByBookId(Long bookId) { + return ratingRepository.findRatingsByBookId(bookId); + } + + public List findAllRatings() { + return ratingRepository.findAll(); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Rating createRating(Rating rating) { + Rating newRating = new Rating(); + newRating.setBookId(rating.getBookId()); + newRating.setStars(rating.getStars()); + return ratingRepository.save(newRating); + } + + @Transactional(propagation = Propagation.REQUIRED) + public void deleteRating(Long ratingId) { + ratingRepository.delete(ratingId); + } + + @Transactional(propagation = Propagation.REQUIRED) + public Rating updateRating(Map updates, Long ratingId) { + Rating rating = findRatingById(ratingId); + updates.keySet().forEach(key -> { + switch (key) { + case "stars": + rating.setStars(Integer.parseInt(updates.get(key))); + break; + } + }); + return ratingRepository.save(rating); + } +} From 0b793f73980d01c12bfb4723c935d7557a1f67d7 Mon Sep 17 00:00:00 2001 From: tschiman Date: Sun, 12 Feb 2017 15:55:20 -0700 Subject: [PATCH 02/10] BAEL-574 integrating zipkin into the cloud project --- .../application-config/zipkin.properties | 7 ++ .../spring-cloud-bootstrap/gateway/pom.xml | 5 + .../bootstrap/gateway/SecurityConfig.java | 1 + .../src/main/resources/bootstrap.properties | 10 +- spring-cloud/spring-cloud-bootstrap/pom.xml | 1 + .../spring-cloud-bootstrap/svc-book/pom.xml | 5 + .../src/main/resources/bootstrap.properties | 3 + .../spring-cloud-bootstrap/svc-rating/pom.xml | 5 + .../src/main/resources/bootstrap.properties | 3 + .../spring-cloud-bootstrap/zipkin/pom.xml | 101 ++++++++++++++++++ .../bootstrap/zipkin/ZipkinApplication.java | 15 +++ .../src/main/resources/bootstrap.properties | 7 ++ 12 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 spring-cloud/spring-cloud-bootstrap/application-config/zipkin.properties create mode 100644 spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml create mode 100644 spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java create mode 100644 spring-cloud/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties diff --git a/spring-cloud/spring-cloud-bootstrap/application-config/zipkin.properties b/spring-cloud/spring-cloud-bootstrap/application-config/zipkin.properties new file mode 100644 index 0000000000..ca3aed2263 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/application-config/zipkin.properties @@ -0,0 +1,7 @@ +spring.application.name=zipkin +server.port=9411 + +eureka.client.region = default +eureka.client.registryFetchIntervalSeconds = 5 + +logging.level.org.springframework.web=debug diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml index 044730ba22..97c440c249 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/gateway/pom.xml @@ -41,6 +41,11 @@ spring-boot-starter-data-redis + + org.springframework.cloud + spring-cloud-starter-zipkin + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java index 9e5c424403..935e50ec72 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/SecurityConfig.java @@ -23,6 +23,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/book-service/books").permitAll() + .antMatchers("/zipkin/**").permitAll() .antMatchers("/eureka/**").hasRole("ADMIN") .anyRequest().authenticated() .and() diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties index 43491ff36b..ca453e1007 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties @@ -4,4 +4,12 @@ spring.cloud.config.discovery.enabled=true spring.cloud.config.username=configUser spring.cloud.config.password=configPassword -eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file +eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ + +zuul.routes.zipkin.path=/zipkin/** +zuul.routes.zipkin.sensitive-headers=Set-Cookie,Authorization +hystrix.command.zipkin.execution.isolation.thread.timeoutInMilliseconds=600000 + +spring.sleuth.sampler.percentage=1.0 +spring.sleuth.web.skipPattern=(.+?cleanup.*|.+favicon.*) +spring.zipkin.base-url=http://zipkin \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/pom.xml b/spring-cloud/spring-cloud-bootstrap/pom.xml index ccfbdb9735..83879cf7d4 100644 --- a/spring-cloud/spring-cloud-bootstrap/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/pom.xml @@ -16,6 +16,7 @@ gateway svc-book svc-rating + zipkin diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml index c351c444f6..cbf7083b83 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/pom.xml @@ -53,6 +53,11 @@ runtime + + org.springframework.cloud + spring-cloud-starter-zipkin + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties index 8f3a3261ac..e8360ecb6f 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties @@ -5,3 +5,6 @@ spring.cloud.config.username=configUser spring.cloud.config.password=configPassword eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ + +spring.sleuth.sampler.percentage=1.0 +spring.zipkin.base-url=http://zipkin \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml index 2285286812..f02ba88f04 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml @@ -53,6 +53,11 @@ runtime + + org.springframework.cloud + spring-cloud-starter-zipkin + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties index be5cf7f1e1..a43e7d76a5 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties @@ -5,3 +5,6 @@ spring.cloud.config.username=configUser spring.cloud.config.password=configPassword eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ + +spring.sleuth.sampler.percentage=1.0 +spring.zipkin.base-url=http://zipkin diff --git a/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml b/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml new file mode 100644 index 0000000000..9d43590366 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + + zipkin + 1.0.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 1.4.4.RELEASE + + + + + + org.springframework.cloud + spring-cloud-starter-config + + + org.springframework.cloud + spring-cloud-starter-eureka + + + + io.zipkin.java + zipkin-server + + + + io.zipkin.java + zipkin-autoconfigure-ui + runtime + + + + + + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + + + **/*LiveTest.java + + + + + + + + Brixton.SR7 + 3.6.0 + + \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java b/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java new file mode 100644 index 0000000000..bb1355e258 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/java/com/baeldung/spring/cloud/bootstrap/zipkin/ZipkinApplication.java @@ -0,0 +1,15 @@ +package com.baeldung.spring.cloud.bootstrap.zipkin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import zipkin.server.EnableZipkinServer; + +@SpringBootApplication +@EnableEurekaClient +@EnableZipkinServer +public class ZipkinApplication { + public static void main(String[] args) { + SpringApplication.run(ZipkinApplication.class, args); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties new file mode 100644 index 0000000000..9569179a4f --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/zipkin/src/main/resources/bootstrap.properties @@ -0,0 +1,7 @@ +spring.cloud.config.name=zipkin +spring.cloud.config.discovery.service-id=config +spring.cloud.config.discovery.enabled=true +spring.cloud.config.username=configUser +spring.cloud.config.password=configPassword + +eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file From 237eb64079946ad76cc5d0acd03d25f767541680 Mon Sep 17 00:00:00 2001 From: tschiman Date: Sun, 12 Feb 2017 15:59:41 -0700 Subject: [PATCH 03/10] BAEL-574 update the readme --- spring-cloud/spring-cloud-bootstrap/README.MD | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spring-cloud/spring-cloud-bootstrap/README.MD b/spring-cloud/spring-cloud-bootstrap/README.MD index d6f8faf31e..8afbc945ff 100644 --- a/spring-cloud/spring-cloud-bootstrap/README.MD +++ b/spring-cloud/spring-cloud-bootstrap/README.MD @@ -1,3 +1,8 @@ ### Relevant Articles: - [Spring Cloud – Bootstrapping](http://www.baeldung.com/spring-cloud-bootstrapping) - [Spring Cloud – Securing Services](http://www.baeldung.com/spring-cloud-securing-services) + +- To run the project copy the appliction-config folder to c:\Users\{username}\ on Windows or /Users/{username}/ on *nix. Then open a git bash terminal in application-config and run: + - git init + - git add . + - git commit -m "First commit" From bebef9a230bc5ffe91a3c6980daa9d7ed572db56 Mon Sep 17 00:00:00 2001 From: tschiman Date: Sun, 12 Feb 2017 16:01:28 -0700 Subject: [PATCH 04/10] BAEL-574 update the readme --- spring-cloud/spring-cloud-bootstrap/README.MD | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/README.MD b/spring-cloud/spring-cloud-bootstrap/README.MD index 8afbc945ff..251c861830 100644 --- a/spring-cloud/spring-cloud-bootstrap/README.MD +++ b/spring-cloud/spring-cloud-bootstrap/README.MD @@ -2,7 +2,11 @@ - [Spring Cloud – Bootstrapping](http://www.baeldung.com/spring-cloud-bootstrapping) - [Spring Cloud – Securing Services](http://www.baeldung.com/spring-cloud-securing-services) -- To run the project copy the appliction-config folder to c:\Users\{username}\ on Windows or /Users/{username}/ on *nix. Then open a git bash terminal in application-config and run: - - git init - - git add . - - git commit -m "First commit" +- To run the project: + - copy the appliction-config folder to c:\Users\{username}\ on Windows or /Users/{username}/ on *nix. Then open a git bash terminal in application-config and run: + - git init + - git add . + - git commit -m "First commit" + - start the config server + - start the discover server + - start all the other servers in any order (gateway, svc-book, svc-rating, zipkin) From c4b693745bf120757ec92e76e3379b02a3e5aa67 Mon Sep 17 00:00:00 2001 From: tschiman Date: Tue, 14 Feb 2017 23:53:23 -0700 Subject: [PATCH 05/10] BAEL-574 adding Zipkin Span Reporters to define the URL from eureka --- .../gateway/EurekaZipkinSpanReporter.java | 32 +++++++++++++++++++ .../src/main/resources/bootstrap.properties | 2 +- .../svcbook/EurekaZipkinSpanReporter.java | 32 +++++++++++++++++++ .../src/main/resources/bootstrap.properties | 2 +- .../svcrating/EurekaZipkinSpanReporter.java | 32 +++++++++++++++++++ .../src/main/resources/bootstrap.properties | 2 +- 6 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java new file mode 100644 index 0000000000..87f9c0506c --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java @@ -0,0 +1,32 @@ +package com.baeldung.spring.cloud.bootstrap.gateway; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; +import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; +import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; +import org.springframework.context.annotation.Configuration; +import zipkin.Span; + +@Configuration +public class EurekaZipkinSpanReporter implements ZipkinSpanReporter { + + @Autowired + private EurekaClient eurekaClient; + @Autowired + private SpanMetricReporter spanMetricReporter; + @Autowired + private ZipkinProperties zipkinProperties; + @Value("${spring.sleuth.web.skipPattern}") + private String skipPattern; + + @Override + public void report(Span span) { + InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); + HttpZipkinSpanReporter reporter = new HttpZipkinSpanReporter(instance.getHomePageUrl(), zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + if (!span.name.matches(skipPattern)) reporter.report(span); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties index ca453e1007..5756b8205a 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties @@ -11,5 +11,5 @@ zuul.routes.zipkin.sensitive-headers=Set-Cookie,Authorization hystrix.command.zipkin.execution.isolation.thread.timeoutInMilliseconds=600000 spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(.+?cleanup.*|.+favicon.*) +spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) spring.zipkin.base-url=http://zipkin \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java new file mode 100644 index 0000000000..96b514ca3f --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java @@ -0,0 +1,32 @@ +package com.baeldung.spring.cloud.bootstrap.svcbook; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; +import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; +import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; +import org.springframework.context.annotation.Configuration; +import zipkin.Span; + +@Configuration +public class EurekaZipkinSpanReporter implements ZipkinSpanReporter { + + @Autowired + private EurekaClient eurekaClient; + @Autowired + private SpanMetricReporter spanMetricReporter; + @Autowired + private ZipkinProperties zipkinProperties; + @Value("${spring.sleuth.web.skipPattern}") + private String skipPattern; + + @Override + public void report(Span span) { + InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); + HttpZipkinSpanReporter reporter = new HttpZipkinSpanReporter(instance.getHomePageUrl(), zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + if (!span.name.matches(skipPattern)) reporter.report(span); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties index e8360ecb6f..aa24cb2ab3 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties @@ -7,4 +7,4 @@ spring.cloud.config.password=configPassword eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ spring.sleuth.sampler.percentage=1.0 -spring.zipkin.base-url=http://zipkin \ No newline at end of file +spring.sleuth.web.skipPattern=(^cleanup.*) \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java new file mode 100644 index 0000000000..39f9c7c96e --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java @@ -0,0 +1,32 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating; + +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; +import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; +import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; +import org.springframework.context.annotation.Configuration; +import zipkin.Span; + +@Configuration +public class EurekaZipkinSpanReporter implements ZipkinSpanReporter { + + @Autowired + private EurekaClient eurekaClient; + @Autowired + private SpanMetricReporter spanMetricReporter; + @Autowired + private ZipkinProperties zipkinProperties; + @Value("${spring.sleuth.web.skipPattern}") + private String skipPattern; + + @Override + public void report(Span span) { + InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); + HttpZipkinSpanReporter reporter = new HttpZipkinSpanReporter(instance.getHomePageUrl(), zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + if (!span.name.matches(skipPattern)) reporter.report(span); + } +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties index a43e7d76a5..ccbd6eeffe 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties @@ -7,4 +7,4 @@ spring.cloud.config.password=configPassword eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ spring.sleuth.sampler.percentage=1.0 -spring.zipkin.base-url=http://zipkin +spring.sleuth.web.skipPattern=(^cleanup.*) From 551d124e8b463bd50b27c912478c0d820bef69ce Mon Sep 17 00:00:00 2001 From: tschiman Date: Wed, 15 Feb 2017 20:13:27 -0700 Subject: [PATCH 06/10] BAEL-574 adding reporters as beans instead of config classes --- .../gateway/EurekaZipkinSpanReporter.java | 32 --------- .../bootstrap/gateway/GatewayApplication.java | 67 ++++++++++++++----- .../svcbook/BookServiceApplication.java | 39 +++++++++++ .../svcbook/EurekaZipkinSpanReporter.java | 32 --------- .../src/main/resources/bootstrap.properties | 3 +- .../svcrating/EurekaZipkinSpanReporter.java | 32 --------- .../svcrating/RatingServiceApplication.java | 38 +++++++++++ 7 files changed, 130 insertions(+), 113 deletions(-) delete mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java delete mode 100644 spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java delete mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java deleted file mode 100644 index 87f9c0506c..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/EurekaZipkinSpanReporter.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.gateway; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.sleuth.metric.SpanMetricReporter; -import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; -import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; -import org.springframework.context.annotation.Configuration; -import zipkin.Span; - -@Configuration -public class EurekaZipkinSpanReporter implements ZipkinSpanReporter { - - @Autowired - private EurekaClient eurekaClient; - @Autowired - private SpanMetricReporter spanMetricReporter; - @Autowired - private ZipkinProperties zipkinProperties; - @Value("${spring.sleuth.web.skipPattern}") - private String skipPattern; - - @Override - public void report(Span span) { - InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - HttpZipkinSpanReporter reporter = new HttpZipkinSpanReporter(instance.getHomePageUrl(), zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); - if (!span.name.matches(skipPattern)) reporter.report(span); - } -} diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java index b5ae1e4e7b..16aae66cab 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/java/com/baeldung/spring/cloud/bootstrap/gateway/GatewayApplication.java @@ -1,6 +1,9 @@ package com.baeldung.spring.cloud.bootstrap.gateway; +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; @@ -8,8 +11,13 @@ import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.ribbon.RibbonClientSpecification; import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; +import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; +import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; +import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; +import zipkin.Span; import java.util.ArrayList; import java.util.List; @@ -18,23 +26,50 @@ import java.util.List; @EnableZuulProxy @EnableEurekaClient public class GatewayApplication { - public static void main(String[] args) { - SpringApplication.run(GatewayApplication.class, args); - } + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } - @Autowired(required = false) - private List configurations = new ArrayList<>(); + @Autowired(required = false) + private List configurations = new ArrayList<>(); + @Autowired + private EurekaClient eurekaClient; + @Autowired + private SpanMetricReporter spanMetricReporter; + @Autowired + private ZipkinProperties zipkinProperties; + @Value("${spring.sleuth.web.skipPattern}") + private String skipPattern; - @Bean - @LoadBalanced - RestTemplate restTemplate() { - return new RestTemplate(); - } + @Bean + @LoadBalanced + RestTemplate restTemplate() { + return new RestTemplate(); + } - @Bean - public SpringClientFactory springClientFactory() { - SpringClientFactory factory = new SpringClientFactory(); - factory.setConfigurations(this.configurations); - return factory; - } + @Bean + public SpringClientFactory springClientFactory() { + SpringClientFactory factory = new SpringClientFactory(); + factory.setConfigurations(this.configurations); + return factory; + } + + @Bean + public ZipkinSpanReporter makeZipkinSpanReporter() { + return new ZipkinSpanReporter() { + private HttpZipkinSpanReporter delegate; + private String baseUrl; + + @Override + public void report(Span span) { + InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); + if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { + baseUrl = instance.getHomePageUrl(); + delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + if (!span.name.matches(skipPattern)) delegate.report(span); + } + if (!span.name.matches(skipPattern)) delegate.report(span); + } + }; + } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java index c5499cd924..63ff0fb134 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/BookServiceApplication.java @@ -1,13 +1,52 @@ package com.baeldung.spring.cloud.bootstrap.svcbook; +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; +import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; +import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; +import org.springframework.context.annotation.Bean; +import zipkin.Span; @SpringBootApplication @EnableEurekaClient public class BookServiceApplication { + + @Autowired + private EurekaClient eurekaClient; + @Autowired + private SpanMetricReporter spanMetricReporter; + @Autowired + private ZipkinProperties zipkinProperties; + @Value("${spring.sleuth.web.skipPattern}") + private String skipPattern; + public static void main(String[] args) { SpringApplication.run(BookServiceApplication.class, args); } + + @Bean + public ZipkinSpanReporter makeZipkinSpanReporter() { + return new ZipkinSpanReporter() { + private HttpZipkinSpanReporter delegate; + private String baseUrl; + + @Override + public void report(Span span) { + InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); + if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { + baseUrl = instance.getHomePageUrl(); + delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + if (!span.name.matches(skipPattern)) delegate.report(span); + } + if (!span.name.matches(skipPattern)) delegate.report(span); + } + }; + } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java deleted file mode 100644 index 96b514ca3f..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/java/com/baeldung/spring/cloud/bootstrap/svcbook/EurekaZipkinSpanReporter.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.svcbook; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.sleuth.metric.SpanMetricReporter; -import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; -import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; -import org.springframework.context.annotation.Configuration; -import zipkin.Span; - -@Configuration -public class EurekaZipkinSpanReporter implements ZipkinSpanReporter { - - @Autowired - private EurekaClient eurekaClient; - @Autowired - private SpanMetricReporter spanMetricReporter; - @Autowired - private ZipkinProperties zipkinProperties; - @Value("${spring.sleuth.web.skipPattern}") - private String skipPattern; - - @Override - public void report(Span span) { - InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - HttpZipkinSpanReporter reporter = new HttpZipkinSpanReporter(instance.getHomePageUrl(), zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); - if (!span.name.matches(skipPattern)) reporter.report(span); - } -} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties index aa24cb2ab3..f183ee9156 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties @@ -7,4 +7,5 @@ spring.cloud.config.password=configPassword eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(^cleanup.*) \ No newline at end of file +spring.sleuth.web.skipPattern=(^cleanup.*) +spring.zipkin.locator.discovery.enabled=true \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java deleted file mode 100644 index 39f9c7c96e..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/EurekaZipkinSpanReporter.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.svcrating; - -import com.netflix.appinfo.InstanceInfo; -import com.netflix.discovery.EurekaClient; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cloud.sleuth.metric.SpanMetricReporter; -import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; -import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; -import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; -import org.springframework.context.annotation.Configuration; -import zipkin.Span; - -@Configuration -public class EurekaZipkinSpanReporter implements ZipkinSpanReporter { - - @Autowired - private EurekaClient eurekaClient; - @Autowired - private SpanMetricReporter spanMetricReporter; - @Autowired - private ZipkinProperties zipkinProperties; - @Value("${spring.sleuth.web.skipPattern}") - private String skipPattern; - - @Override - public void report(Span span) { - InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); - HttpZipkinSpanReporter reporter = new HttpZipkinSpanReporter(instance.getHomePageUrl(), zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); - if (!span.name.matches(skipPattern)) reporter.report(span); - } -} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java index 61074e0bcc..0d85c5c825 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/RatingServiceApplication.java @@ -1,13 +1,51 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; +import com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.cloud.sleuth.metric.SpanMetricReporter; +import org.springframework.cloud.sleuth.zipkin.HttpZipkinSpanReporter; +import org.springframework.cloud.sleuth.zipkin.ZipkinProperties; +import org.springframework.cloud.sleuth.zipkin.ZipkinSpanReporter; +import org.springframework.context.annotation.Bean; +import zipkin.Span; @SpringBootApplication @EnableEurekaClient public class RatingServiceApplication { + @Autowired + private EurekaClient eurekaClient; + @Autowired + private SpanMetricReporter spanMetricReporter; + @Autowired + private ZipkinProperties zipkinProperties; + @Value("${spring.sleuth.web.skipPattern}") + private String skipPattern; + public static void main(String[] args) { SpringApplication.run(RatingServiceApplication.class, args); } + + @Bean + public ZipkinSpanReporter makeZipkinSpanReporter() { + return new ZipkinSpanReporter() { + private HttpZipkinSpanReporter delegate; + private String baseUrl; + + @Override + public void report(Span span) { + InstanceInfo instance = eurekaClient.getNextServerFromEureka("zipkin", false); + if (!(baseUrl != null && instance.getHomePageUrl().equals(baseUrl))) { + baseUrl = instance.getHomePageUrl(); + delegate = new HttpZipkinSpanReporter(baseUrl, zipkinProperties.getFlushInterval(), zipkinProperties.getCompression().isEnabled(), spanMetricReporter); + if (!span.name.matches(skipPattern)) delegate.report(span); + } + if (!span.name.matches(skipPattern)) delegate.report(span); + } + }; + } } \ No newline at end of file From cb5e2ce8f1553423e768a84199379f360fcf5481 Mon Sep 17 00:00:00 2001 From: tschiman Date: Wed, 15 Feb 2017 20:31:45 -0700 Subject: [PATCH 07/10] BAEL-574 deleting commented out code --- spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml b/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml index 9d43590366..c2fd7cd2dc 100644 --- a/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/zipkin/pom.xml @@ -34,19 +34,6 @@ zipkin-autoconfigure-ui runtime - - - - - - - - - - - - - org.springframework.boot From 6f78b05d03da52b4c66da521500a85beead8f473 Mon Sep 17 00:00:00 2001 From: tschiman Date: Wed, 15 Feb 2017 21:07:43 -0700 Subject: [PATCH 08/10] BAEL-574 moving configuration to config server controlled files --- .../application-config/book-service.properties | 3 +++ .../application-config/gateway.properties | 6 +++++- .../application-config/rating-service.properties | 3 +++ .../gateway/src/main/resources/bootstrap.properties | 10 +--------- .../svc-book/src/main/resources/bootstrap.properties | 6 +----- .../svc-rating/src/main/resources/bootstrap.properties | 3 --- 6 files changed, 13 insertions(+), 18 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/application-config/book-service.properties b/spring-cloud/spring-cloud-bootstrap/application-config/book-service.properties index e1244a0cf0..49f7d1ed91 100644 --- a/spring-cloud/spring-cloud-bootstrap/application-config/book-service.properties +++ b/spring-cloud/spring-cloud-bootstrap/application-config/book-service.properties @@ -15,3 +15,6 @@ logging.level.org.springframework.security=debug spring.redis.host=localhost spring.redis.port=6379 + +spring.sleuth.sampler.percentage=1.0 +spring.sleuth.web.skipPattern=(^cleanup.*) diff --git a/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties b/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties index 09f7f3bf4a..e2686ae64c 100644 --- a/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties +++ b/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties @@ -24,4 +24,8 @@ logging.level.org.springframework.security=debug logging.level.org.springframework.cloud.netflix.zuul=debug spring.redis.host=localhost -spring.redis.port=6379 \ No newline at end of file +spring.redis.port=6379 + +spring.sleuth.sampler.percentage=1.0 +spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) +spring.zipkin.base-url=http://zipkin \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties b/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties index 4817d12c83..b7cbb6fbd6 100644 --- a/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties @@ -15,3 +15,6 @@ logging.level.org.springframework.security=debug spring.redis.host=localhost spring.redis.port=6379 + +spring.sleuth.sampler.percentage=1.0 +spring.sleuth.web.skipPattern=(^cleanup.*) diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties index 5756b8205a..43491ff36b 100644 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/gateway/src/main/resources/bootstrap.properties @@ -4,12 +4,4 @@ spring.cloud.config.discovery.enabled=true spring.cloud.config.username=configUser spring.cloud.config.password=configPassword -eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ - -zuul.routes.zipkin.path=/zipkin/** -zuul.routes.zipkin.sensitive-headers=Set-Cookie,Authorization -hystrix.command.zipkin.execution.isolation.thread.timeoutInMilliseconds=600000 - -spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) -spring.zipkin.base-url=http://zipkin \ No newline at end of file +eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties index f183ee9156..481cdc182c 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-book/src/main/resources/bootstrap.properties @@ -4,8 +4,4 @@ spring.cloud.config.discovery.enabled=true spring.cloud.config.username=configUser spring.cloud.config.password=configPassword -eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ - -spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(^cleanup.*) -spring.zipkin.locator.discovery.enabled=true \ No newline at end of file +eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ \ No newline at end of file diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties index ccbd6eeffe..be5cf7f1e1 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/resources/bootstrap.properties @@ -5,6 +5,3 @@ spring.cloud.config.username=configUser spring.cloud.config.password=configPassword eureka.client.serviceUrl.defaultZone=http://discUser:discPassword@localhost:8082/eureka/ - -spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(^cleanup.*) From 0d31cab067788ec1d2926de7b0beb2bf06f2fb38 Mon Sep 17 00:00:00 2001 From: tschiman Date: Mon, 27 Feb 2017 20:52:22 -0700 Subject: [PATCH 09/10] BAEL-574 removing zipkin URL since we are setting it in our custom configuration --- .../application-config/gateway.properties | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties b/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties index e2686ae64c..e9e593284c 100644 --- a/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties +++ b/spring-cloud/spring-cloud-bootstrap/application-config/gateway.properties @@ -27,5 +27,4 @@ spring.redis.host=localhost spring.redis.port=6379 spring.sleuth.sampler.percentage=1.0 -spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) -spring.zipkin.base-url=http://zipkin \ No newline at end of file +spring.sleuth.web.skipPattern=(^cleanup.*|.+favicon.*) \ No newline at end of file From 73e195b190a58899a24fbbf699a67ac1081e0524 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Thu, 2 Mar 2017 05:49:21 +0100 Subject: [PATCH 10/10] BAEL-574 - Removing obsolete test --- .../bootstrap/gateway/IntegrationTest.java | 201 ------------------ 1 file changed, 201 deletions(-) delete mode 100644 spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java diff --git a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java b/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java deleted file mode 100644 index 16057edc48..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/gateway/src/test/java/com/baeldung/spring/cloud/bootstrap/gateway/IntegrationTest.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.gateway; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import org.apache.http.entity.ContentType; -import org.junit.Assert; -import org.junit.Test; -import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.http.*; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; - -public class IntegrationTest { - - private TestRestTemplate testRestTemplate = new TestRestTemplate(); - private String testUrl = "http://localhost:8080"; - - @Test - public void testAccess() throws Exception { - ResponseEntity response = testRestTemplate.getForEntity(testUrl + "/book-service/books", String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //try the protected resource and confirm the redirect to login - response = testRestTemplate.getForEntity(testUrl + "/book-service/books/1", String.class); - Assert.assertEquals(HttpStatus.FOUND, response.getStatusCode()); - Assert.assertEquals("http://localhost:8080/login", response.getHeaders().get("Location").get(0)); - - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "user"); - form.add("password", "password"); - response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - HttpEntity httpEntity = new HttpEntity<>(headers); - - addBook(); - - //request the protected resource - response = testRestTemplate.exchange(testUrl + "/book-service/books/1", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - addRatings(); - - //request the admin protected resource to determine it is still protected - response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); - - //login as the admin - form.clear(); - form.add("username", "admin"); - form.add("password", "admin"); - response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - httpEntity = new HttpEntity<>(headers); - - //request the protected resource - response = testRestTemplate.exchange(testUrl + "/rating-service/ratings", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - Assert.assertNotNull(response.getBody()); - - //request the discovery resources as the admin - response = testRestTemplate.exchange(testUrl + "/discovery", HttpMethod.GET, httpEntity, String.class); - Assert.assertEquals(HttpStatus.OK, response.getStatusCode()); - } - - private void addRatings() { - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "user"); - form.add("password", "password"); - ResponseEntity response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType()); - Rating rating = new Rating(1L, 4); - - HttpEntity httpEntity = new HttpEntity<>(rating, headers); - - //request the protected resource - ResponseEntity bookResponse = testRestTemplate.postForEntity(testUrl + "/rating-service/ratings", httpEntity, Rating.class); - Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode()); - Assert.assertEquals(rating.getBookId(), bookResponse.getBody().getBookId()); - Assert.assertEquals(rating.getStars(), bookResponse.getBody().getStars()); - } - - private void addBook(){ - //login as user/password - MultiValueMap form = new LinkedMultiValueMap<>(); - form.add("username", "admin"); - form.add("password", "admin"); - ResponseEntity response = testRestTemplate.postForEntity(testUrl + "/login", form, String.class); - - //extract the session from the cookie and propagate it to the next request - String sessionCookie = response.getHeaders().get("Set-Cookie").get(0).split(";")[0]; - HttpHeaders headers = new HttpHeaders(); - headers.add("Cookie", sessionCookie); - headers.add("ContentType", ContentType.APPLICATION_JSON.getMimeType()); - Book book = new Book("Baeldung", "How to spring cloud"); - - HttpEntity httpEntity = new HttpEntity<>(book, headers); - - //request the protected resource - ResponseEntity bookResponse = testRestTemplate.postForEntity(testUrl + "/book-service/books", httpEntity, Book.class); - Assert.assertEquals(HttpStatus.OK, bookResponse.getStatusCode()); - Assert.assertEquals(book.getAuthor(), bookResponse.getBody().getAuthor()); - Assert.assertEquals(book.getTitle(), bookResponse.getBody().getTitle()); - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Book { - - private Long id; - private String author; - private String title; - - public Book() { - } - - public Book(String author, String title) { - this.author = author; - this.title = title; - } - - public String getAuthor() { - return author; - } - - public void setAuthor(String author) { - this.author = author; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - } - - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Rating { - private Long id; - private Long bookId; - private int stars; - - public Rating() { - } - - public Rating(Long bookId, int stars) { - this.bookId = bookId; - this.stars = stars; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Long getBookId() { - return bookId; - } - - public void setBookId(Long bookId) { - this.bookId = bookId; - } - - public int getStars() { - return stars; - } - - public void setStars(int stars) { - this.stars = stars; - } - } - - -} \ No newline at end of file