Skip to content

Commit

Permalink
#15 Cached by decorator in java
Browse files Browse the repository at this point in the history
  • Loading branch information
vlad-iv committed Apr 19, 2019
1 parent 96195d6 commit 0889ba9
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 10 deletions.
3 changes: 3 additions & 0 deletions rest/src/main/java/app/prime/controller/PrimeController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import app.prime.model.PrimeResult;
import app.prime.service.PrimeFactorService;
import app.prime.service.PrimeService;
import app.prime.service.WithCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -20,8 +21,10 @@
@RequestMapping("/prime")
public class PrimeController {
@Autowired
@WithCache
PrimeService primeService;
@Autowired
@WithCache
PrimeFactorService primeFactorService;

@RequestMapping(value = "/find/{number}", method = GET)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package app.prime.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Cache prime factors calculation results.
*
* @author Vladimir Ivanov ([email protected])
*/
@Service
@WithCache
public class CachedPrimeFactorService implements PrimeFactorService {
private final PrimeFactorService primeFactorService;
private final Map<Long, List<Long>> cache;

@Autowired
@WithOutCache
public CachedPrimeFactorService(PrimeFactorService primeFactorService) {
this(primeFactorService, new ConcurrentHashMap<>());
}

CachedPrimeFactorService(PrimeFactorService primeFactorService, Map<Long, List<Long>> cache) {
this.primeFactorService = primeFactorService;
this.cache = cache;
}

/**
* Expand a number into prime factors.
*/
public List<Long> findPrimeFactors(long number) {
if (cache.containsKey(number)) {
return cache.get(number);
}
List<Long> factors = primeFactorService.findPrimeFactors(number);
cache.put(number, factors);
return factors;
}
}
42 changes: 42 additions & 0 deletions service/src/main/java/app/prime/service/CachedPrimeService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package app.prime.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
* Cache prime calculation results.
*
* @author Vladimir Ivanov ([email protected])
*/
@Service
@WithCache
public class CachedPrimeService implements PrimeService {
private final PrimeService primeService;
private final Map<Long, Boolean> cache;

@Autowired
@WithOutCache
public CachedPrimeService(PrimeService primeService) {
this(primeService, new ConcurrentHashMap<>());
}

CachedPrimeService(PrimeService primeService, Map<Long, Boolean> cache) {
this.primeService = primeService;
this.cache = cache;
}

/**
* Check a number is prime.
*/
public boolean isPrime(final long number) {
if (cache.containsKey(number)) {
return cache.get(number);
}
boolean prime = primeService.isPrime(number);
cache.put(number, prime);
return prime;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package app.prime.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
Expand All @@ -13,34 +12,39 @@
* @author Vladimir Ivanov ([email protected])
*/
@Service
@WithOutCache
public class SimplePrimeFactorService implements PrimeFactorService {
final PrimeService primeService;

@Autowired
@WithCache
public SimplePrimeFactorService(PrimeService primeService) {
this.primeService = primeService;
}

/**
* List prime factors.
*/
@Cacheable
public List<Long> findPrimeFactors(final long number) {

final List<Long> primes = new ArrayList<>();

long divide = number;
for (long l = 2; l <= number; l++) {
for (long factor = 2; factor <= number; factor++) {
if (divide == 1) {
break;
}
if (!primeService.isPrime(l)) {
if (!primeService.isPrime(factor)) {
continue;
}
if (primeService.isPrime(divide)) {
primes.add(divide);
break;
}

while (divide % l == 0) {
divide /= l;
primes.add(l);
while (divide % factor == 0) {
divide /= factor;
primes.add(factor);
}
}
return primes;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package app.prime.service;

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
Expand All @@ -9,11 +8,11 @@
* @author Vladimir Ivanov ([email protected])
*/
@Service
@WithOutCache
public class SimplePrimeService implements PrimeService {
/**
* Check a number is prime.
*/
@Cacheable
public boolean isPrime(final long number) {
for (long l = 2; l < number; l++) {
if (number % l == 0) {
Expand Down
16 changes: 16 additions & 0 deletions service/src/main/java/app/prime/service/WithCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app.prime.service;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* Select cached version.
*
* @author Vladimir Ivanov ([email protected])
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface WithCache {
}
16 changes: 16 additions & 0 deletions service/src/main/java/app/prime/service/WithOutCache.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package app.prime.service;

import org.springframework.beans.factory.annotation.Qualifier;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
* Select cached version.
*
* @author Vladimir Ivanov ([email protected])
*/
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface WithOutCache {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package app.prime.service;

import org.junit.Before;
import org.junit.Test;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

/**
* Test cached prime favors service.
*
* @author Vladimir Ivanov ([email protected])
*/
public class CachedPrimeFactorServiceTest {
private CachedPrimeFactorService primeFactorService;
private ConcurrentHashMap<Long, List<Long>> cache;

@Before
public void setUp() {
cache = new ConcurrentHashMap<>();
primeFactorService = new CachedPrimeFactorService(
new SimplePrimeFactorService(
new SimplePrimeService()
),
cache
);
}

@Test
public void testFindPrimeFactors() {
checkPrimeFactors(-1, Collections.emptyList());
checkPrimeFactors(0, Collections.emptyList());
checkPrimeFactors(1, Collections.emptyList());
checkPrimeFactors(2, singletonList(2L));
checkPrimeFactors(3, singletonList(3L));
checkPrimeFactors(4, asList(2L, 2L));
checkPrimeFactors(5, singletonList(5L));
checkPrimeFactors(6, asList(2L, 3L));
checkPrimeFactors(7, singletonList(7L));
checkPrimeFactors(8, asList(2L, 2L, 2L));
checkPrimeFactors(9, asList(3L, 3L));
checkPrimeFactors(10, asList(2L, 5L));
checkPrimeFactors(10, asList(2L, 5L));
checkPrimeFactors(9999998, asList(2L, 4999999L));
}

private void checkPrimeFactors(long n, List<Long> factors) {
assertThat("Prime factor for " + n + " is " + factors, primeFactorService.findPrimeFactors(n), is(factors));
assertTrue("Cache contain number " + n, cache.containsKey(n));
assertThat("Valid prime factor cached result for " + n + " is " + factors, cache.get(n), is(factors));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package app.prime.service;

import org.junit.Before;
import org.junit.Test;

import java.util.concurrent.ConcurrentHashMap;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
* Test cached prime service.
*
* @author Vladimir Ivanov ([email protected])
*/
public class CachedPrimeServiceTest {
private CachedPrimeService primeService;
private ConcurrentHashMap<Long, Boolean> cache;

@Before
public void setUp() {
cache = new ConcurrentHashMap<>();
primeService = new CachedPrimeService(new SimplePrimeService(), cache);
}

@Test
public void testIsPrime() {

checkNotPrime(-1);
checkNotPrime(0);
checkNotPrime(4);
checkNotPrime(10);
checkNotPrime(10);

checkPrime(1);
checkPrime(2);
checkPrime(3);
checkPrime(5);
checkPrime(7);
checkPrime(7);
}

private void checkNotPrime(long n) {
assertFalse("Not prime number " + n, primeService.isPrime(n));
assertTrue("Cache contain number " + n, cache.containsKey(n));
assertFalse("Valid not prime cached result for " + n, cache.get(n));
}

private void checkPrime(long n) {
assertTrue("Prime number " + n, primeService.isPrime(n));
assertTrue("Cache contain number " + n, cache.containsKey(n));
assertTrue("Valid prime cached result for " + n, cache.get(n));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,5 @@ public void testFindPrimeFactors() {
assertThat(primeFactorService.findPrimeFactors(8), is(asList(2L, 2L, 2L)));
assertThat(primeFactorService.findPrimeFactors(9), is(asList(3L, 3L)));
assertThat(primeFactorService.findPrimeFactors(10), is(asList(2L, 5L)));

}
}

0 comments on commit 0889ba9

Please sign in to comment.