From c03ca0e9983b025316bdd44902f32c2592303834 Mon Sep 17 00:00:00 2001 From: Ahamed Mustafa Date: Fri, 16 Jun 2017 21:03:43 +0100 Subject: [PATCH 1/4] BAEL-951 Self-Healing Services with Spring Cloud - C1 --- .../rating-service.properties | 3 + .../spring-cloud-bootstrap/svc-rating/pom.xml | 139 ++++++++++-------- .../bootstrap/svcrating/CacheConfig.java | 30 ++++ .../bootstrap/svcrating/CacheProperties.java | 24 +++ .../svcrating/RatingServiceApplication.java | 8 +- .../bootstrap/svcrating/SecurityConfig.java | 8 +- .../bootstrap/svcrating/SessionConfig.java | 18 +++ .../bootstrap/svcrating/rating/Rating.java | 52 ++++++- .../rating/RatingCacheRepository.java | 13 ++ .../rating/RatingCacheRepositoryImpl.java | 77 ++++++++++ .../svcrating/rating/RatingService.java | 67 +++++++-- 11 files changed, 353 insertions(+), 86 deletions(-) create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java create mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java 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 b7cbb6fbd6..6ee1a73d29 100644 --- a/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties @@ -16,5 +16,8 @@ logging.level.org.springframework.security=debug spring.redis.host=localhost spring.redis.port=6379 +cache.redis.hostName=localhost +cache.redis.port=6379 + spring.sleuth.sampler.percentage=1.0 spring.sleuth.web.skipPattern=(^cleanup.*) diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml index 7879031a2a..736a6114cf 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/pom.xml @@ -1,78 +1,87 @@ - 4.0.0 + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - com.baeldung.spring.cloud - svc-rating - 1.0.0-SNAPSHOT + com.baeldung.spring.cloud + svc-rating + 1.0.0-SNAPSHOT - - parent-boot-4 - com.baeldung - 0.0.1-SNAPSHOT - ../../../parent-boot-4 - + + parent-boot-4 + com.baeldung + 0.0.1-SNAPSHOT + ../../../parent-boot-4 + - - - org.springframework.cloud - spring-cloud-starter-config - - - org.springframework.cloud - spring-cloud-starter-eureka - - - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-security - + + + org.springframework.cloud + spring-cloud-starter-config + + + org.springframework.cloud + spring-cloud-starter-eureka + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-security + - - org.springframework.session - spring-session - - - org.springframework.boot - spring-boot-starter-data-redis - + + org.springframework.session + spring-session + + + org.springframework.boot + spring-boot-starter-data-redis + - - org.springframework.boot - spring-boot-starter-data-jpa - + + org.springframework.boot + spring-boot-starter-data-jpa + - - com.h2database - h2 - runtime - + + org.springframework.cloud + spring-cloud-starter-hystrix + + + org.springframework.boot + spring-boot-starter-actuator + - - org.springframework.cloud - spring-cloud-starter-zipkin - + + com.h2database + h2 + runtime + - + + org.springframework.cloud + spring-cloud-starter-zipkin + - - - - org.springframework.cloud - spring-cloud-dependencies - ${spring-cloud-dependencies.version} - pom - import - - - + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud-dependencies.version} + pom + import + + + + + + Brixton.SR7 + - - Brixton.SR7 - - \ 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/CacheConfig.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java new file mode 100644 index 0000000000..c06571a8fa --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java @@ -0,0 +1,30 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; + +@Configuration +@EnableConfigurationProperties({CacheProperties.class}) +public class CacheConfig { + + @Autowired + CacheProperties cacheProperties; + + @Bean(name="cacheConnectionFactory") + @Qualifier("cacheJedisConnectionFactory") + JedisConnectionFactory cacheConnectionFactory() { + System.out.println(">>>>>>>>>>>>>>>>>>>>>Qualified Jedis Conn.Name.."+cacheProperties.hostName); + System.out.println(">>>>>>>>>>>>>>>>>>>>>Qualified Jedis Conn.Port.."+cacheProperties.port); + JedisConnectionFactory factory = new JedisConnectionFactory(); + factory.setHostName(cacheProperties.hostName); + factory.setPort(cacheProperties.port); + factory.setUsePool(true); + factory.afterPropertiesSet(); + return factory; + } + +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java new file mode 100644 index 0000000000..0016522281 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java @@ -0,0 +1,24 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix="cache.redis") +public class CacheProperties { +public String hostName; +public int port; + +public String getHostName() { + return hostName; +} +public void setHostName(String hostName) { + this.hostName = hostName; +} +public int getPort() { + return port; +} +public void setPort(int port) { + this.port = port; +} + + +} 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 0d85c5c825..c1d92376e3 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,21 +1,25 @@ 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.netflix.hystrix.EnableHystrix; 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 com.netflix.appinfo.InstanceInfo; +import com.netflix.discovery.EurekaClient; + import zipkin.Span; @SpringBootApplication @EnableEurekaClient +@EnableHystrix public class RatingServiceApplication { @Autowired private EurekaClient eurekaClient; 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 171fbba7af..a20c81f244 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 @@ -20,17 +20,21 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { - http.httpBasic() - .disable() + http .authorizeRequests() .regexMatchers("^/ratings\\?bookId.*$").authenticated() .antMatchers(HttpMethod.POST,"/ratings").authenticated() + .antMatchers(HttpMethod.GET,"/ratings/**").authenticated() .antMatchers(HttpMethod.PATCH,"/ratings/*").hasRole("ADMIN") .antMatchers(HttpMethod.DELETE,"/ratings/*").hasRole("ADMIN") .antMatchers(HttpMethod.GET,"/ratings").hasRole("ADMIN") + .antMatchers(HttpMethod.GET,"/hystrix*").permitAll() .anyRequest().authenticated() .and() + .httpBasic().and() .csrf() .disable(); + + } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java index 62bc701868..6e8fcd10d4 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/SessionConfig.java @@ -1,10 +1,28 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.env.Environment; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; import org.springframework.session.web.context.AbstractHttpSessionApplicationInitializer; @Configuration @EnableRedisHttpSession public class SessionConfig extends AbstractHttpSessionApplicationInitializer { + @Autowired + Environment properties; + + @Bean + @Primary + public JedisConnectionFactory connectionFactory() { + JedisConnectionFactory factory = new JedisConnectionFactory(); + factory.setHostName(properties.getProperty("spring.redis.host","localhost")); + factory.setPort(properties.getProperty("spring.redis.port", Integer.TYPE,6379)); + factory.afterPropertiesSet(); + factory.setUsePool(true); + return factory; + } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java index c37099f3c1..348d854b5c 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java @@ -1,22 +1,34 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.Transient; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @JsonIgnoreProperties(ignoreUnknown = true) -public class Rating { +public class Rating implements Serializable{ + /** + * + */ + private static final long serialVersionUID = 3308900941650386473L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; private Long bookId; private int stars; + @Transient + private boolean fromCache; + @Transient + private Long cachedTS=-1L; + public Rating() { } @@ -54,4 +66,40 @@ public class Rating { public void setStars(int stars) { this.stars = stars; } + + public boolean isFromCache() { + return fromCache; + } + + public void setFromCache(boolean fromCache) { + this.fromCache = fromCache; + } + + public Long getCachedTS() { + return cachedTS; + } + + public void setCachedTS(Long cachedTS) { + this.cachedTS = cachedTS; + } + + @Override + public String toString() { + return "Rating [" + id + "," + bookId + "," + stars + "," + cachedTS + "]"; + } + + public static Rating fromString(String ratingAsStr){ + + if(ratingAsStr == null || ratingAsStr.isEmpty()) + return null; + String[] attributeVals=ratingAsStr.substring(8,ratingAsStr.length()-1).split("[,]"); + + Rating rating=new Rating(); + rating.setId(Long.valueOf(attributeVals[0])); + rating.setBookId(Long.valueOf(attributeVals[1])); + rating.setStars(Integer.valueOf(attributeVals[2])); + rating.setCachedTS(Long.valueOf(attributeVals[3])); + + return rating; + } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java new file mode 100644 index 0000000000..a807a61862 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java @@ -0,0 +1,13 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; + +import java.util.List; + +public interface RatingCacheRepository { + + List findCachedRatingsByBookId(Long bookId); + Rating findCachedRatingById(Long ratingId); + List findAllCachedRatings(); + boolean createRating(Rating persisted); + boolean updateRating(Rating persisted); + boolean deleteRating(Long ratingId); +} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java new file mode 100644 index 0000000000..78f83484b2 --- /dev/null +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java @@ -0,0 +1,77 @@ +package com.baeldung.spring.cloud.bootstrap.svcrating.rating; + +import java.util.List; +import java.util.stream.Collectors; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Repository; + +@Repository +public class RatingCacheRepositoryImpl implements InitializingBean, RatingCacheRepository { + + + @Autowired + @Qualifier("cacheJedisConnectionFactory") + private JedisConnectionFactory cacheConnectionFactory; + + private StringRedisTemplate redisTemplate; + private ValueOperations valueOps; + private SetOperations setOps; + + + public List findCachedRatingsByBookId(Long bookId){ + return setOps.members("book-" + bookId) + .stream() + .map(rtId -> Rating.fromString(valueOps.get(rtId))) + .map(rt -> { + rt.setFromCache(true); + return rt; + }) + .collect(Collectors.toList()); + } + + public Rating findCachedRatingById(Long ratingId) { + return Rating.fromString(valueOps.get("rating-" + ratingId)); + } + + public List findAllCachedRatings(){ + return redisTemplate.keys("rating*") + .stream() + .map(rtId -> Rating.fromString(valueOps.get(rtId))) + .collect(Collectors.toList()); + } + + public boolean createRating(Rating persisted){ + valueOps.set("rating-"+persisted.getId(), persisted.toString()); + setOps.add("book-"+persisted.getBookId(), "rating-"+persisted.getId()); + return true; + } + + public boolean updateRating(Rating persisted){ + valueOps.set("rating-"+persisted.getId(), persisted.toString()); + return true; + } + + public boolean deleteRating(Long ratingId){ + Rating toDel=Rating.fromString(valueOps.get("rating-"+ratingId)); + setOps.remove("book-"+toDel.getBookId(), "rating-"+ratingId); + redisTemplate.delete("rating-"+ratingId); + return true; + } + + @Override + public void afterPropertiesSet() throws Exception { + + this.redisTemplate = new StringRedisTemplate(cacheConnectionFactory); + + this.valueOps = redisTemplate.opsForValue(); + this.setOps=redisTemplate.opsForSet(); + + } +} 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 index 6ab5e0acff..4f099da0df 100644 --- 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 @@ -1,46 +1,80 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; -import com.google.common.base.Preconditions; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; + 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; +import com.google.common.base.Preconditions; +import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @Service @Transactional(readOnly = true) -public class RatingService { +public class RatingService{ @Autowired private RatingRepository ratingRepository; + + @Autowired + private RatingCacheRepository cacheRepository; + + @HystrixCommand(commandKey="ratingsByBookIdFromDB",fallbackMethod="findCachedRatingsByBookId") + public List findRatingsByBookId(Long bookId) { + if(bookId==2) + throw new IllegalArgumentException("BookID 2 redirects to cache"); + + return ratingRepository.findRatingsByBookId(bookId); + } + + @HystrixCommand(commandKey="ratingsByBookIdFromCache",fallbackMethod="defaultRatingsByBookId") + public List findCachedRatingsByBookId(Long bookId){ + return cacheRepository.findCachedRatingsByBookId(bookId); + } + + public List defaultRatingsByBookId(Long bookId){ + return Collections.emptyList(); + } + + + @HystrixCommand(commandKey="ratingsFromDB",fallbackMethod="findAllCachedRatings") + public List findAllRatings() { + return ratingRepository.findAll(); + } + + public List findAllCachedRatings(){ + return cacheRepository.findAllCachedRatings(); + } + + @HystrixCommand(commandKey = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById", ignoreExceptions = { RatingNotFoundException.class }) 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 Rating findCachedRatingById(Long ratingId){ + return cacheRepository.findCachedRatingById(ratingId); } - - public List findAllRatings() { - return ratingRepository.findAll(); - } - + @Transactional(propagation = Propagation.REQUIRED) public Rating createRating(Rating rating) { - final Rating newRating = new Rating(); + Rating newRating = new Rating(); newRating.setBookId(rating.getBookId()); newRating.setStars(rating.getStars()); - return ratingRepository.save(newRating); + Rating persisted=ratingRepository.save(newRating); + cacheRepository.createRating(persisted); + return persisted; } @Transactional(propagation = Propagation.REQUIRED) public void deleteRating(Long ratingId) { ratingRepository.delete(ratingId); + cacheRepository.deleteRating(ratingId); } @Transactional(propagation = Propagation.REQUIRED) @@ -54,7 +88,9 @@ public class RatingService { break; } }); - return ratingRepository.save(rating); + Rating persisted= ratingRepository.save(rating); + cacheRepository.updateRating(persisted); + return persisted; } @Transactional(propagation = Propagation.REQUIRED) @@ -64,4 +100,5 @@ public class RatingService { Preconditions.checkNotNull(ratingRepository.findOne(ratingId)); return ratingRepository.save(rating); } + } From 0021df46372238267587a4349e106783bc2e3dbc Mon Sep 17 00:00:00 2001 From: Ahamed Mustafa Date: Tue, 20 Jun 2017 19:41:05 +0100 Subject: [PATCH 2/4] BAEL-951 Self-Healing Services with Spring Cloud - C2 --- .../rating-service.properties | 3 - .../bootstrap/svcrating/CacheConfig.java | 6 - .../bootstrap/svcrating/CacheProperties.java | 3 - .../svcrating/RatingServiceApplication.java | 14 ++ .../bootstrap/svcrating/SecurityConfig.java | 3 +- .../bootstrap/svcrating/rating/Rating.java | 25 +--- .../rating/RatingCacheRepositoryImpl.java | 121 ++++++++++++------ .../svcrating/rating/RatingService.java | 37 ++---- 8 files changed, 113 insertions(+), 99 deletions(-) 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 6ee1a73d29..b7cbb6fbd6 100644 --- a/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties +++ b/spring-cloud/spring-cloud-bootstrap/application-config/rating-service.properties @@ -16,8 +16,5 @@ logging.level.org.springframework.security=debug spring.redis.host=localhost spring.redis.port=6379 -cache.redis.hostName=localhost -cache.redis.port=6379 - spring.sleuth.sampler.percentage=1.0 spring.sleuth.web.skipPattern=(^cleanup.*) diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java index c06571a8fa..d2332f86a8 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java @@ -2,13 +2,9 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -@Configuration -@EnableConfigurationProperties({CacheProperties.class}) public class CacheConfig { @Autowired @@ -17,8 +13,6 @@ public class CacheConfig { @Bean(name="cacheConnectionFactory") @Qualifier("cacheJedisConnectionFactory") JedisConnectionFactory cacheConnectionFactory() { - System.out.println(">>>>>>>>>>>>>>>>>>>>>Qualified Jedis Conn.Name.."+cacheProperties.hostName); - System.out.println(">>>>>>>>>>>>>>>>>>>>>Qualified Jedis Conn.Port.."+cacheProperties.port); JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(cacheProperties.hostName); factory.setPort(cacheProperties.port); diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java index 0016522281..980038fa36 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java @@ -1,8 +1,5 @@ package com.baeldung.spring.cloud.bootstrap.svcrating; -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties(prefix="cache.redis") public class CacheProperties { public String hostName; public int port; 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 c1d92376e3..31ca69c139 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 @@ -10,16 +10,23 @@ 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.AdviceMode; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.transaction.annotation.EnableTransactionManagement; import com.netflix.appinfo.InstanceInfo; import com.netflix.discovery.EurekaClient; +import com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCommandAspect; import zipkin.Span; @SpringBootApplication @EnableEurekaClient @EnableHystrix +@EnableTransactionManagement(order=Ordered.LOWEST_PRECEDENCE, mode=AdviceMode.ASPECTJ) public class RatingServiceApplication { @Autowired private EurekaClient eurekaClient; @@ -52,4 +59,11 @@ public class RatingServiceApplication { } }; } + + @Bean + @Primary + @Order(value=Ordered.HIGHEST_PRECEDENCE) + public HystrixCommandAspect hystrixAspect() { + return new HystrixCommandAspect(); + } } \ 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 a20c81f244..9b6afc8059 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 @@ -24,11 +24,10 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter { .authorizeRequests() .regexMatchers("^/ratings\\?bookId.*$").authenticated() .antMatchers(HttpMethod.POST,"/ratings").authenticated() - .antMatchers(HttpMethod.GET,"/ratings/**").authenticated() .antMatchers(HttpMethod.PATCH,"/ratings/*").hasRole("ADMIN") .antMatchers(HttpMethod.DELETE,"/ratings/*").hasRole("ADMIN") .antMatchers(HttpMethod.GET,"/ratings").hasRole("ADMIN") - .antMatchers(HttpMethod.GET,"/hystrix*").permitAll() + .antMatchers(HttpMethod.GET,"/hystrix").authenticated() .anyRequest().authenticated() .and() .httpBasic().and() diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java index 348d854b5c..2c7069926c 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/Rating.java @@ -12,7 +12,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @Entity @JsonIgnoreProperties(ignoreUnknown = true) -public class Rating implements Serializable{ +public class Rating implements Serializable { /** * @@ -27,8 +27,8 @@ public class Rating implements Serializable{ @Transient private boolean fromCache; @Transient - private Long cachedTS=-1L; - + private Long cachedTS = -1L; + public Rating() { } @@ -83,23 +83,4 @@ public class Rating implements Serializable{ this.cachedTS = cachedTS; } - @Override - public String toString() { - return "Rating [" + id + "," + bookId + "," + stars + "," + cachedTS + "]"; - } - - public static Rating fromString(String ratingAsStr){ - - if(ratingAsStr == null || ratingAsStr.isEmpty()) - return null; - String[] attributeVals=ratingAsStr.substring(8,ratingAsStr.length()-1).split("[,]"); - - Rating rating=new Rating(); - rating.setId(Long.valueOf(attributeVals[0])); - rating.setBookId(Long.valueOf(attributeVals[1])); - rating.setStars(Integer.valueOf(attributeVals[2])); - rating.setCachedTS(Long.valueOf(attributeVals[3])); - - return rating; - } } diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java index 78f83484b2..35eddefade 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java @@ -1,77 +1,120 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; +import java.io.IOException; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.SetOperations; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Repository; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; + @Repository public class RatingCacheRepositoryImpl implements InitializingBean, RatingCacheRepository { - @Autowired - @Qualifier("cacheJedisConnectionFactory") private JedisConnectionFactory cacheConnectionFactory; - - private StringRedisTemplate redisTemplate; - private ValueOperations valueOps; - private SetOperations setOps; - - public List findCachedRatingsByBookId(Long bookId){ + private StringRedisTemplate redisTemplate; + private ValueOperations valueOps; + private SetOperations setOps; + + private ObjectMapper jsonMapper; + + public List findCachedRatingsByBookId(Long bookId) { return setOps.members("book-" + bookId) .stream() - .map(rtId -> Rating.fromString(valueOps.get(rtId))) - .map(rt -> { - rt.setFromCache(true); - return rt; + .map(rtId -> { + try { + Rating rt = jsonMapper.readValue(valueOps.get(rtId), Rating.class); + rt.setFromCache(true); + return rt; + } catch (IOException ex) { + return null; + } }) .collect(Collectors.toList()); } - + public Rating findCachedRatingById(Long ratingId) { - return Rating.fromString(valueOps.get("rating-" + ratingId)); + + try { + return jsonMapper.readValue(valueOps.get("rating-" + ratingId), Rating.class); + } catch (IOException e) { + return null; + } + } - - public List findAllCachedRatings(){ - return redisTemplate.keys("rating*") + + public List findAllCachedRatings() { + List ratings = null; + + ratings = redisTemplate.keys("rating*") .stream() - .map(rtId -> Rating.fromString(valueOps.get(rtId))) + .map(rtId -> { + try { + + return jsonMapper.readValue(valueOps.get(rtId), Rating.class); + + } catch (IOException e) { + return null; + } + }) .collect(Collectors.toList()); + + return ratings; } - - public boolean createRating(Rating persisted){ - valueOps.set("rating-"+persisted.getId(), persisted.toString()); - setOps.add("book-"+persisted.getBookId(), "rating-"+persisted.getId()); - return true; + + public boolean createRating(Rating persisted) { + try { + valueOps.set("rating-" + persisted.getId(), jsonMapper.writeValueAsString(persisted)); + setOps.add("book-" + persisted.getBookId(), "rating-" + persisted.getId()); + return true; + } catch (JsonProcessingException ex) { + return false; + } } - - public boolean updateRating(Rating persisted){ - valueOps.set("rating-"+persisted.getId(), persisted.toString()); - return true; + + public boolean updateRating(Rating persisted) { + try { + valueOps.set("rating-" + persisted.getId(), jsonMapper.writeValueAsString(persisted)); + return true; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return false; } - - public boolean deleteRating(Long ratingId){ - Rating toDel=Rating.fromString(valueOps.get("rating-"+ratingId)); - setOps.remove("book-"+toDel.getBookId(), "rating-"+ratingId); - redisTemplate.delete("rating-"+ratingId); - return true; + + public boolean deleteRating(Long ratingId) { + Rating toDel; + try { + + toDel = jsonMapper.readValue(valueOps.get("rating-" + ratingId), Rating.class); + setOps.remove("book-" + toDel.getBookId(), "rating-" + ratingId); + redisTemplate.delete("rating-" + ratingId); + return true; + } catch (IOException e) { + e.printStackTrace(); + } + return false; } - + @Override public void afterPropertiesSet() throws Exception { - + this.redisTemplate = new StringRedisTemplate(cacheConnectionFactory); - + this.valueOps = redisTemplate.opsForValue(); - this.setOps=redisTemplate.opsForSet(); - + this.setOps = redisTemplate.opsForSet(); + + jsonMapper = new ObjectMapper(); + jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); } } 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 index 4f099da0df..395ff50bd7 100644 --- 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 @@ -1,6 +1,5 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; @@ -15,58 +14,48 @@ import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @Service @Transactional(readOnly = true) -public class RatingService{ +public class RatingService { @Autowired private RatingRepository ratingRepository; - + @Autowired private RatingCacheRepository cacheRepository; - - @HystrixCommand(commandKey="ratingsByBookIdFromDB",fallbackMethod="findCachedRatingsByBookId") + @HystrixCommand(commandKey = "ratingsByBookIdFromDB", fallbackMethod = "findCachedRatingsByBookId") public List findRatingsByBookId(Long bookId) { - if(bookId==2) - throw new IllegalArgumentException("BookID 2 redirects to cache"); - return ratingRepository.findRatingsByBookId(bookId); } - - @HystrixCommand(commandKey="ratingsByBookIdFromCache",fallbackMethod="defaultRatingsByBookId") - public List findCachedRatingsByBookId(Long bookId){ + + public List findCachedRatingsByBookId(Long bookId) { return cacheRepository.findCachedRatingsByBookId(bookId); } - - public List defaultRatingsByBookId(Long bookId){ - return Collections.emptyList(); - } - - @HystrixCommand(commandKey="ratingsFromDB",fallbackMethod="findAllCachedRatings") + @HystrixCommand(commandKey = "ratingsFromDB", fallbackMethod = "findAllCachedRatings") public List findAllRatings() { return ratingRepository.findAll(); } - - public List findAllCachedRatings(){ + + public List findAllCachedRatings() { return cacheRepository.findAllCachedRatings(); } - + @HystrixCommand(commandKey = "ratingsByIdFromDB", fallbackMethod = "findCachedRatingById", ignoreExceptions = { RatingNotFoundException.class }) public Rating findRatingById(Long ratingId) { return Optional.ofNullable(ratingRepository.findOne(ratingId)) .orElseThrow(() -> new RatingNotFoundException("Rating not found. ID: " + ratingId)); } - public Rating findCachedRatingById(Long ratingId){ + public Rating findCachedRatingById(Long ratingId) { return cacheRepository.findCachedRatingById(ratingId); } - + @Transactional(propagation = Propagation.REQUIRED) public Rating createRating(Rating rating) { Rating newRating = new Rating(); newRating.setBookId(rating.getBookId()); newRating.setStars(rating.getStars()); - Rating persisted=ratingRepository.save(newRating); + Rating persisted = ratingRepository.save(newRating); cacheRepository.createRating(persisted); return persisted; } @@ -88,7 +77,7 @@ public class RatingService{ break; } }); - Rating persisted= ratingRepository.save(rating); + Rating persisted = ratingRepository.save(rating); cacheRepository.updateRating(persisted); return persisted; } From fb4ba02ecf3fcbd860acad20c553e86fb1693a91 Mon Sep 17 00:00:00 2001 From: Ahamed Mustafa Date: Wed, 21 Jun 2017 20:04:31 +0100 Subject: [PATCH 3/4] BAEL-951 Self-Healing Services with Spring Cloud - C3 --- .../bootstrap/svcrating/CacheConfig.java | 24 ------------------- .../bootstrap/svcrating/CacheProperties.java | 21 ---------------- 2 files changed, 45 deletions(-) delete mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java delete mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java deleted file mode 100644 index d2332f86a8..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheConfig.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.svcrating; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.context.annotation.Bean; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; - -public class CacheConfig { - - @Autowired - CacheProperties cacheProperties; - - @Bean(name="cacheConnectionFactory") - @Qualifier("cacheJedisConnectionFactory") - JedisConnectionFactory cacheConnectionFactory() { - JedisConnectionFactory factory = new JedisConnectionFactory(); - factory.setHostName(cacheProperties.hostName); - factory.setPort(cacheProperties.port); - factory.setUsePool(true); - factory.afterPropertiesSet(); - return factory; - } - -} diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java deleted file mode 100644 index 980038fa36..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/CacheProperties.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.svcrating; - -public class CacheProperties { -public String hostName; -public int port; - -public String getHostName() { - return hostName; -} -public void setHostName(String hostName) { - this.hostName = hostName; -} -public int getPort() { - return port; -} -public void setPort(int port) { - this.port = port; -} - - -} From e495a51b6d4c3984c78cbb3642d8b91b34fa4f09 Mon Sep 17 00:00:00 2001 From: slavisa-baeldung Date: Wed, 5 Jul 2017 15:25:27 +0100 Subject: [PATCH 4/4] BAEL-951 adding @Repository stereotype --- .../rating/RatingCacheRepository.java | 121 ++++++++++++++++-- .../rating/RatingCacheRepositoryImpl.java | 120 ----------------- 2 files changed, 113 insertions(+), 128 deletions(-) delete mode 100644 spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java diff --git a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java index a807a61862..d9f3a3584e 100644 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java +++ b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepository.java @@ -1,13 +1,118 @@ package com.baeldung.spring.cloud.bootstrap.svcrating.rating; +import java.io.IOException; import java.util.List; +import java.util.stream.Collectors; -public interface RatingCacheRepository { +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.SetOperations; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; - List findCachedRatingsByBookId(Long bookId); - Rating findCachedRatingById(Long ratingId); - List findAllCachedRatings(); - boolean createRating(Rating persisted); - boolean updateRating(Rating persisted); - boolean deleteRating(Long ratingId); -} +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.stereotype.Repository; + +@Repository +public class RatingCacheRepository implements InitializingBean { + + @Autowired + private JedisConnectionFactory cacheConnectionFactory; + + private StringRedisTemplate redisTemplate; + private ValueOperations valueOps; + private SetOperations setOps; + + private ObjectMapper jsonMapper; + + public List findCachedRatingsByBookId(Long bookId) { + return setOps.members("book-" + bookId) + .stream() + .map(rtId -> { + try { + return jsonMapper.readValue(valueOps.get(rtId), Rating.class); + } catch (IOException ex) { + return null; + } + }) + .collect(Collectors.toList()); + } + + public Rating findCachedRatingById(Long ratingId) { + + try { + return jsonMapper.readValue(valueOps.get("rating-" + ratingId), Rating.class); + } catch (IOException e) { + return null; + } + + } + + public List findAllCachedRatings() { + List ratings = null; + + ratings = redisTemplate.keys("rating*") + .stream() + .map(rtId -> { + try { + + return jsonMapper.readValue(valueOps.get(rtId), Rating.class); + + } catch (IOException e) { + return null; + } + }) + .collect(Collectors.toList()); + + return ratings; + } + + public boolean createRating(Rating persisted) { + try { + valueOps.set("rating-" + persisted.getId(), jsonMapper.writeValueAsString(persisted)); + setOps.add("book-" + persisted.getBookId(), "rating-" + persisted.getId()); + return true; + } catch (JsonProcessingException ex) { + return false; + } + } + + public boolean updateRating(Rating persisted) { + try { + valueOps.set("rating-" + persisted.getId(), jsonMapper.writeValueAsString(persisted)); + return true; + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + return false; + } + + public boolean deleteRating(Long ratingId) { + Rating toDel; + try { + + toDel = jsonMapper.readValue(valueOps.get("rating-" + ratingId), Rating.class); + setOps.remove("book-" + toDel.getBookId(), "rating-" + ratingId); + redisTemplate.delete("rating-" + ratingId); + return true; + } catch (IOException e) { + e.printStackTrace(); + } + return false; + } + + @Override + public void afterPropertiesSet() throws Exception { + + this.redisTemplate = new StringRedisTemplate(cacheConnectionFactory); + + this.valueOps = redisTemplate.opsForValue(); + this.setOps = redisTemplate.opsForSet(); + + jsonMapper = new ObjectMapper(); + jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } +} \ 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/rating/RatingCacheRepositoryImpl.java b/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java deleted file mode 100644 index 35eddefade..0000000000 --- a/spring-cloud/spring-cloud-bootstrap/svc-rating/src/main/java/com/baeldung/spring/cloud/bootstrap/svcrating/rating/RatingCacheRepositoryImpl.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.baeldung.spring.cloud.bootstrap.svcrating.rating; - -import java.io.IOException; -import java.util.List; -import java.util.stream.Collectors; - -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; -import org.springframework.data.redis.core.SetOperations; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.core.ValueOperations; -import org.springframework.stereotype.Repository; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; - -@Repository -public class RatingCacheRepositoryImpl implements InitializingBean, RatingCacheRepository { - - @Autowired - private JedisConnectionFactory cacheConnectionFactory; - - private StringRedisTemplate redisTemplate; - private ValueOperations valueOps; - private SetOperations setOps; - - private ObjectMapper jsonMapper; - - public List findCachedRatingsByBookId(Long bookId) { - return setOps.members("book-" + bookId) - .stream() - .map(rtId -> { - try { - Rating rt = jsonMapper.readValue(valueOps.get(rtId), Rating.class); - rt.setFromCache(true); - return rt; - } catch (IOException ex) { - return null; - } - }) - .collect(Collectors.toList()); - } - - public Rating findCachedRatingById(Long ratingId) { - - try { - return jsonMapper.readValue(valueOps.get("rating-" + ratingId), Rating.class); - } catch (IOException e) { - return null; - } - - } - - public List findAllCachedRatings() { - List ratings = null; - - ratings = redisTemplate.keys("rating*") - .stream() - .map(rtId -> { - try { - - return jsonMapper.readValue(valueOps.get(rtId), Rating.class); - - } catch (IOException e) { - return null; - } - }) - .collect(Collectors.toList()); - - return ratings; - } - - public boolean createRating(Rating persisted) { - try { - valueOps.set("rating-" + persisted.getId(), jsonMapper.writeValueAsString(persisted)); - setOps.add("book-" + persisted.getBookId(), "rating-" + persisted.getId()); - return true; - } catch (JsonProcessingException ex) { - return false; - } - } - - public boolean updateRating(Rating persisted) { - try { - valueOps.set("rating-" + persisted.getId(), jsonMapper.writeValueAsString(persisted)); - return true; - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - return false; - } - - public boolean deleteRating(Long ratingId) { - Rating toDel; - try { - - toDel = jsonMapper.readValue(valueOps.get("rating-" + ratingId), Rating.class); - setOps.remove("book-" + toDel.getBookId(), "rating-" + ratingId); - redisTemplate.delete("rating-" + ratingId); - return true; - } catch (IOException e) { - e.printStackTrace(); - } - return false; - } - - @Override - public void afterPropertiesSet() throws Exception { - - this.redisTemplate = new StringRedisTemplate(cacheConnectionFactory); - - this.valueOps = redisTemplate.opsForValue(); - this.setOps = redisTemplate.opsForSet(); - - jsonMapper = new ObjectMapper(); - jsonMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - } -}