diff --git a/src/main/java/part2/cache/CachingDataStorageImpl.java b/src/main/java/part2/cache/CachingDataStorageImpl.java index a2ae460..ede9905 100755 --- a/src/main/java/part2/cache/CachingDataStorageImpl.java +++ b/src/main/java/part2/cache/CachingDataStorageImpl.java @@ -1,5 +1,6 @@ package part2.cache; +import com.sun.javafx.geom.AreaOp; import db.DataStorage; import db.SlowCompletableFutureDb; @@ -38,6 +39,30 @@ public OutdatableResult getOutdatable(String key) { // TODO don't use obtrudeException on result - just don't // TODO use remove(Object key, Object value) to remove target value // TODO Start timeout after receiving result in CompletableFuture, not after receiving CompletableFuture itself - throw new UnsupportedOperationException(); + + OutdatableResult res = new OutdatableResult<>(new CompletableFuture<>(), new CompletableFuture<>()); + OutdatableResult tOutdatableResult = cache.putIfAbsent(key, res); + + if (tOutdatableResult == null) { + db.get(key).whenComplete( + (t, e) -> { + scheduledExecutorService.schedule(() -> { + cache.remove(key, cache.get(key)); + res.getOutdated().complete(null); + }, + timeout, + timeoutUnits + ); + if (e != null) { + res.getResult().completeExceptionally(e); + } else { + res.getResult().complete(t); + } + } + ); + return res; + } else { + return tOutdatableResult; + } } } diff --git a/src/main/java/part3/exercise/ComposeCachingDataStorage.java b/src/main/java/part3/exercise/ComposeCachingDataStorage.java index 64d1b3d..4d71987 100755 --- a/src/main/java/part3/exercise/ComposeCachingDataStorage.java +++ b/src/main/java/part3/exercise/ComposeCachingDataStorage.java @@ -2,20 +2,55 @@ import part2.cache.CachingDataStorage; +import java.util.concurrent.CompletableFuture; import java.util.function.Function; public class ComposeCachingDataStorage implements CachingDataStorage { - public ComposeCachingDataStorage(CachingDataStorage storage1, - CachingDataStorage storage2, - Function mapping) { - // TODO - throw new UnsupportedOperationException(); + private CachingDataStorage storage1; + private CachingDataStorage storage2; + private Function mapping; + + public ComposeCachingDataStorage(CachingDataStorage storage1, CachingDataStorage storage2, Function mapping) { + this.storage1 = storage1; + this.storage2 = storage2; + this.mapping = mapping; } @Override public OutdatableResult getOutdatable(K1 key) { - // TODO - throw new UnsupportedOperationException(); + + OutdatableResult outdatableFromStorage1 = storage1.getOutdatable(key); + + CompletableFuture> outdatableResultCompletableFuture = outdatableFromStorage1.getResult().thenApply( + v -> storage2.getOutdatable(mapping.apply(v)) + ); + + OutdatableResult result = new OutdatableResult<>(new CompletableFuture<>(), new CompletableFuture<>()); + + thenComplete(outdatableFromStorage1.getOutdated(), result.getOutdated()); + outdatableResultCompletableFuture.thenAccept( + v -> v.getResult().thenAccept( + res -> { + result.getResult().complete(res); + thenComplete(v.getOutdated(),result.getOutdated()); + } + ) + ); + + return result; + } + + private void thenComplete(CompletableFuture source, CompletableFuture target) { + source.whenComplete( + (r,e) -> { + if (e == null) { + target.complete(null); + } else { + target.completeExceptionally(e); + } + } + ); } + } diff --git a/src/main/java/part3/exercise/ListCachingDataStorage.java b/src/main/java/part3/exercise/ListCachingDataStorage.java index bb47836..ea99fb6 100755 --- a/src/main/java/part3/exercise/ListCachingDataStorage.java +++ b/src/main/java/part3/exercise/ListCachingDataStorage.java @@ -3,17 +3,50 @@ import part2.cache.CachingDataStorage; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.stream.Collectors; public class ListCachingDataStorage implements CachingDataStorage, List> { + private CachingDataStorage storage; + public ListCachingDataStorage(CachingDataStorage storage) { - // TODO - throw new UnsupportedOperationException(); + this.storage = storage; } @Override public OutdatableResult> getOutdatable(List key) { - // TODO - throw new UnsupportedOperationException(); + List> collect = key.stream() + .map(storage::getOutdatable) + .collect(Collectors.toList()); + + List> outdatables = collect.stream() + .map(OutdatableResult::getOutdated) + .collect(Collectors.toList()); + + List> results = collect.stream() + .map(OutdatableResult::getResult) + .collect(Collectors.toList()); + + CompletableFuture> listCompletableFuture = CompletableFuture.allOf(results.toArray(new CompletableFuture[0])) + .thenApply(v -> results.stream() + .map(ListCachingDataStorage::getOrNull) + .collect(Collectors.toList())); + + return new OutdatableResult<>( + listCompletableFuture, + CompletableFuture.anyOf(outdatables.toArray(new CompletableFuture[0])).thenApply(v -> null) + ); + } + + private static T getOrNull(Future f) { + try { + return f.get(); + } catch (InterruptedException | ExecutionException e1) { + e1.printStackTrace(); + return null; + } } } diff --git a/src/main/java/part3/exercise/MappingCachingDataStorage.java b/src/main/java/part3/exercise/MappingCachingDataStorage.java index 39ef5ea..64db106 100755 --- a/src/main/java/part3/exercise/MappingCachingDataStorage.java +++ b/src/main/java/part3/exercise/MappingCachingDataStorage.java @@ -7,16 +7,23 @@ public class MappingCachingDataStorage implements CachingDataStorage { - public MappingCachingDataStorage(CachingDataStorage storage, - Function mapKey, - BiFunction mapValue) { - // TODO - throw new UnsupportedOperationException(); + private CachingDataStorage storage; + private Function mapKey; + private BiFunction mapValue; + + public MappingCachingDataStorage(CachingDataStorage storage, Function mapKey, BiFunction mapValue) { + this.storage = storage; + this.mapKey = mapKey; + this.mapValue = mapValue; } @Override public OutdatableResult getOutdatable(K key) { - // TODO - throw new UnsupportedOperationException(); + OutdatableResult outdatable = storage.getOutdatable(mapKey.apply(key)); + + return new OutdatableResult<>( + outdatable.getResult().thenApply(t1 -> mapValue.apply(key, t1)), + outdatable.getOutdated() + ); } } diff --git a/src/main/java/part3/exercise/PairCachingDataStorage.java b/src/main/java/part3/exercise/PairCachingDataStorage.java index fa3a735..4f0a8d7 100755 --- a/src/main/java/part3/exercise/PairCachingDataStorage.java +++ b/src/main/java/part3/exercise/PairCachingDataStorage.java @@ -2,23 +2,41 @@ import part2.cache.CachingDataStorage; +import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import java.util.function.Function; public class PairCachingDataStorage implements CachingDataStorage { - public PairCachingDataStorage(CachingDataStorage storage1, - CachingDataStorage storage2, - Function getKey1, - Function getKey2, - Function> resultMapper) { - // TODO - throw new UnsupportedOperationException(); + private CachingDataStorage storage1; + private CachingDataStorage storage2; + private Function getKey1; + private Function getKey2; + private Function> resultMapper; + + + public PairCachingDataStorage( + CachingDataStorage storage1, + CachingDataStorage storage2, + Function getKey1, + Function getKey2, + Function> resultMapper + ) { + this.storage1 = storage1; + this.storage2 = storage2; + this.getKey1 = getKey1; + this.getKey2 = getKey2; + this.resultMapper = resultMapper; } @Override public OutdatableResult getOutdatable(K key) { - // TODO - throw new UnsupportedOperationException(); + OutdatableResult outdatable1 = storage1.getOutdatable(getKey1.apply(key)); + OutdatableResult outdatable2 = storage2.getOutdatable(getKey2.apply(key)); + + return new OutdatableResult<>( + outdatable1.getResult().thenCombine(outdatable2.getResult(), resultMapper.apply(key)), + CompletableFuture.anyOf(outdatable1.getOutdated(),outdatable2.getOutdated()).thenApply(v -> null) + ); } }