diff --git a/build.gradle b/build.gradle index 5e1a2141..883d56db 100644 --- a/build.gradle +++ b/build.gradle @@ -57,8 +57,8 @@ dependencies { // dependencies. It will automatically choose the fitting ones. implementation("edu.kit.datamanager:service-base:1.2.0") implementation("edu.kit.datamanager:repo-core:1.2.1") - // com.google.common, LoadingCache - implementation("com.google.guava:guava:33.2.1-jre") + // AsyncLoadingCache https://github.com/ben-manes/caffeine + implementation("com.github.ben-manes.caffeine:caffeine:3.1.8") // Required by Spring/Javers at runtime implementation 'com.google.code.gson:gson:2.10.1' diff --git a/src/main/java/edu/kit/datamanager/pit/Application.java b/src/main/java/edu/kit/datamanager/pit/Application.java index 5857e71a..932c16a0 100644 --- a/src/main/java/edu/kit/datamanager/pit/Application.java +++ b/src/main/java/edu/kit/datamanager/pit/Application.java @@ -19,11 +19,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import com.google.common.cache.RemovalNotification; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; import edu.kit.datamanager.pit.cli.CliTaskBootstrap; import edu.kit.datamanager.pit.cli.CliTaskWriteFile; import edu.kit.datamanager.pit.cli.ICliTask; @@ -150,21 +148,18 @@ public CacheConfig cacheConfig() { * @return the cache */ @Bean - public LoadingCache typeLoader(ApplicationProperties props) { - int maximumsize = props.getMaximumSize(); - long expireafterwrite = props.getExpireAfterWrite(); - return CacheBuilder.newBuilder() - .maximumSize(maximumsize) - .expireAfterWrite(expireafterwrite, TimeUnit.MINUTES) - .removalListener((RemovalNotification rn) -> LOG.trace( - "Removing type definition located at {} from schema cache. Cause: {}", rn.getKey(), - rn.getCause())) - .build(new CacheLoader() { - @Override - public TypeDefinition load(String typeIdentifier) throws IOException, URISyntaxException { - LOG.trace("Loading type definition for identifier {} to cache.", typeIdentifier); - return typeRegistry().queryTypeDefinition(typeIdentifier); - } + public AsyncLoadingCache typeLoader(ApplicationProperties props) { + int maximumSize = props.getMaximumSize(); + long expireAfterWrite = props.getExpireAfterWrite(); + return Caffeine.newBuilder() + .maximumSize(maximumSize) + .expireAfterWrite(expireAfterWrite, TimeUnit.MINUTES) + .removalListener((key, value, cause) -> + LOG.trace("Removing type definition located at {} from schema cache. Cause: {}", key, cause) + ) + .buildAsync(pid -> { + LOG.trace("Loading type definition for identifier {} to cache.", pid); + return typeRegistry().queryTypeDefinition(pid); }); } diff --git a/src/main/java/edu/kit/datamanager/pit/domain/Operations.java b/src/main/java/edu/kit/datamanager/pit/domain/Operations.java index dc040ca7..94f5f128 100644 --- a/src/main/java/edu/kit/datamanager/pit/domain/Operations.java +++ b/src/main/java/edu/kit/datamanager/pit/domain/Operations.java @@ -8,7 +8,10 @@ import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +import org.apache.commons.lang3.stream.Streams; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; @@ -69,14 +72,17 @@ public Optional findDateCreated(PIDRecord pidRecord) throws IOException { /* TODO try to find types extending or relating otherwise to known types * (currently not supported by our TypeDefinition) */ - // we need to resolve types without streams to forward possible exceptions Collection types = new ArrayList<>(); - for (String attributePid : pidRecord.getPropertyIdentifiers()) { - if (this.typingService.isIdentifierRegistered(attributePid)) { - TypeDefinition type = this.typingService.describeType(attributePid); - types.add(type); - } - } + List> futures = Streams + .stream(pidRecord.getPropertyIdentifiers().stream()) + .filter(attributePid -> this.typingService.isIdentifierRegistered(attributePid)) + .map(attributePid -> { + return this.typingService + .describeType(attributePid) + .thenAcceptAsync(types::add); + }) + .collect(Collectors.toList()); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); /* * as a last fallback, try find types with human readable names containing @@ -134,14 +140,17 @@ public Optional findDateModified(PIDRecord pidRecord) throws IOException { /* TODO try to find types extending or relating otherwise to known types * (currently not supported by our TypeDefinition) */ - // we need to resolve types without streams to forward possible exceptions Collection types = new ArrayList<>(); - for (String attributePid : pidRecord.getPropertyIdentifiers()) { - if (this.typingService.isIdentifierRegistered(attributePid)) { - TypeDefinition type = this.typingService.describeType(attributePid); - types.add(type); - } - } + List> futures = Streams + .stream(pidRecord.getPropertyIdentifiers().stream()) + .filter(attributePid -> this.typingService.isIdentifierRegistered(attributePid)) + .map(attributePid -> { + return this.typingService + .describeType(attributePid) + .thenAcceptAsync(types::add); + }) + .collect(Collectors.toList()); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); /* * as a last fallback, try find types with human readable names containing diff --git a/src/main/java/edu/kit/datamanager/pit/pitservice/ITypingService.java b/src/main/java/edu/kit/datamanager/pit/pitservice/ITypingService.java index 86fc1923..aafceb7c 100644 --- a/src/main/java/edu/kit/datamanager/pit/pitservice/ITypingService.java +++ b/src/main/java/edu/kit/datamanager/pit/pitservice/ITypingService.java @@ -6,6 +6,7 @@ import edu.kit.datamanager.pit.domain.PIDRecord; import edu.kit.datamanager.pit.domain.TypeDefinition; import java.io.IOException; +import java.util.concurrent.CompletableFuture; import edu.kit.datamanager.pit.pidsystem.IIdentifierSystem; @@ -29,7 +30,7 @@ public void validate(PIDRecord pidRecord) * record otherwise. * @throws IOException */ - public TypeDefinition describeType(String typeIdentifier) throws IOException; + public CompletableFuture describeType(String typeIdentifier) throws IOException; /** * Queries a single property from the PID. diff --git a/src/main/java/edu/kit/datamanager/pit/pitservice/impl/EmbeddedStrictValidatorStrategy.java b/src/main/java/edu/kit/datamanager/pit/pitservice/impl/EmbeddedStrictValidatorStrategy.java index 43141fe1..8480d8e2 100644 --- a/src/main/java/edu/kit/datamanager/pit/pitservice/impl/EmbeddedStrictValidatorStrategy.java +++ b/src/main/java/edu/kit/datamanager/pit/pitservice/impl/EmbeddedStrictValidatorStrategy.java @@ -1,5 +1,6 @@ package edu.kit.datamanager.pit.pitservice.impl; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; import edu.kit.datamanager.pit.common.ExternalServiceException; import edu.kit.datamanager.pit.common.RecordValidationException; import edu.kit.datamanager.pit.configuration.ApplicationProperties; @@ -8,14 +9,19 @@ import edu.kit.datamanager.pit.pitservice.IValidationStrategy; import edu.kit.datamanager.pit.util.TypeValidationUtils; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; +import org.apache.commons.lang3.stream.Streams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import com.google.common.cache.LoadingCache; - /** * Validates a PID record using embedded profile(s). * @@ -27,8 +33,10 @@ public class EmbeddedStrictValidatorStrategy implements IValidationStrategy { private static final Logger LOG = LoggerFactory.getLogger(EmbeddedStrictValidatorStrategy.class); + private static final Executor EXECUTOR = Executors.newWorkStealingPool(); + @Autowired - public LoadingCache typeLoader; + public AsyncLoadingCache typeLoader; @Autowired ApplicationProperties applicationProps; @@ -50,26 +58,28 @@ public void validate(PIDRecord pidRecord) throws RecordValidationException, Exte "Profile attribute " + profileKey + " has no values."); } - for (String profilePID : profilePIDs) { - TypeDefinition profileDefinition; - try { - profileDefinition = this.typeLoader.get(profilePID); - } catch (ExecutionException e) { - LOG.error("Could not resolve identifier {}.", profilePID); - throw new ExternalServiceException( - applicationProps.getTypeRegistryUri().toString()); - } - if (profileDefinition == null) { - LOG.error("No type definition found for identifier {}.", profilePID); - throw new RecordValidationException( - pidRecord, - String.format("No type found for identifier %s.", profilePID)); - } - - LOG.debug("validating profile {}", profilePID); - this.strictProfileValidation(pidRecord, profileDefinition); - LOG.debug("successfully validated {}", profilePID); - } + List> futures = Streams.stream(Arrays.stream(profilePIDs)) + .map(profilePID -> { + try { + return this.typeLoader.get(profilePID) + .thenAcceptAsync(profileDefinition -> { + if (profileDefinition == null) { + LOG.error("No type definition found for identifier {}.", profilePID); + throw new RecordValidationException( + pidRecord, + String.format("No type found for identifier %s.", profilePID)); + } + this.strictProfileValidation(pidRecord, profileDefinition); + }, EXECUTOR); + } catch (RuntimeException e) { + LOG.error("Could not resolve identifier {}.", profilePID); + throw new ExternalServiceException( + applicationProps.getTypeRegistryUri().toString()); + } + }) + .collect(Collectors.toList()); + CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); + // TODO catch and unpack exceptions } /** @@ -87,7 +97,7 @@ private void strictProfileValidation(PIDRecord pidRecord, TypeDefinition profile // return profile.validate(jsonRecord); // } - LOG.trace("Validating PID record against type definition."); + LOG.trace("Validating PID record against profile {}.", profile.getIdentifier()); TypeValidationUtils.checkMandatoryAttributes(pidRecord, profile); @@ -109,6 +119,7 @@ private void strictProfileValidation(PIDRecord pidRecord, TypeDefinition profile validateValuesForKey(pidRecord, attributeKey, type); } + LOG.debug("successfully validated {}", profile.getIdentifier()); } /** diff --git a/src/main/java/edu/kit/datamanager/pit/pitservice/impl/TypingService.java b/src/main/java/edu/kit/datamanager/pit/pitservice/impl/TypingService.java index 0e556933..4a77b054 100644 --- a/src/main/java/edu/kit/datamanager/pit/pitservice/impl/TypingService.java +++ b/src/main/java/edu/kit/datamanager/pit/pitservice/impl/TypingService.java @@ -1,16 +1,13 @@ package edu.kit.datamanager.pit.pitservice.impl; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; import edu.kit.datamanager.pit.common.InvalidConfigException; import edu.kit.datamanager.pit.common.PidAlreadyExistsException; import edu.kit.datamanager.pit.common.PidNotFoundException; import edu.kit.datamanager.pit.common.RecordValidationException; -import edu.kit.datamanager.pit.common.TypeNotFoundException; import java.io.IOException; import java.util.Collection; -import java.util.HashSet; -import java.util.List; import java.util.Optional; import edu.kit.datamanager.pit.pidsystem.IIdentifierSystem; @@ -21,6 +18,8 @@ import edu.kit.datamanager.pit.domain.Operations; import edu.kit.datamanager.pit.domain.PIDRecord; import edu.kit.datamanager.pit.domain.TypeDefinition; + +import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; @@ -39,7 +38,7 @@ public class TypingService implements ITypingService { private static final String LOG_MSG_QUERY_TYPE = "Querying for type with identifier {}."; - protected final LoadingCache typeCache; + protected final AsyncLoadingCache typeCache; protected final IIdentifierSystem identifierSystem; protected final ITypeRegistry typeRegistry; @@ -54,7 +53,7 @@ public class TypingService implements ITypingService { protected IValidationStrategy defaultStrategy = null; public TypingService(IIdentifierSystem identifierSystem, ITypeRegistry typeRegistry, - LoadingCache typeCache) { + AsyncLoadingCache typeCache) { super(); this.identifierSystem = identifierSystem; this.typeRegistry = typeRegistry; @@ -108,12 +107,12 @@ public boolean deletePID(String pid) throws ExternalServiceException { } @Override - public TypeDefinition describeType(String typeIdentifier) throws IOException { + public CompletableFuture describeType(String typeIdentifier) throws IOException { LOG.trace("Performing describeType({}).", typeIdentifier); try { LOG.trace(LOG_MSG_QUERY_TYPE, typeIdentifier); return typeCache.get(typeIdentifier); - } catch (ExecutionException ex) { + } catch (RuntimeException ex) { LOG.error("Failed to query for type with identifier " + typeIdentifier + ".", ex); throw new InvalidConfigException(LOG_MSG_TYPING_SERVICE_MISCONFIGURED); } @@ -152,10 +151,9 @@ public PIDRecord queryProperty(String pid, String propertyIdentifier) throws IOE TypeDefinition typeDef; try { LOG.trace(LOG_MSG_QUERY_TYPE, propertyIdentifier); - typeDef = typeCache.get(propertyIdentifier); - } catch (ExecutionException ex) { + typeDef = typeCache.get(propertyIdentifier).get(); + } catch (ExecutionException | InterruptedException ex) { LOG.error(LOG_MSG_QUERY_TYPE, propertyIdentifier); - throw new InvalidConfigException(LOG_MSG_TYPING_SERVICE_MISCONFIGURED); } @@ -172,8 +170,8 @@ private void enrichPIDInformationRecord(PIDRecord pidInfo) { for (String typeIdentifier : pidInfo.getPropertyIdentifiers()) { TypeDefinition typeDef; try { - typeDef = typeCache.get(typeIdentifier); - } catch (ExecutionException ex) { + typeDef = typeCache.get(typeIdentifier).get(); + } catch (ExecutionException | InterruptedException ex) { throw new InvalidConfigException(LOG_MSG_TYPING_SERVICE_MISCONFIGURED); } @@ -190,8 +188,8 @@ public PIDRecord queryByType(String pid, String typeIdentifier, boolean includeP throws IOException { TypeDefinition typeDef; try { - typeDef = typeCache.get(typeIdentifier); - } catch (ExecutionException ex) { + typeDef = typeCache.get(typeIdentifier).get(); + } catch (ExecutionException | InterruptedException ex) { throw new InvalidConfigException(LOG_MSG_TYPING_SERVICE_MISCONFIGURED); } diff --git a/src/main/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistry.java b/src/main/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistry.java index 0d016d27..f429595a 100644 --- a/src/main/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistry.java +++ b/src/main/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistry.java @@ -1,13 +1,14 @@ package edu.kit.datamanager.pit.typeregistry.impl; import java.io.IOException; -import java.util.HashMap; +import java.util.Date; +import java.util.List; import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.cache.LoadingCache; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; import edu.kit.datamanager.pit.configuration.ApplicationProperties; import edu.kit.datamanager.pit.domain.ProvenanceInformation; import edu.kit.datamanager.pit.domain.TypeDefinition; @@ -15,8 +16,11 @@ import java.net.URISyntaxException; import java.time.Instant; import java.time.format.DateTimeParseException; -import java.util.Date; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.*; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import org.apache.commons.lang3.stream.Streams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -36,8 +40,11 @@ public class TypeRegistry implements ITypeRegistry { private static final Logger LOG = LoggerFactory.getLogger(TypeRegistry.class); + private static final Executor EXECUTOR = Executors.newWorkStealingPool(10); + + @Autowired - public LoadingCache typeCache; + public AsyncLoadingCache typeCache; @Autowired private ApplicationProperties applicationProperties; @@ -66,111 +73,61 @@ public TypeDefinition queryTypeDefinition(String typeIdentifier) throws IOExcept * Helper method to construct a type definition from a JSON response * received from the TypeRegistry. * - * @param rootNode The type definition. - * + * @param registryRepresentation The type definition. * @return The TypeDefinition as object. */ - private TypeDefinition constructTypeDefinition(JsonNode rootNode) + private TypeDefinition constructTypeDefinition(JsonNode registryRepresentation) throws JsonProcessingException, IOException, URISyntaxException { // TODO We are doing things too complicated here. Deserialization should be // easy. // But before we change the domain model to do so, we need a lot of tests to // make sure things work as before after the changes. LOG.trace("Performing constructTypeDefinition()."); - JsonNode entry = rootNode; - Map properties = new HashMap<>(); - LOG.trace("Checking for 'properties' attribute."); - if (entry.has("properties")) { - LOG.trace("'properties' attribute found. Transferring properties to type definition."); - for (JsonNode entryKV : entry.get("properties")) { - LOG.trace("Checking for 'name' property."); - if (!entryKV.has("name")) { - LOG.trace("No 'name' property found. Skipping property {}.", entryKV); - continue; - } - - String key = entryKV.get("name").asText(); - - if (!entryKV.has("identifier")) { - LOG.trace("No 'identifier' property found. Skipping property {}.", entryKV); - continue; - } - - String value = entryKV.get("identifier").asText(); - LOG.trace("Creating type definition instance for identifier {}.", value); - TypeDefinition type_def; - - try { - type_def = typeCache.get(value); - } catch (ExecutionException ex) { - throw new IOException("Failed to obtain type definition via cache.", ex); - } - - LOG.trace("Checking for sub-types in 'representationsAndSemantics' property."); - if (entryKV.has("representationsAndSemantics")) { - LOG.trace( - "'representationsAndSemantics' attribute found. Transferring properties to type definition."); - JsonNode semNode = entryKV.get("representationsAndSemantics"); - semNode = semNode.get(0); - LOG.trace("Checking for 'expression' property."); - if (semNode.has("expression")) { - LOG.trace("Setting 'expression' value {}.", semNode.get("expression").asText()); - type_def.setExpression(semNode.get("expression").asText()); - } - - LOG.trace("Checking for 'value' property."); - if (semNode.has("value")) { - LOG.trace("Setting 'value' value {}.", semNode.get("value").asText()); - type_def.setValue(semNode.get("value").asText()); - } - - LOG.trace("Checking for 'obligation' property."); - if (semNode.has("obligation")) { - LOG.trace("Setting 'obligation' value {}.", semNode.get("obligation").asText()); - String obligation = semNode.get("obligation").asText(); - type_def.setOptional("Optional".equalsIgnoreCase(obligation)); - } - - LOG.trace("Checking for 'repeatable' property."); - if (semNode.has("repeatable")) { - LOG.trace("Setting 'repeatable' value {}.", semNode.get("repeatable").asText()); - String repeatable = semNode.get("repeatable").asText(); - type_def.setRepeatable(!"No".equalsIgnoreCase(repeatable)); - } - } - LOG.trace("Adding new sub-type with key {}.", key); - properties.put(key, type_def); - } - } - String typeUseExpl = null; - if (entry.has("description")) { - typeUseExpl = entry.get("description").asText(); - } - String name = null; - if (entry.has("name")) { - name = entry.get("name").asText(); - } - - if (!entry.has("identifier")) { - LOG.error("No 'identifier' property found in entry: {}", entry); + final String identifier = registryRepresentation.path("identifier").asText(null); + if (identifier == null) { + LOG.error("No 'identifier' property found in entry: {}", registryRepresentation); throw new IOException("No 'identifier' attribute found in type definition."); } - String identifier = entry.get("identifier").asText(); + + LOG.trace("Checking for 'properties' attribute."); + Map properties = new ConcurrentHashMap<>(); + List> propertiesHandling = Streams.stream(StreamSupport.stream( + registryRepresentation.path("properties").spliterator(), false)) + .filter(property -> property.hasNonNull("name")) + .filter(property -> property.hasNonNull("identifier")) + .map(property -> { + final String name = property.path("name").asText(); + final String pid = property.path("identifier").asText(); + return typeCache.get(pid).thenAcceptAsync( + typeDefinition -> { + final JsonNode semantics = property.path("representationsAndSemantics").path(0); + final String expression = semantics.path("expression").asText(null); + typeDefinition.setExpression(expression); + final String value = semantics.path("value").asText(null); + typeDefinition.setValue(value); + final String obligation = semantics.path("obligation").asText("Mandatory"); + typeDefinition.setOptional("Optional".equalsIgnoreCase(obligation)); + final String repeatable = semantics.path("repeatable").asText("No"); + typeDefinition.setRepeatable(!"No".equalsIgnoreCase(repeatable)); + properties.put(name, typeDefinition); + }, + EXECUTOR); + // TODO catch and unpack exceptions + }) + .collect(Collectors.toList()); TypeDefinition result = new TypeDefinition(); - result.setName(name); - result.setDescription(typeUseExpl); result.setIdentifier(identifier); - LOG.trace("Checking for 'validationSchema' property."); - if (entry.has("validationSchema")) { - String validationSchema = entry.get("validationSchema").asText(); - result.setSchema(validationSchema); - } + final String description = registryRepresentation.path("description").asText(null); + result.setDescription(description); + final String name = registryRepresentation.path("name").asText(null); + result.setName(name); + final String validationSchema = registryRepresentation.path("validationSchema").asText(null); + result.setSchema(validationSchema); - LOG.trace("Checking for 'provenance' property."); - if (entry.has("provenance")) { + if (registryRepresentation.has("provenance")) { ProvenanceInformation prov = new ProvenanceInformation(); - JsonNode provNode = entry.get("provenance"); + JsonNode provNode = registryRepresentation.get("provenance"); if (provNode.has("creationDate")) { String creationDate = provNode.get("creationDate").asText(); try { @@ -192,13 +149,13 @@ private TypeDefinition constructTypeDefinition(JsonNode rootNode) String contributorName = null; String details = null; - if (entry.has("identifiedBy")) { + if (registryRepresentation.has("identifiedBy")) { identified = entryKV.get("identifiedBy").asText(); } - if (entry.has("name")) { + if (registryRepresentation.has("name")) { contributorName = entryKV.get("name").asText(); } - if (entry.has("details")) { + if (registryRepresentation.has("details")) { details = entryKV.get("details").asText(); } prov.addContributor(identified, contributorName, details); @@ -207,8 +164,13 @@ private TypeDefinition constructTypeDefinition(JsonNode rootNode) } LOG.trace("Finalizing and returning type definition."); + CompletableFuture.allOf(propertiesHandling.toArray(new CompletableFuture[0])).join(); + // TODO catch exceptions and unpack them + // catch (ExecutionException | InterruptedException ex) { + // throw new IOException("Failed to obtain type definition via cache.", ex); + // } properties.keySet().forEach(pd -> result.addSubType(properties.get(pd))); - this.typeCache.put(identifier, result); + this.typeCache.put(identifier, CompletableFuture.completedFuture(result)); return result; } } diff --git a/src/test/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistryTest.java b/src/test/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistryTest.java index cc056d0e..2bb7db38 100644 --- a/src/test/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistryTest.java +++ b/src/test/java/edu/kit/datamanager/pit/typeregistry/impl/TypeRegistryTest.java @@ -36,7 +36,7 @@ void isCachingProfiles() throws IOException, URISyntaxException { assertEquals( null, typeRegistry.typeCache.getIfPresent(profileIdentifier)); - assertEquals(0, typeRegistry.typeCache.size()); + assertEquals(0, typeRegistry.typeCache.synchronous().estimatedSize()); typeRegistry.queryTypeDefinition(profileIdentifier); assertNotEquals( @@ -44,6 +44,6 @@ void isCachingProfiles() throws IOException, URISyntaxException { typeRegistry.typeCache.getIfPresent(profileIdentifier)); // A profile definition contains type definitions. // The cache therefore should have more than one identifiers in cache. - assertTrue(typeRegistry.typeCache.size() > 1); + assertTrue(typeRegistry.typeCache.synchronous().estimatedSize() > 1); } }