diff --git a/src/main/java/no/ndla/taxonomy/config/SchedulingConfig.java b/src/main/java/no/ndla/taxonomy/config/SchedulingConfig.java deleted file mode 100644 index 962c0558..00000000 --- a/src/main/java/no/ndla/taxonomy/config/SchedulingConfig.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Part of NDLA taxonomy-api - * Copyright (C) 2021 NDLA - * - * See LICENSE - */ - -package no.ndla.taxonomy.config; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.task.ThreadPoolTaskSchedulerCustomizer; -import org.springframework.context.annotation.Configuration; -import org.springframework.dao.DataAccessException; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; -import org.springframework.util.ErrorHandler; - -@Configuration -@EnableScheduling -public class SchedulingConfig implements ThreadPoolTaskSchedulerCustomizer { - @Override - public void customize(ThreadPoolTaskScheduler taskScheduler) { - taskScheduler.setErrorHandler(new CustomErrorHandler()); - } - - /* - * Don't care about database errors in scheduled tasks - */ - private static class CustomErrorHandler implements ErrorHandler { - Logger logger = LoggerFactory.getLogger(getClass().getName()); - - @Override - public void handleError(Throwable t) { - if (t instanceof DataAccessException) { - logger.info("Scheduled task threw an exception, ignoring: {}", t.getMessage()); - } else { - logger.error("Scheduled task threw an exception: {}", t.getMessage(), t); - } - } - } -} diff --git a/src/main/java/no/ndla/taxonomy/domain/NodeConnection.java b/src/main/java/no/ndla/taxonomy/domain/NodeConnection.java index a70ae2c0..61de5b35 100644 --- a/src/main/java/no/ndla/taxonomy/domain/NodeConnection.java +++ b/src/main/java/no/ndla/taxonomy/domain/NodeConnection.java @@ -165,8 +165,8 @@ public Optional isPrimary() { public void setPrimary(boolean isPrimary) { var childType = this.child.getNodeType(); if (childType == NodeType.TOPIC && !isPrimary) { - throw new UnsupportedOperationException( - "NodeConnection with child of type '" + childType.toString() + "' can not be non-primary"); + throw new IllegalArgumentException( + "NodeConnection with child of type '" + childType + "' cannot be non-primary"); } this.isPrimary = isPrimary; diff --git a/src/main/java/no/ndla/taxonomy/rest/ControllerExceptionHandler.java b/src/main/java/no/ndla/taxonomy/rest/ControllerExceptionHandler.java index 22e1e4fb..c321a7c3 100644 --- a/src/main/java/no/ndla/taxonomy/rest/ControllerExceptionHandler.java +++ b/src/main/java/no/ndla/taxonomy/rest/ControllerExceptionHandler.java @@ -66,6 +66,11 @@ protected ResponseEntity handleConflictExceptions(RuntimeException excep return new ResponseEntity<>(createErrorBody(exception), createHeaders(), HttpStatus.CONFLICT); } + @ExceptionHandler({UnsupportedOperationException.class}) + protected ResponseEntity handleUnsupportedExceptions(RuntimeException exception) { + return new ResponseEntity<>(createErrorBody(exception), createHeaders(), HttpStatus.GONE); + } + @ExceptionHandler({ IdFormatException.class, InvalidArgumentServiceException.class, diff --git a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java index ab38f04c..d88b4492 100644 --- a/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java +++ b/src/main/java/no/ndla/taxonomy/rest/v1/Nodes.java @@ -263,6 +263,7 @@ public void updateNode( @ResponseStatus(HttpStatus.ACCEPTED) @PreAuthorize("hasAuthority('TAXONOMY_ADMIN')") @Transactional + @Deprecated public void publishNode( @PathVariable("id") URI id, @Parameter( @@ -273,7 +274,7 @@ public void publishNode( @Parameter(description = "Version id to publish to.", example = "urn:version:2") @RequestParam(value = "targetId") URI targetId) { - nodeService.publishNode(id, sourceId, targetId, true, false); + throw new UnsupportedOperationException("This endpoint is deprecated"); } @GetMapping("/{id}/nodes") diff --git a/src/main/java/no/ndla/taxonomy/service/ChangelogService.java b/src/main/java/no/ndla/taxonomy/service/ChangelogService.java deleted file mode 100644 index 36e9631b..00000000 --- a/src/main/java/no/ndla/taxonomy/service/ChangelogService.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Part of NDLA taxonomy-api - * Copyright (C) 2022 NDLA - * - * See LICENSE - */ - -package no.ndla.taxonomy.service; - -import java.util.ConcurrentModificationException; -import java.util.Optional; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import no.ndla.taxonomy.domain.Changelog; -import no.ndla.taxonomy.domain.DomainEntity; -import no.ndla.taxonomy.repositories.ChangelogRepository; -import no.ndla.taxonomy.service.exceptions.NotFoundServiceException; -import no.ndla.taxonomy.service.task.Fetcher; -import no.ndla.taxonomy.service.task.Updater; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -@Transactional -public class ChangelogService implements DisposableBean { - final Logger logger = LoggerFactory.getLogger(this.getClass()); - private final ChangelogRepository changelogRepository; - private final DomainEntityHelperService domainEntityHelperService; - private final VersionService versionService; - private final ExecutorService executor = Executors.newSingleThreadExecutor(); - - public ChangelogService( - ChangelogRepository changelogRepository, - DomainEntityHelperService domainEntityHelperService, - VersionService versionService) { - this.changelogRepository = changelogRepository; - this.domainEntityHelperService = domainEntityHelperService; - this.versionService = versionService; - } - - @Transactional - @Scheduled(fixedRate = 10, timeUnit = TimeUnit.SECONDS) - public void removeFinishedChangelogs() { - changelogRepository.deleteByDoneTrue(); - } - - @Scheduled(fixedRate = 1, timeUnit = TimeUnit.SECONDS) - @Transactional - public void processChanges() { - try { - Optional maybeChangelog = changelogRepository.findFirstByDoneFalse(); - if (maybeChangelog.isPresent()) { - Changelog changelog = maybeChangelog.get(); - if (changelog.isDone()) { - return; - } - DomainEntity entity; - // Fetch - try { - Fetcher fetcher = new Fetcher(); - fetcher.setVersion(versionService.schemaFromHash(changelog.getSourceSchema())); - fetcher.setPublicId(changelog.getPublicId()); - fetcher.setCleanUp(changelog.isCleanUp()); - fetcher.setDomainEntityHelperService(domainEntityHelperService); - - Future future = executor.submit(fetcher); - entity = future.get(); - } catch (Exception e) { - logger.info(e.getMessage(), e); - throw new NotFoundServiceException("Failed to fetch node from source schema", e); - } - // Update - try { - Updater updater = new Updater(); - updater.setVersion(versionService.schemaFromHash(changelog.getDestinationSchema())); - updater.setElement(entity); - updater.setCleanUp(changelog.isCleanUp()); - updater.setDomainEntityHelperService(domainEntityHelperService); - - Future future = executor.submit(updater); - future.get(); - } catch (Exception e) { - logger.info(e.getMessage(), e); - throw new NotFoundServiceException("Failed to update entity", e); - } - changelog.setDone(true); - changelogRepository.save(changelog); - } - } catch (ConcurrentModificationException cme) { - try { - logger.info("Another server tried to change entity at the same time: " + cme.getMessage()); - var random = new Random(); - Thread.sleep(1000 + random.nextInt(5000)); - } catch (InterruptedException ie) { - // Nothing to see here - } - } catch (Exception exception) { - logger.info("Failed to process entity " + exception.getMessage()); - } - } - - @Override - public void destroy() throws Exception { - executor.shutdown(); - } -} diff --git a/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperService.java b/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperService.java index e897834f..a66494f0 100644 --- a/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperService.java +++ b/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperService.java @@ -8,23 +8,11 @@ package no.ndla.taxonomy.service; import java.net.URI; -import java.util.Optional; import no.ndla.taxonomy.domain.DomainEntity; import no.ndla.taxonomy.domain.Node; -import no.ndla.taxonomy.repositories.TaxonomyRepository; public interface DomainEntityHelperService { Node getNodeByPublicId(URI publicId); DomainEntity getEntityByPublicId(URI publicId); - - TaxonomyRepository getRepository(URI publicId); - - void buildPathsForEntity(URI publicId); - - void deleteEntityByPublicId(URI publicId); - - Optional getProcessedEntityByPublicId(URI publicId, boolean addIsPublishing, boolean cleanUp); - - Optional updateEntity(DomainEntity domainEntity, boolean cleanUp); } diff --git a/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java b/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java index 37e158bb..0a6941c0 100644 --- a/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java +++ b/src/main/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImpl.java @@ -8,13 +8,10 @@ package no.ndla.taxonomy.service; import java.net.URI; -import java.util.*; -import java.util.stream.Collectors; -import no.ndla.taxonomy.domain.*; +import no.ndla.taxonomy.domain.DomainEntity; +import no.ndla.taxonomy.domain.Node; import no.ndla.taxonomy.repositories.NodeConnectionRepository; import no.ndla.taxonomy.repositories.NodeRepository; -import no.ndla.taxonomy.repositories.ResourceTypeRepository; -import no.ndla.taxonomy.repositories.TaxonomyRepository; import no.ndla.taxonomy.service.exceptions.NotFoundServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,18 +25,11 @@ public class DomainEntityHelperServiceImpl implements DomainEntityHelperService final Logger logger = LoggerFactory.getLogger(this.getClass()); private final NodeRepository nodeRepository; private final NodeConnectionRepository nodeConnectionRepository; - private final ResourceTypeRepository resourceTypeRepository; - private final ContextUpdaterService cachedUrlUpdaterService; public DomainEntityHelperServiceImpl( - NodeRepository nodeRepository, - NodeConnectionRepository nodeConnectionRepository, - ResourceTypeRepository resourceTypeRepository, - ContextUpdaterService cachedUrlUpdaterService) { + NodeRepository nodeRepository, NodeConnectionRepository nodeConnectionRepository) { this.nodeRepository = nodeRepository; this.nodeConnectionRepository = nodeConnectionRepository; - this.resourceTypeRepository = resourceTypeRepository; - this.cachedUrlUpdaterService = cachedUrlUpdaterService; } @Override @@ -63,229 +53,4 @@ public DomainEntity getEntityByPublicId(URI publicId) { } throw new NotFoundServiceException("Entity of type not found"); } - - @Override - public TaxonomyRepository getRepository(URI publicId) { - switch (publicId.getSchemeSpecificPart().split(":")[0]) { - case "subject", "topic", "node", "resource", "programme" -> { - return nodeRepository; - } - case "node-connection", "subject-topic", "topic-subtopic", "node-resource", "topic-resource" -> { - return nodeConnectionRepository; - } - } - throw new NotFoundServiceException(String.format("Unknown repository requested: %s", publicId)); - } - - @Override - @Transactional - public void buildPathsForEntity(URI publicId) { - DomainEntity domainEntity = getEntityByPublicId(publicId); - if (domainEntity instanceof Node) { - cachedUrlUpdaterService.updateContexts((Node) domainEntity); - } - } - - @Override - @Transactional - public void deleteEntityByPublicId(URI publicId) { - TaxonomyRepository repository = getRepository(publicId); - repository.deleteByPublicId(publicId); - } - - @Override - @Transactional - public Optional getProcessedEntityByPublicId(URI publicId, boolean addIsPublishing, boolean cleanUp) { - DomainEntity entity = getEntityByPublicId(publicId); - if (entity != null) { - initializeFields(entity); - } - if (entity instanceof EntityWithMetadata entityWithMetadata) { - if (addIsPublishing && !cleanUp) { - entityWithMetadata.setCustomField(CustomField.IS_PUBLISHING, "true"); - return Optional.of(entity); - } - if (cleanUp) { - entityWithMetadata.unsetCustomField(CustomField.IS_PUBLISHING); - entityWithMetadata.unsetCustomField(CustomField.REQUEST_PUBLISH); - entityWithMetadata.unsetCustomField(CustomField.IS_CHANGED); - } - } - return Optional.ofNullable(entity); - } - - private void initializeFields(DomainEntity domainEntity) { - if (domainEntity instanceof Node) { - ((Node) domainEntity).getTranslations().forEach(JsonTranslation::getName); - ((Node) domainEntity).getChildConnections(); - ((Node) domainEntity).getParentConnections(); - ((Node) domainEntity).getResourceResourceTypes(); - ((Node) domainEntity).getResourceResourceTypes().forEach(ResourceResourceType::getResourceType); - ((Node) domainEntity).getResourceTypes().forEach(this::initializeFields); - } else if (domainEntity instanceof NodeConnection) { - ((NodeConnection) domainEntity).getParent().ifPresent(this::initializeFields); - ((NodeConnection) domainEntity).getChild().ifPresent(this::initializeFields); - } else if (domainEntity instanceof ResourceType) { - ((ResourceType) domainEntity).getParent().ifPresent(this::initializeFields); - ((ResourceType) domainEntity).getTranslations().forEach(JsonTranslation::getName); - } - } - - @Override - @Transactional - public Optional updateEntity(DomainEntity domainEntity, boolean cleanUp) { - if (domainEntity instanceof Node) { - return updateNode((Node) domainEntity, cleanUp); - } - if (domainEntity instanceof NodeConnection) { - return updateNodeConnection((NodeConnection) domainEntity, cleanUp); - } - throw new IllegalArgumentException("Wrong type of element to update: " + domainEntity.getEntityName()); - } - - @Transactional(propagation = Propagation.MANDATORY) - private Optional updateNode(Node node, boolean cleanUp) { - Node result; - Node existing = nodeRepository.findByPublicId(node.getPublicId()); - node.getResourceTypes().forEach(this::ensureResourceTypesExists); - if (existing == null) { - result = nodeRepository.save(new Node(node)); - } else if (existing.equals(node)) { - result = existing; - } else { - logger.debug("Updating node " + node.getPublicId()); - existing.setName(node.getName()); - existing.setContentUri(node.getContentUri()); - existing.setNodeType(node.getNodeType()); - existing.setContext(node.isContext()); - existing.setTranslations(node.getTranslations()); - existing.setVisible(node.isVisible()); - existing.setCustomFields(node.getCustomFields()); - existing.setGrepCodes(node.getGrepCodes()); - - // ResourceTypes - Collection typesToSet = new HashSet<>(); - Collection typesToKeep = new HashSet<>(); - List existingTypes = existing.getResourceTypes().stream() - .map(DomainEntity::getPublicId) - .toList(); - node.getResourceTypes().forEach(resourceType -> { - if (existingTypes.contains(resourceType.getPublicId())) { - typesToKeep.add(resourceType.getPublicId()); - } else { - typesToSet.add(resourceType.getPublicId()); - } - }); - if (!typesToSet.isEmpty()) { - Map reusedUris = node.getResourceResourceTypes().stream() - .filter(resourceResourceType -> typesToSet.contains( - resourceResourceType.getResourceType().getPublicId())) - .collect(Collectors.toMap( - resourceResourceType -> - resourceResourceType.getResourceType().getPublicId(), - ResourceResourceType::getPublicId)); - - Collection toRemove = new HashSet<>(); - existing.getResourceResourceTypes().forEach(resourceResourceType -> { - if (!typesToKeep.contains( - resourceResourceType.getResourceType().getPublicId())) { - toRemove.add(resourceResourceType); - } - }); - toRemove.forEach(existing::removeResourceResourceType); - typesToSet.forEach(uri -> { - ResourceType resourceType = resourceTypeRepository.findByPublicId(uri); - ResourceResourceType resourceResourceType = existing.addResourceType(resourceType); - if (reusedUris.containsKey(resourceType.getPublicId())) { - resourceResourceType.setPublicId(reusedUris.get(resourceType.getPublicId())); - } - }); - } - - result = nodeRepository.save(existing); - } - // delete any orphans - List childIds = node.getChildConnections().stream() - .map(DomainEntity::getPublicId) - .toList(); - result.getChildConnections().forEach(nodeConnection -> { - if (!childIds.contains(nodeConnection.getPublicId())) { - // Connection deleted - deleteEntityByPublicId(nodeConnection.getPublicId()); - } - }); - if (cleanUp) { - buildPathsForEntity(result.getPublicId()); - } - return Optional.of(result); - } - - @Transactional(propagation = Propagation.MANDATORY) - private Optional updateNodeConnection(NodeConnection nodeConnection, boolean cleanUp) { - NodeConnection result; - NodeConnection existing = nodeConnectionRepository.findByPublicId(nodeConnection.getPublicId()); - if (existing == null) { - // Check if connection have changed id - Node parent = nodeRepository.findByPublicId( - nodeConnection.getParent().get().getPublicId()); - Node child = nodeRepository.findByPublicId( - nodeConnection.getChild().get().getPublicId()); - if (parent == null || child == null) { - return Optional.empty(); - } - existing = nodeConnectionRepository.findByParentIdAndChildId(parent.getId(), child.getId()); - if (existing != null) { - existing.setPublicId(nodeConnection.getPublicId()); - result = updateExisting(existing, nodeConnection); - } else { - nodeConnection.setParent(parent); - nodeConnection.setChild(child); - NodeConnection connection = new NodeConnection(nodeConnection); - result = nodeConnectionRepository.save(connection); - } - } else { - if (existing.equals(nodeConnection)) { - return Optional.of(existing); - } - logger.debug("Updating nodeconnection " + nodeConnection.getPublicId()); - existing.setParent(nodeRepository.findByPublicId( - nodeConnection.getParent().get().getPublicId())); - existing.setChild(nodeRepository.findByPublicId( - nodeConnection.getChild().get().getPublicId())); - result = updateExisting(existing, nodeConnection); - } - if (cleanUp) { - buildPathsForEntity(result.getChild().get().getPublicId()); - } - return Optional.of(result); - } - - private NodeConnection updateExisting(NodeConnection existing, NodeConnection nodeConnection) { - existing.setRank(nodeConnection.getRank()); - existing.setVisible(nodeConnection.isVisible()); - existing.setGrepCodes(nodeConnection.getGrepCodes()); - existing.setCustomFields(nodeConnection.getCustomFields()); - if (nodeConnection.getRelevance().isPresent()) { - existing.setRelevance(nodeConnection.getRelevance().get()); - } - if (nodeConnection.isPrimary().isPresent()) { - existing.setPrimary(nodeConnection.isPrimary().get()); - } - return nodeConnectionRepository.save(existing); - } - - private ResourceType ensureResourceTypesExists(ResourceType resourceType) { - ResourceType parent = null; - if (resourceType.getParent().isPresent()) { - parent = ensureResourceTypesExists(resourceType.getParent().get()); - } - Optional existing = - resourceTypeRepository.findFirstByPublicIdIncludingTranslations(resourceType.getPublicId()); - if (existing.isEmpty()) { - // Create resource type - ResourceType rt = new ResourceType(resourceType, parent); - return resourceTypeRepository.save(rt); - } - return existing.get(); - } } diff --git a/src/main/java/no/ndla/taxonomy/service/NodeService.java b/src/main/java/no/ndla/taxonomy/service/NodeService.java index d0832f29..077742f2 100644 --- a/src/main/java/no/ndla/taxonomy/service/NodeService.java +++ b/src/main/java/no/ndla/taxonomy/service/NodeService.java @@ -9,15 +9,11 @@ import java.net.URI; import java.util.*; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import java.util.stream.Stream; import no.ndla.taxonomy.config.Constants; import no.ndla.taxonomy.domain.*; -import no.ndla.taxonomy.repositories.ChangelogRepository; import no.ndla.taxonomy.repositories.NodeConnectionRepository; import no.ndla.taxonomy.repositories.NodeRepository; import no.ndla.taxonomy.repositories.RelevanceRepository; @@ -28,11 +24,9 @@ import no.ndla.taxonomy.rest.v1.dtos.searchapi.TaxonomyContextDTO; import no.ndla.taxonomy.service.dtos.*; import no.ndla.taxonomy.service.exceptions.NotFoundServiceException; -import no.ndla.taxonomy.service.task.Fetcher; import no.ndla.taxonomy.util.PrettyUrlUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.jpa.domain.Specification; import org.springframework.scheduling.annotation.Async; @@ -41,32 +35,22 @@ @Transactional(readOnly = true) @Service -public class NodeService implements SearchService, DisposableBean { +public class NodeService implements SearchService { Logger logger = LoggerFactory.getLogger(getClass().getName()); private final NodeRepository nodeRepository; private final NodeConnectionRepository nodeConnectionRepository; private final NodeConnectionService connectionService; - private final VersionService versionService; private final TreeSorter topicTreeSorter; - private final ChangelogRepository changelogRepository; private final DomainEntityHelperService domainEntityHelperService; private final RecursiveNodeTreeService recursiveNodeTreeService; private final TreeSorter treeSorter; private final ContextUpdaterService cachedUrlUpdaterService; private final RelevanceRepository relevanceRepository; - private final ExecutorService executor = Executors.newSingleThreadExecutor(); - @Value(value = "${new.url.separator:false}") private boolean newUrlSeparator; - @Override - public void destroy() throws Exception { - executor.shutdown(); - } - public NodeService( - ChangelogRepository changelogRepository, DomainEntityHelperService domainEntityHelperService, NodeConnectionService connectionService, NodeConnectionRepository nodeConnectionRepository, @@ -74,15 +58,12 @@ public NodeService( RecursiveNodeTreeService recursiveNodeTreeService, TreeSorter topicTreeSorter, TreeSorter treeSorter, - VersionService versionService, ContextUpdaterService cachedUrlUpdaterService, RelevanceRepository relevanceRepository) { this.nodeRepository = nodeRepository; this.nodeConnectionRepository = nodeConnectionRepository; this.connectionService = connectionService; - this.versionService = versionService; this.topicTreeSorter = topicTreeSorter; - this.changelogRepository = changelogRepository; this.domainEntityHelperService = domainEntityHelperService; this.recursiveNodeTreeService = recursiveNodeTreeService; this.treeSorter = treeSorter; @@ -369,69 +350,6 @@ public boolean makeAllResourcesPrimary(URI nodePublicId, boolean recursive) { .allMatch(resourceConnection -> resourceConnection.isPrimary().orElse(false)); } - /** - * Adds node and children to table to be processed later. - * Wrapper async method to private inner method. - * - * @param nodeId Public ID of the node to publish - * @param sourceId Public ID of source schema. Default schema if not present - * @param targetId Public ID of target schema. Mandatory - * @param isPublishRoot Used to save meta-field to track which node is publishing - * @param cleanUp Used to clean up metadata after publishing - */ - @Async - @Transactional - public void publishNode(URI nodeId, Optional sourceId, URI targetId, boolean isPublishRoot, boolean cleanUp) { - publishNodeSync(nodeId, sourceId, targetId, isPublishRoot, cleanUp); - } - - @Transactional - private void publishNodeSync( - URI nodeId, Optional sourceId, URI targetId, boolean isPublishRoot, boolean cleanUp) { - String source = sourceId.flatMap( - sid -> versionService.findVersionByPublicId(sid).map(Version::getHash)) - .orElse(null); - String target = versionService - .findVersionByPublicId(targetId) - .map(Version::getHash) - .orElseThrow(() -> new NotFoundServiceException("Target version not found! Aborting")); - - Node node; - try { - Fetcher fetcher = new Fetcher(); - fetcher.setDomainEntityHelperService(domainEntityHelperService); - fetcher.setVersion(versionService.schemaFromHash(source)); - fetcher.setPublicId(nodeId); - fetcher.setAddIsPublishing(isPublishRoot); - Future future = executor.submit(fetcher); - node = (Node) future.get(); - } catch (Exception e) { - logger.info(e.getMessage(), e); - throw new NotFoundServiceException("Failed to fetch node from source schema", e); - } - // At first run, makes sure node exists in db for node-connection to be saved. - if (!cleanUp) { - changelogRepository.save(new Changelog(source, target, nodeId, false)); - } - for (NodeConnection connection : node.getChildConnections()) { - if (connection.getChild().isPresent()) { - Node child = connection.getChild().get(); - publishNodeSync(child.getPublicId(), sourceId, targetId, false, cleanUp); - } - changelogRepository.save(new Changelog(source, target, connection.getPublicId(), cleanUp)); - } - // When cleaning, node can be cleaned last to end with publish request to be stripped - if (cleanUp) { - changelogRepository.save(new Changelog(source, target, nodeId, true)); - } else { - // Once more, with cleaning - publishNodeSync(nodeId, sourceId, targetId, false, true); - } - if (isPublishRoot) { - logger.info("Node " + nodeId + " added to changelog for publishing to " + target); - } - } - public Node cloneNode(URI publicId, Optional contentUri) { final var node = getNode(publicId); var cloned = new Node(node, false); diff --git a/src/main/java/no/ndla/taxonomy/service/task/Fetcher.java b/src/main/java/no/ndla/taxonomy/service/task/Fetcher.java deleted file mode 100644 index 5ffd2c8e..00000000 --- a/src/main/java/no/ndla/taxonomy/service/task/Fetcher.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Part of NDLA taxonomy-api - * Copyright (C) 2022 NDLA - * - * See LICENSE - */ - -package no.ndla.taxonomy.service.task; - -import java.net.URI; -import java.util.Optional; -import no.ndla.taxonomy.domain.DomainEntity; -import no.ndla.taxonomy.service.DomainEntityHelperService; - -public class Fetcher extends Task { - private DomainEntityHelperService domainEntityHelperService; - private URI publicId; - private boolean addIsPublishing; - - public Fetcher() {} - - public void setDomainEntityHelperService(DomainEntityHelperService domainEntityHelperService) { - this.domainEntityHelperService = domainEntityHelperService; - } - - public void setPublicId(URI publicId) { - this.publicId = publicId; - } - - public void setAddIsPublishing(boolean addIsPublishing) { - this.addIsPublishing = addIsPublishing; - } - - @Override - protected Optional execute() { - return domainEntityHelperService.getProcessedEntityByPublicId( - this.publicId, this.addIsPublishing, this.cleanUp); - } -} diff --git a/src/main/java/no/ndla/taxonomy/service/task/Updater.java b/src/main/java/no/ndla/taxonomy/service/task/Updater.java deleted file mode 100644 index 628c565a..00000000 --- a/src/main/java/no/ndla/taxonomy/service/task/Updater.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Part of NDLA taxonomy-api - * Copyright (C) 2022 NDLA - * - * See LICENSE - */ - -package no.ndla.taxonomy.service.task; - -import java.util.Optional; -import no.ndla.taxonomy.domain.DomainEntity; -import no.ndla.taxonomy.service.DomainEntityHelperService; - -public class Updater extends Task { - private DomainEntityHelperService domainEntityHelperService; - private DomainEntity element; - - public void setDomainEntityHelperService(DomainEntityHelperService domainEntityHelperService) { - this.domainEntityHelperService = domainEntityHelperService; - } - - public void setElement(DomainEntity element) { - this.element = element; - } - - @Override - protected Optional execute() { - return domainEntityHelperService.updateEntity(element, this.cleanUp); - } -} diff --git a/src/main/resources/db-master-changelog.xml b/src/main/resources/db-master-changelog.xml index 32f918cc..84e54253 100644 --- a/src/main/resources/db-master-changelog.xml +++ b/src/main/resources/db-master-changelog.xml @@ -1534,5 +1534,8 @@ + + + diff --git a/src/test/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImplTest.java b/src/test/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImplTest.java index ddcd9947..c2b3f151 100644 --- a/src/test/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImplTest.java +++ b/src/test/java/no/ndla/taxonomy/service/DomainEntityHelperServiceImplTest.java @@ -16,7 +16,6 @@ import no.ndla.taxonomy.domain.NodeType; import no.ndla.taxonomy.repositories.NodeConnectionRepository; import no.ndla.taxonomy.repositories.NodeRepository; -import no.ndla.taxonomy.repositories.ResourceTypeRepository; import no.ndla.taxonomy.service.exceptions.NotFoundServiceException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -42,13 +41,8 @@ class DomainEntityHelperServiceImplTest extends AbstractIntegrationTest { private DomainEntityHelperServiceImpl service; @BeforeEach - void setUp( - @Autowired NodeRepository nodeRepository, - @Autowired NodeConnectionRepository nodeConnectionRepository, - @Autowired ResourceTypeRepository resourceTypeRepository, - @Autowired ContextUpdaterService cachedUrlUpdaterService) { - service = new DomainEntityHelperServiceImpl( - nodeRepository, nodeConnectionRepository, resourceTypeRepository, cachedUrlUpdaterService); + void setUp(@Autowired NodeRepository nodeRepository, @Autowired NodeConnectionRepository nodeConnectionRepository) { + service = new DomainEntityHelperServiceImpl(nodeRepository, nodeConnectionRepository); topic1 = new Node(NodeType.TOPIC); topic1.setPublicId(URI.create("urn:topic:test:1")); diff --git a/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java b/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java deleted file mode 100644 index ad825444..00000000 --- a/src/test/java/no/ndla/taxonomy/service/NodePublishingIntegrationTest.java +++ /dev/null @@ -1,708 +0,0 @@ -/* - * Part of NDLA taxonomy-api - * Copyright (C) 2022 NDLA - * - * See LICENSE - */ - -package no.ndla.taxonomy.service; - -import static no.ndla.taxonomy.TestUtils.assertAnyTrue; -import static org.junit.jupiter.api.Assertions.*; - -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import no.ndla.taxonomy.domain.*; -import no.ndla.taxonomy.repositories.ChangelogRepository; -import no.ndla.taxonomy.repositories.NodeConnectionRepository; -import no.ndla.taxonomy.repositories.NodeRepository; -import no.ndla.taxonomy.repositories.VersionRepository; -import no.ndla.taxonomy.rest.v1.commands.VersionPostPut; -import org.junit.jupiter.api.BeforeEach; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; -import org.springframework.test.context.transaction.TestTransaction; -import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.annotation.Transactional; - -/** - * Will only be run in maven using '-P integration' - */ -@SpringBootTest -public class NodePublishingIntegrationTest extends AbstractIntegrationTest { - - @Autowired - VersionRepository versionRepository; - - @Autowired - NodeRepository nodeRepository; - - @Autowired - NodeConnectionRepository nodeConnectionRepository; - - @Autowired - NodeService nodeService; - - @Autowired - NodeConnectionService nodeConnectionService; - - @Autowired - VersionService versionService; - - @Autowired - ChangelogRepository changelogRepository; - - @Autowired - Builder builder; - - @Autowired - DomainEntityHelperService domainEntityHelperService; - - @Autowired - ThreadPoolTaskExecutor executor; - - @BeforeEach - void clearAllRepos() { - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - versionRepository.deleteAllAndFlush(); - nodeConnectionRepository.deleteAllAndFlush(); - nodeRepository.deleteAllAndFlush(); - changelogRepository.deleteAll(); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node node = builder.node(n -> n.publicId("urn:node:1") - .name("Node") - .grepCode("KM123") - .customField("key", "value") - .isContext(true) - .translation("NN Node", "nn") - .translation("NB Node", "nb")); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node published = nodeRepository.findFirstByPublicId(node.getPublicId()).get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(published); - assertNotEquals(node.getId(), published.getId()); // node should have 1, published 3 - assertEquals(node.getName(), published.getName()); - assertEquals(node.getNodeType(), published.getNodeType()); - assertEquals(1, published.getContexts().size()); - assertEquals(node.getMetadata().isVisible(), published.getMetadata().isVisible()); - assertEquals( - node.getMetadata().getGrepCodes().size(), - published.getMetadata().getGrepCodes().size()); - assertAnyTrue(published.getMetadata().getGrepCodes(), grepCode -> grepCode.getCode() - .equals("KM123")); - assertEquals(node.getCustomFields().size(), published.getCustomFields().size()); - assertAnyTrue( - published.getCustomFields().entrySet(), - customFieldValue -> customFieldValue.getKey().equals("key")); - assertAnyTrue( - published.getCustomFields().entrySet(), - customFieldValue -> customFieldValue.getValue().equals("value")); - assertNotNull(published.getTranslations()); - assertAnyTrue( - published.getTranslations(), - translation -> translation.getName().contains("NN Node")); - assertAnyTrue( - published.getTranslations(), - translation -> translation.getName().contains("NB Node")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_with_resource_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.resource(r -> r.publicId("urn:resource:first"))); - Node node = builder.node(n -> n.publicId("urn:node:1") - .grepCode("KM123") - .customField("key", "value") - .resource(r -> r.publicId("urn:resource:1") - .name("Resource") - .grepCode("KM234") - .customField("key2", "value2") - .translation("nb", tr -> tr.name("Resource NB")) - .translation("nn", tr -> tr.name("Resource NN")))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node published = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(node.getPublicId(), false, false) - .get(); - Node connected = published.getResourceChildren().stream() - .findFirst() - .get() - .getResource() - .get(); - Node resource = - nodeRepository.findFirstByPublicId(connected.getPublicId()).get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertEquals( - node.getResourceChildren().size(), - published.getResourceChildren().size()); - assertNotEquals(node.getId(), published.getId()); - assertEquals("urn:resource:1", connected.getPublicId().toString()); - assertEquals("Resource", connected.getName()); - assertAnyTrue(connected.getMetadata().getGrepCodes(), grepCode -> grepCode.getCode() - .equals("KM234")); - assertAnyTrue( - connected.getCustomFields().entrySet(), - customFieldValue -> customFieldValue.getKey().equals("key2")); - assertAnyTrue( - connected.getCustomFields().entrySet(), - customFieldValue -> customFieldValue.getValue().equals("value2")); - assertAnyTrue( - resource.getTranslations(), translation -> translation.getName().contains("Resource NB")); - assertAnyTrue( - resource.getTranslations(), translation -> translation.getName().contains("Resource NN")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_sub_node_with_resource_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node node = builder.node( - NodeType.SUBJECT, - s -> s.isContext(true).publicId("urn:subject:1").child(NodeType.TOPIC, t -> t.publicId("urn:topic:1") - .resource(r -> - r.publicId("urn:resource:1").name("Resource").isVisible(false)))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Optional resource = nodeRepository.findFirstByPublicId(URI.create("urn:resource:1")); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertTrue(resource.isPresent()); - assertFalse(resource.get().getMetadata().isVisible()); - assertEquals("Resource", resource.get().getName()); - assertAnyTrue(resource.get().getAllPaths(), path -> path.equals("/subject:1/topic:1/resource:1")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_tree_with_resources_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node node = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:1") - .child(NodeType.TOPIC, t -> t.publicId("urn:topic:1").resource(r -> r.publicId("urn:resource:1"))) - .child(NodeType.TOPIC, t2 -> t2.publicId("urn:topic:2") - .resource(r2 -> r2.publicId("urn:resource:2")) - .child( - NodeType.TOPIC, - t3 -> t3.publicId("urn:topic:3").grepCode("TT2").isVisible(false)))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node resource = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:resource:1"), false, false) - .get(); - Node subnode = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:topic:2"), false, false) - .get(); - Node subsubnode = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:topic:3"), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(resource); - assertNotNull(subnode); - assertFalse(subnode.getResourceChildren().isEmpty()); - assertNotNull(subsubnode); - assertAnyTrue(subsubnode.getMetadata().getGrepCodes(), grepCode -> grepCode.getCode() - .equals("TT2")); - assertAnyTrue(resource.getAllPaths(), path -> path.equals("/subject:1/topic:1/resource:1")); - assertAnyTrue(subnode.getAllPaths(), path -> path.equals("/subject:1/topic:2")); - assertAnyTrue(subsubnode.getAllPaths(), path -> path.equals("/subject:1/topic:2/topic:3")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_tree_with_reused_resource_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // nodes to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - builder.node(n -> n.publicId("urn:node:second").resource(r -> r.publicId("urn:resource:second"))); - builder.node(n -> n.publicId("urn:node:third").resource(r -> r.publicId("urn:resource:third"))); - Node resource = builder.node(NodeType.RESOURCE, r -> r.publicId("urn:resource:1")); - Node node = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:1") - .child(NodeType.TOPIC, t -> t.publicId("urn:topic:1").resource(resource)) - .child(NodeType.TOPIC, t2 -> t2.publicId("urn:topic:2") - .resource(resource) - .resource(r2 -> r2.publicId("urn:resource:2")) - .child( - NodeType.TOPIC, - t3 -> t3.publicId("urn:topic:3").grepCode("TT2").isVisible(false)))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node updated = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:resource:1"), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(updated); - assertNotEquals(updated.getId(), resource.getId()); - assertNotNull(updated.getContexts()); - assertEquals(2, updated.getParentConnections().size()); // Should be used twice - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:1"))); - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:2"))); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:1/topic:1/resource:1")); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:1/topic:2/resource:1")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_in_tree_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node child = builder.node(n -> n.publicId("urn:node:1") - .isContext(true) - .isVisible(false) - .resource(r2 -> r2.publicId("urn:resource:2"))); - Node node = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:1") - .child(NodeType.TOPIC, t -> t.publicId("urn:topic:1")) - .child(child) - .child(NodeType.TOPIC, t3 -> t3.publicId("urn:topic:3").isVisible(false))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node updatedChild = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(child.getPublicId(), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(updatedChild); - assertFalse(updatedChild.getMetadata().isVisible()); - assertFalse(updatedChild.getResourceChildren().isEmpty()); - assertFalse(updatedChild.getParentNodes().isEmpty()); - assertEquals( - node.getPublicId(), - updatedChild.getParentNodes().stream().findFirst().get().getPublicId()); - assertAnyTrue(updatedChild.getAllPaths(), path -> path.equals("/subject:1/node:1")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_tree_with_reused_resource_twice_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node resource = builder.node(NodeType.RESOURCE, r -> r.publicId("urn:resource:1")); - Node node = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:1") - .child(NodeType.TOPIC, t2 -> t2.publicId("urn:topic:1").resource(resource))); - Node second = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:2") - .child(NodeType.TOPIC, t -> t.publicId("urn:topic:2").resource(resource))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - nodeService.publishNode(second.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node updated = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:resource:1"), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(updated); - assertNotNull(updated.getContexts()); - assertEquals(2, updated.getParentConnections().size()); // Should be used twice - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:1"))); - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:2"))); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:1/topic:1/resource:1")); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:2/topic:2/resource:1")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_reused_resource_with_translations_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - builder.resourceType(rt -> rt.name("Fagstoff") - .translation("nb", t -> t.name("Fagstoff nb")) - .translation("nn", t -> t.name("Fagstoff nn")) - .subtype("urn:resourcetype:1", st -> st.name("Fagartikkel") - .publicId("urn:resourcetype:1") - .translation("nb", t -> t.name("Fagartikkel nb")) - .translation("nn", t -> t.name("Fagartikkel nn")))); - Node resource = builder.node(NodeType.RESOURCE, r -> r.publicId("urn:resource:1") - .resourceType("urn:resourcetype:1") - .translation("nb", tr -> tr.name("Resource nb")) - .translation("nn", tr -> tr.name("Resource nn"))); - Node node = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:1") - .child(NodeType.TOPIC, t2 -> t2.publicId("urn:topic:1").resource(resource))); - Node second = builder.node(NodeType.SUBJECT, s -> s.isContext(true) - .publicId("urn:subject:2") - .child(NodeType.TOPIC, t -> t.publicId("urn:topic:2").resource(resource))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - // Update translations to resource in standard schema for updating - TestTransaction.start(); - TestTransaction.flagForCommit(); - Node r = nodeRepository.findByPublicId(resource.getPublicId()); - var nb = r.getTranslation("nb"); - // Update - nb.get().setName("Resource nb updated"); - // Add new - var resourceTranslation = new JsonTranslation("en"); - resourceTranslation.setName("Resource en"); - r.addTranslation(resourceTranslation); - // Remove - r.removeTranslation("nn"); - entityManager.persist(r); - TestTransaction.end(); - - nodeService.publishNode(second.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node updated = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:resource:1"), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(updated); - assertNotNull(updated.getContexts()); - assertEquals(2, updated.getParentConnections().size()); // Should be used twice - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:1"))); - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:2"))); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:1/topic:1/resource:1")); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:2/topic:2/resource:1")); - - assertNotNull(updated.getResourceTypes()); - assertEquals(1, updated.getResourceTypes().size()); - - assertEquals(2, updated.getTranslations().size()); - assertAnyTrue( - updated.getTranslations(), translation -> translation.getName().equals("Resource nb updated")); - assertAnyTrue( - updated.getTranslations(), translation -> translation.getName().equals("Resource en")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_twice_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node node = builder.node(n -> n.name("Node") - .isContext(true) - .translation("nn", tr -> tr.name("NN Node")) - .translation("nb", tr -> tr.name("NB Node"))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - // Update translations to node in standard schema for updating - TestTransaction.start(); - TestTransaction.flagForCommit(); - Node n = nodeRepository.findByPublicId(node.getPublicId()); - var nb = n.getTranslation("nb"); - // Update - nb.get().setName("NB Node updated"); - // Add new - n.addTranslation("EN Node", "en"); - // Remove - n.removeTranslation("nn"); - entityManager.persist(n); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node published = nodeRepository.findFirstByPublicId(node.getPublicId()).get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(published); - assertEquals(2, published.getTranslations().size()); - assertNotEquals(node.getId(), published.getId()); - assertAnyTrue( - published.getTranslations(), - translation -> translation.getName().contains("EN Node")); - assertAnyTrue( - published.getTranslations(), - translation -> translation.getName().contains("NB Node updated")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_tree_to_schema_async() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - List changelogs = changelogRepository.findAll(); - assertTrue(changelogs.isEmpty()); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node node = builder.node(n -> n.publicId("urn:node:1") - .name("Node") - .isContext(true) - .translation("nn", tr -> tr.name("NN Node")) - .translation("nb", tr -> tr.name("NB Node")) - .customField(CustomField.IS_CHANGED, "true") - .customField("to be kept", "true") - .child(c -> c.publicId("urn:node:2")) - .resource(r -> r.publicId("urn:resource:1"))); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - // Check node is published to schema - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node published = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(node.getPublicId(), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(published); - assertEquals(2, published.getTranslations().size()); - assertEquals(2, published.getChildNodes().size()); - assertEquals(1, published.getResources().size()); - var customfields = new ArrayList<>(published.getCustomFields().keySet()); - assertEquals(1, customfields.size()); - assertAnyTrue(customfields, customfield -> customfield.equals("to be kept")); - } - - @Transactional(propagation = Propagation.REQUIRES_NEW) - void can_publish_node_tree_with_moved_resource_to_schema() throws Exception { - final var command = new VersionPostPut() { - { - name = "Beta"; - } - }; - Version target = versionService.createNewVersion(Optional.empty(), command); - assertTrue(checkSchemaExists(versionService.schemaFromHash(target.getHash()))); - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - - // a node to make sure testnode is not the first - builder.node(n -> n.publicId("urn:node:first").resource(r -> r.publicId("urn:resource:first"))); - Node resource = builder.node(NodeType.RESOURCE, r -> r.publicId("urn:resource:1")); - Node topic1 = - builder.node(NodeType.TOPIC, t -> t.publicId("urn:topic:1").resource(resource)); - Node topic2 = builder.node(NodeType.TOPIC, t -> t.publicId("urn:topic:2")); - Node node = builder.node( - NodeType.SUBJECT, - s -> s.isContext(true).publicId("urn:subject:1").child(topic1).child(topic2)); - - TestTransaction.flagForCommit(); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - TestTransaction.start(); - TestTransaction.flagForCommit(); - // Move resource to another node - nodeConnectionService.disconnectParentChild(topic1, resource); - nodeConnectionService.connectParentChild(topic2, resource, builder.core(), null, Optional.empty()); - TestTransaction.end(); - - nodeService.publishNode(node.getPublicId(), Optional.empty(), target.getPublicId(), true, false); - - while (!changelogRepository.findAll().isEmpty()) { - executor.getThreadPoolExecutor().awaitTermination(2, TimeUnit.SECONDS); - } - - VersionContext.setCurrentVersion(versionService.schemaFromHash(target.getHash())); - Node updated = (Node) domainEntityHelperService - .getProcessedEntityByPublicId(URI.create("urn:resource:1"), false, false) - .get(); - VersionContext.setCurrentVersion(versionService.schemaFromHash(null)); - - assertNotNull(updated); - assertNotNull(updated.getContexts()); - assertEquals(1, updated.getParentConnections().size()); - assertAnyTrue( - updated.getParentConnections(), - nodeResource -> nodeResource.getParent().get().getPublicId().equals(URI.create("urn:topic:2"))); - assertAnyTrue(updated.getAllPaths(), path -> path.equals("/subject:1/topic:2/resource:1")); - } -}