Skip to content

Commit

Permalink
Merge pull request #44 from who-icatx/20-be-postcoordination-action-a…
Browse files Browse the repository at this point in the history
…t-class-creation

added creation of postcoordination specification to new created entity
  • Loading branch information
alexsilaghi authored Oct 24, 2024
2 parents 8e99cda + f9b88dd commit eb29a9e
Show file tree
Hide file tree
Showing 5 changed files with 316 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package edu.stanford.protege.webprotege.postcoordinationservice.handlers;

import edu.stanford.protege.webprotege.ipc.*;
import edu.stanford.protege.webprotege.postcoordinationservice.dto.*;
import edu.stanford.protege.webprotege.postcoordinationservice.model.WhoficEntityPostCoordinationSpecification;
import edu.stanford.protege.webprotege.postcoordinationservice.services.*;
import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Mono;

import java.util.*;

@WebProtegeHandler
public class CreatePostcoordinationFromParentCommandHandler implements CommandHandler<CreatePostcoordinationFromParentRequest, CreatePostcoordinationFromParentResponse> {

private final PostCoordinationEventProcessor postCoordProcessor;
private final LinearizationService linService;

public CreatePostcoordinationFromParentCommandHandler(PostCoordinationEventProcessor postCoordProcessor,
LinearizationService linService) {

this.postCoordProcessor = postCoordProcessor;
this.linService = linService;
}

@NotNull
@Override
public String getChannelName() {
return CreatePostcoordinationFromParentRequest.CHANNEL;
}

@Override
public Class<CreatePostcoordinationFromParentRequest> getRequestClass() {
return CreatePostcoordinationFromParentRequest.class;
}

@Override
public Mono<CreatePostcoordinationFromParentResponse> handleRequest(CreatePostcoordinationFromParentRequest request, ExecutionContext executionContext) {
List<LinearizationDefinition> definitionList = linService.getLinearizationDefinitions();

var parentWhoficSpec = postCoordProcessor.fetchHistory(request.parentEntityIri().toString(), request.projectId());
List<PostCoordinationSpecification> newSpecsList = new ArrayList<>();

parentWhoficSpec.postcoordinationSpecifications().forEach(spec -> {
var currDef = definitionList.stream().filter(lin -> lin.getWhoficEntityIri().equalsIgnoreCase(spec.getLinearizationView())).findFirst();
if (currDef.isEmpty()) {
return;
}
var allAxes = new ArrayList<>(spec.getAllowedAxes());
allAxes.addAll(spec.getDefaultAxes());
allAxes.addAll(spec.getRequiredAxes());
allAxes.addAll(spec.getNotAllowedAxes());
PostCoordinationSpecification newSpec = new PostCoordinationSpecification(spec.getLinearizationView(), null, null, null, null);

if (currDef.get().getCoreLinId() != null) {
newSpec.getDefaultAxes().addAll(allAxes);
} else {
newSpec.getNotAllowedAxes().addAll(allAxes);
}
newSpecsList.add(newSpec);
});

postCoordProcessor.saveNewSpecificationRevision(
WhoficEntityPostCoordinationSpecification.create(request.newEntityIri().toString(), parentWhoficSpec.entityType(), newSpecsList),
executionContext.userId(),
request.projectId()
);
return Mono.just(CreatePostcoordinationFromParentResponse.create());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package edu.stanford.protege.webprotege.postcoordinationservice.handlers;

import com.fasterxml.jackson.annotation.*;
import edu.stanford.protege.webprotege.common.*;
import org.semanticweb.owlapi.model.IRI;

@JsonTypeName(CreatePostcoordinationFromParentRequest.CHANNEL)
public record CreatePostcoordinationFromParentRequest(
@JsonProperty("newEntityIri") IRI newEntityIri,
@JsonProperty("parentEntityIri") IRI parentEntityIri,
@JsonProperty("projectId") ProjectId projectId
) implements Request<CreatePostcoordinationFromParentResponse> {

public final static String CHANNEL = "webprotege.postcoordination.CreateFromParentEntity";

public static CreatePostcoordinationFromParentRequest create(IRI newEntityIri,
IRI parentEntityIri,
ProjectId projectId) {
return new CreatePostcoordinationFromParentRequest(newEntityIri, parentEntityIri, projectId);
}

@Override
public String getChannel() {
return CHANNEL;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package edu.stanford.protege.webprotege.postcoordinationservice.handlers;

import com.fasterxml.jackson.annotation.JsonTypeName;
import edu.stanford.protege.webprotege.common.Response;


@JsonTypeName(CreatePostcoordinationFromParentRequest.CHANNEL)
public record CreatePostcoordinationFromParentResponse() implements Response {
public static CreatePostcoordinationFromParentResponse create() {
return new CreatePostcoordinationFromParentResponse();
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
package edu.stanford.protege.webprotege.postcoordinationservice.model;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.*;
import edu.stanford.protege.webprotege.postcoordinationservice.dto.PostCoordinationSpecification;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.*;

public record WhoficEntityPostCoordinationSpecification(@JsonProperty("whoficEntityIri") String whoficEntityIri, @JsonProperty("entityType") String entityType,
public record WhoficEntityPostCoordinationSpecification(@JsonProperty("whoficEntityIri") String whoficEntityIri,
@JsonProperty("entityType") String entityType,
@JsonProperty("postcoordinationSpecifications") List<PostCoordinationSpecification> postcoordinationSpecifications) {

@JsonCreator
public WhoficEntityPostCoordinationSpecification(@JsonProperty("whoficEntityIri") @NotNull String whoficEntityIri,
@JsonProperty("entityType") String entityType,
@JsonProperty("postcoordinationSpecifications") List<PostCoordinationSpecification> postcoordinationSpecifications) {
public WhoficEntityPostCoordinationSpecification(@NotNull String whoficEntityIri,
String entityType,
List<PostCoordinationSpecification> postcoordinationSpecifications) {
this.whoficEntityIri = whoficEntityIri;
this.entityType = Objects.requireNonNullElse(entityType, "ICD");
this.postcoordinationSpecifications = Objects.requireNonNullElseGet(postcoordinationSpecifications, ArrayList::new);
}

@JsonCreator
public static WhoficEntityPostCoordinationSpecification create(@JsonProperty("whoficEntityIri") @NotNull String whoficEntityIri,
@JsonProperty("entityType") String entityType,
@JsonProperty("postcoordinationSpecifications") List<PostCoordinationSpecification> postcoordinationSpecifications) {
return new WhoficEntityPostCoordinationSpecification(whoficEntityIri,
entityType,
postcoordinationSpecifications);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package edu.stanford.protege.webprotege.postcoordinationservice.handlers;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.stanford.protege.webprotege.common.*;
import edu.stanford.protege.webprotege.ipc.ExecutionContext;
import edu.stanford.protege.webprotege.postcoordinationservice.*;
import edu.stanford.protege.webprotege.postcoordinationservice.dto.PostCoordinationSpecification;
import edu.stanford.protege.webprotege.postcoordinationservice.model.*;
import edu.stanford.protege.webprotege.postcoordinationservice.services.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.semanticweb.owlapi.model.IRI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.*;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.io.*;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;

@SpringBootTest
@Import({WebprotegePostcoordinationServiceServiceApplication.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_CLASS)
@ExtendWith({SpringExtension.class, IntegrationTest.class})
@ActiveProfiles("test")
class CreatePostcoordinationFromParentCommandHandlerIT {

@Autowired
private CreatePostcoordinationFromParentCommandHandler handler;

@Autowired
private PostCoordinationEventProcessor eventProcessor;

@MockBean
private LinearizationService linearizationService;

@Autowired
private ObjectMapper objectMapper;

@Autowired
private MongoTemplate mongoTemplate;

private ProjectId projectId;
private ExecutionContext executionContext;
private String parentEntityIri;
private String newEntityIri;

@BeforeEach
void setUp() throws IOException {
projectId = ProjectId.generate();
executionContext = new ExecutionContext(UserId.valueOf("testUser"), "testToken");
parentEntityIri = "http://example.org/parentEntity";
newEntityIri = "http://example.org/newEntity";
FileInputStream defintions = new FileInputStream("src/test/resources/LinearizationDefinitions.json");
when(linearizationService.getLinearizationDefinitions())
.thenReturn(objectMapper.readValue(defintions, new TypeReference<>() {
}));

mongoTemplate.getDb().drop();
}

@Test
void GIVEN_validParentWithCoreLinId_WHEN_handleRequest_THEN_defaultAxesShouldBeInherited() {
CreatePostcoordinationFromParentRequest request = CreatePostcoordinationFromParentRequest.create(
IRI.create(newEntityIri), IRI.create(parentEntityIri), projectId
);

WhoficEntityPostCoordinationSpecification parentSpec = new WhoficEntityPostCoordinationSpecification(
parentEntityIri, "ICD", List.of(
new PostCoordinationSpecification("http://id.who.int/icd/release/11/mms", List.of("axis1"), List.of("axis2"), List.of(), List.of())
));
eventProcessor.saveNewSpecificationRevision(parentSpec, UserId.getGuest(), projectId);

handler.handleRequest(request, executionContext).block();

WhoficEntityPostCoordinationSpecification savedSpec = eventProcessor.fetchHistory(newEntityIri, projectId);

assertNotNull(savedSpec, "The new specification should be saved.");
assertEquals(newEntityIri, savedSpec.whoficEntityIri(), "The saved specification should match the new entity IRI.");

PostCoordinationSpecification inheritedSpec = savedSpec.postcoordinationSpecifications().get(0);
assertEquals(List.of("axis1", "axis2"), inheritedSpec.getNotAllowedAxes(), "Axes inherited from parent should have not allowed values for main linearizations");
assertTrue(inheritedSpec.getDefaultAxes().isEmpty(), "Axes inherited from parent should have default values for telescopic linearizations");
}


@Test
void GIVEN_validParentWithoutCoreLinId_WHEN_handleRequest_THEN_notAllowedAxesShouldBeInherited() {
CreatePostcoordinationFromParentRequest request = CreatePostcoordinationFromParentRequest.create(
IRI.create(newEntityIri), IRI.create(parentEntityIri), projectId
);

WhoficEntityPostCoordinationSpecification parentSpec = WhoficEntityPostCoordinationSpecification.create(
parentEntityIri, "ICD", List.of(
new PostCoordinationSpecification("http://id.who.int/icd/release/11/icd-o", List.of("axis1"), List.of(), List.of(), List.of())
));
eventProcessor.saveNewSpecificationRevision(parentSpec, UserId.getGuest(), projectId);


handler.handleRequest(request, executionContext).block();

WhoficEntityPostCoordinationSpecification savedSpec = eventProcessor.fetchHistory(newEntityIri, projectId);

assertNotNull(savedSpec, "The new specification should be saved.");
assertEquals(newEntityIri, savedSpec.whoficEntityIri(), "The saved specification should match the new entity IRI.");

PostCoordinationSpecification inheritedSpec = savedSpec.postcoordinationSpecifications().get(0);
assertTrue(inheritedSpec.getDefaultAxes().isEmpty(), "defaultAxes should be empty for main linearizations");
assertEquals(List.of("axis1"), inheritedSpec.getNotAllowedAxes(), "notAllowedAxes should inherit from the parent all axes when linearization view is main linearization");
}

@Test
void GIVEN_invalidParentEntity_WHEN_handleRequest_THEN_noSpecificationShouldBeSaved() {
CreatePostcoordinationFromParentRequest request = CreatePostcoordinationFromParentRequest.create(
IRI.create(newEntityIri), IRI.create("http://invalid-parent-iri"), projectId
);

handler.handleRequest(request, executionContext).block();

Query query = new Query();
query.addCriteria(Criteria.where("whoficEntityIri").is(newEntityIri));
WhoficEntityPostCoordinationSpecification savedSpec = mongoTemplate.findOne(query, WhoficEntityPostCoordinationSpecification.class);

assertNull(savedSpec, "No specification should have been saved when the parent entity is invalid.");
}

@Test
void GIVEN_parentWithMultipleLinearizations_WHEN_handleRequest_THEN_axesShouldBeInheritedForEachView() {
CreatePostcoordinationFromParentRequest request = CreatePostcoordinationFromParentRequest.create(
IRI.create(newEntityIri), IRI.create(parentEntityIri), projectId
);

WhoficEntityPostCoordinationSpecification parentSpec = new WhoficEntityPostCoordinationSpecification(
parentEntityIri, "ICD", List.of(
new PostCoordinationSpecification("http://id.who.int/icd/release/11/mms", List.of("axis1"), List.of(), List.of(), List.of()),
new PostCoordinationSpecification("http://id.who.int/icd/release/11/pch", List.of("axis2"), List.of(), List.of(), List.of())
));
eventProcessor.saveNewSpecificationRevision(parentSpec, UserId.getGuest(), projectId);


handler.handleRequest(request, executionContext).block();

WhoficEntityPostCoordinationSpecification savedSpec = eventProcessor.fetchHistory(newEntityIri, projectId);

assertNotNull(savedSpec, "The new specification should be saved.");
assertEquals(2, savedSpec.postcoordinationSpecifications().size(), "There should be two linearization specifications.");

for (PostCoordinationSpecification inheritedSpec : savedSpec.postcoordinationSpecifications()) {
if (inheritedSpec.getLinearizationView().equals("http://id.who.int/icd/release/11/mms")) {
assertEquals(List.of("axis1"), inheritedSpec.getNotAllowedAxes(), "Should inherit axes for MMS (main linearization) and have not allowed value.");
} else if (inheritedSpec.getLinearizationView().equals("http://id.who.int/icd/release/11/pch")) {
assertEquals(List.of("axis2"), inheritedSpec.getDefaultAxes(), "Should inherit axes for PCH (telescopic linearization) and have default value");
}
}
}

@Test
void GIVEN_validRequest_WHEN_handleRequestTwice_THEN_noDuplicateSpecificationsShouldBeSaved() {
CreatePostcoordinationFromParentRequest request = CreatePostcoordinationFromParentRequest.create(
IRI.create(newEntityIri), IRI.create(parentEntityIri), projectId
);

WhoficEntityPostCoordinationSpecification parentSpec = new WhoficEntityPostCoordinationSpecification(
parentEntityIri, "ICD", List.of(
new PostCoordinationSpecification("http://id.who.int/icd/release/11/mms", List.of("axis1"), List.of(), List.of(), List.of())
));
eventProcessor.saveNewSpecificationRevision(parentSpec, UserId.getGuest(), projectId);


handler.handleRequest(request, executionContext).block();
handler.handleRequest(request, executionContext).block();

Query query = new Query();
query.addCriteria(Criteria.where("whoficEntityIri").is(newEntityIri));
EntityPostCoordinationHistory savedHistory = mongoTemplate.findOne(query, EntityPostCoordinationHistory.class);

assertNotNull(savedHistory);
assertEquals(1, savedHistory.getPostCoordinationRevisions().size(), "There should only be one saved revision.");
}


}


0 comments on commit eb29a9e

Please sign in to comment.