Search in sources :

Example 1 with Composition

use of com.nedap.archie.rm.composition.Composition in project ehrbase by ehrbase.

the class CustomMethodSecurityExpressionRoot method templateHandling.

/**
 * Handles template ID extraction of specific payload.
 * <p>
 * Payload will be a response body string, in case of @PostAuthorize.
 * <p>
 * Payload will be request body string, or already deserialized object (e.g. EhrStatus), in case of @PreAuthorize.
 * @param type Object type of scope
 * @param payload Payload object, either request's input or response's output
 * @param contentType Content type from the scope
 * @param requestMap ABAC request attribute map to add the result
 * @param authType Pre- or PostAuthorize, determines payload style (string or object)
 */
private void templateHandling(String type, Object payload, String contentType, Map<String, Object> requestMap, String authType) {
    switch(type) {
        case BaseController.EHR:
            throw new IllegalArgumentException("ABAC: Unsupported configuration: Can't set template ID for EHR type.");
        case BaseController.EHR_STATUS:
            throw new IllegalArgumentException("ABAC: Unsupported configuration: Can't set template ID for EHR_STATUS type.");
        case BaseController.COMPOSITION:
            String content = "";
            if (authType.equals(POST)) {
                // @PostAuthorize gives a ResponseEntity type for "returnObject", so payload is of that type
                if (((ResponseEntity) payload).hasBody()) {
                    Object body = ((ResponseEntity) payload).getBody();
                    // can have "No content" here (even with some data in the body) if the compo was (logically) deleted
                    if (((ResponseEntity<?>) payload).getStatusCode().equals(HttpStatus.NO_CONTENT)) {
                        if (body instanceof Map) {
                            Object error = ((Map<?, ?>) body).get("error");
                            if (error != null) {
                                if (((String) error).contains("delet")) {
                                    // composition was deleted, so nothing to check here, skip
                                    break;
                                }
                            }
                        }
                        throw new InternalServerException("ABAC: Unexpected empty response from composition reuquest");
                    }
                    if (body instanceof OriginalVersionResponseData) {
                        // case of versioned_composition --> fast path, because template is easy to get
                        if (((OriginalVersionResponseData<?>) body).getData() instanceof Composition) {
                            String template = Objects.requireNonNull(((Composition) ((OriginalVersionResponseData<?>) body).getData()).getArchetypeDetails().getTemplateId()).getValue();
                            requestMap.put(TEMPLATE, template);
                            // special case, so done here, exit
                            break;
                        }
                    } else if (body instanceof String) {
                        content = (String) body;
                    } else {
                        throw new InternalServerException("ABAC: unexpected composition payload object");
                    }
                } else {
                    throw new InternalServerException("ABAC: unexpected empty response body");
                }
            } else if (authType.equals(PRE)) {
                try {
                    // try if this is the Delete composition case. Payload would contain the UUID of the compo.
                    ObjectVersionId versionId = new ObjectVersionId((String) payload);
                    UUID compositionUid = UUID.fromString(versionId.getRoot().getValue());
                    Optional<CompositionDto> compoDto = compositionService.retrieve(compositionUid, null);
                    if (compoDto.isPresent()) {
                        Composition c = compoDto.get().getComposition();
                        requestMap.put(TEMPLATE, c.getArchetypeDetails().getTemplateId().getValue());
                        // special case, so done here, exit
                        break;
                    } else {
                        throw new InternalServerException("ABAC: unexpected empty response from composition delete");
                    }
                } catch (IllegalArgumentException e) {
                    // if not an UUID, the payload is a composition itself so continue
                    content = (String) payload;
                }
            } else {
                throw new InternalServerException("ABAC: invalid auth type given.");
            }
            String templateId;
            if (MediaType.parseMediaType(contentType).isCompatibleWith(MediaType.APPLICATION_JSON)) {
                templateId = compositionService.getTemplateIdFromInputComposition(content, CompositionFormat.JSON);
            } else if (MediaType.parseMediaType(contentType).isCompatibleWith(MediaType.APPLICATION_XML)) {
                templateId = compositionService.getTemplateIdFromInputComposition(content, CompositionFormat.XML);
            } else {
                throw new IllegalArgumentException("ABAC: Only JSON and XML composition are supported.");
            }
            requestMap.put(TEMPLATE, templateId);
            break;
        case BaseController.CONTRIBUTION:
            CompositionFormat format;
            if (MediaType.parseMediaType(contentType).isCompatibleWith(MediaType.APPLICATION_JSON)) {
                format = CompositionFormat.JSON;
            } else if (MediaType.parseMediaType(contentType).isCompatibleWith(MediaType.APPLICATION_XML)) {
                format = CompositionFormat.XML;
            } else {
                throw new IllegalArgumentException("ABAC: Only JSON and XML composition are supported.");
            }
            if (payload instanceof String) {
                Set<String> templates = contributionService.getListOfTemplates((String) payload, format);
                requestMap.put(TEMPLATE, templates);
                break;
            } else {
                throw new InternalServerException("ABAC: invalid POST contribution payload.");
            }
        case BaseController.QUERY:
            // special case of type QUERY, where multiple subjects are possible
            if (payload instanceof Map) {
                if (((Map<?, ?>) payload).containsKey(AuditVariables.TEMPLATE_PATH)) {
                    Set<String> templates = (Set) ((Map<?, ?>) payload).get(AuditVariables.TEMPLATE_PATH);
                    Set<String> templateSet = new HashSet<>(templates);
                    // put result set into the requestMap and exit
                    requestMap.put(TEMPLATE, templateSet);
                    break;
                } else {
                    throw new InternalServerException("ABAC: AQL audit template data unavailable.");
                }
            } else {
                throw new InternalServerException("ABAC: AQL audit template data malformed.");
            }
        default:
            throw new InternalServerException("ABAC: Invalid type given from Pre- or PostAuthorize");
    }
}
Also used : CompositionFormat(org.ehrbase.response.ehrscape.CompositionFormat) Composition(com.nedap.archie.rm.composition.Composition) HashSet(java.util.HashSet) Set(java.util.Set) Optional(java.util.Optional) InternalServerException(org.ehrbase.api.exception.InternalServerException) ObjectVersionId(com.nedap.archie.rm.support.identification.ObjectVersionId) OriginalVersionResponseData(org.ehrbase.response.openehr.OriginalVersionResponseData) ResponseEntity(org.springframework.http.ResponseEntity) UUID(java.util.UUID) HashMap(java.util.HashMap) Map(java.util.Map) HashSet(java.util.HashSet)

Example 2 with Composition

use of com.nedap.archie.rm.composition.Composition in project ehrbase by ehrbase.

the class CompositionServiceImp method getOriginalVersionComposition.

@Override
public Optional<OriginalVersion<Composition>> getOriginalVersionComposition(UUID versionedObjectUid, int version) {
    // check for valid version parameter
    if ((version == 0) || I_CompositionAccess.getLastVersionNumber(getDataAccess(), versionedObjectUid) < version) {
        throw new ObjectNotFoundException("versioned_composition", "No VERSIONED_COMPOSITION with given version: " + version);
    }
    // retrieve requested object
    I_CompositionAccess compositionAccess = I_CompositionAccess.retrieveCompositionVersion(getDataAccess(), versionedObjectUid, version);
    if (compositionAccess == null) {
        return Optional.empty();
    }
    // create data for output, i.e. fields of the OriginalVersion<Composition>
    ObjectVersionId versionId = new ObjectVersionId(versionedObjectUid + "::" + getServerConfig().getNodename() + "::" + version);
    DvCodedText lifecycleState = new DvCodedText("complete", new CodePhrase(// TODO: once lifecycle state is supported, get it here dynamically
    "532"));
    AuditDetails commitAudit = compositionAccess.getAuditDetailsAccess().getAsAuditDetails();
    ObjectRef<HierObjectId> contribution = new ObjectRef<>(new HierObjectId(compositionAccess.getContributionId().toString()), "openehr", "contribution");
    List<UUID> attestationIdList = I_AttestationAccess.retrieveListOfAttestationsByRef(getDataAccess(), compositionAccess.getAttestationRef());
    List<Attestation> attestations = // as default, gets content if available in the following lines
    null;
    if (!attestationIdList.isEmpty()) {
        attestations = new ArrayList<>();
        for (UUID id : attestationIdList) {
            I_AttestationAccess a = new AttestationAccess(getDataAccess()).retrieveInstance(id);
            attestations.add(a.getAsAttestation());
        }
    }
    ObjectVersionId precedingVersionId = null;
    // check if there is a preceding version and set it, if available
    if (version > 1) {
        // in the current scope version is an int and therefore: preceding = current - 1
        precedingVersionId = new ObjectVersionId(versionedObjectUid + "::" + getServerConfig().getNodename() + "::" + (version - 1));
    }
    Optional<CompositionDto> compositionDto = retrieve(versionedObjectUid, version);
    Composition composition = null;
    if (compositionDto.isPresent()) {
        composition = compositionDto.get().getComposition();
    }
    OriginalVersion<Composition> versionComposition = new OriginalVersion<>(versionId, precedingVersionId, composition, lifecycleState, commitAudit, contribution, null, null, attestations);
    return Optional.of(versionComposition);
}
Also used : OriginalVersion(com.nedap.archie.rm.changecontrol.OriginalVersion) Composition(com.nedap.archie.rm.composition.Composition) VersionedComposition(com.nedap.archie.rm.ehr.VersionedComposition) DvCodedText(com.nedap.archie.rm.datavalues.DvCodedText) CodePhrase(com.nedap.archie.rm.datatypes.CodePhrase) I_AttestationAccess(org.ehrbase.dao.access.interfaces.I_AttestationAccess) I_AttestationAccess(org.ehrbase.dao.access.interfaces.I_AttestationAccess) AttestationAccess(org.ehrbase.dao.access.jooq.AttestationAccess) ObjectVersionId(com.nedap.archie.rm.support.identification.ObjectVersionId) Attestation(com.nedap.archie.rm.generic.Attestation) ObjectNotFoundException(org.ehrbase.api.exception.ObjectNotFoundException) CompositionDto(org.ehrbase.response.ehrscape.CompositionDto) I_CompositionAccess(org.ehrbase.dao.access.interfaces.I_CompositionAccess) AuditDetails(com.nedap.archie.rm.generic.AuditDetails) ObjectRef(com.nedap.archie.rm.support.identification.ObjectRef) UUID(java.util.UUID) HierObjectId(com.nedap.archie.rm.support.identification.HierObjectId)

Example 3 with Composition

use of com.nedap.archie.rm.composition.Composition in project ehrbase by ehrbase.

the class ContributionServiceImp method processMetadataVersion.

/**
 * Helper to process versions from a contribution, which do not have the optional "data" attribute and therefore are called metadata versions.
 * @param ehrId ID of given EHR scope
 * @param contributionId Top level contribution this version is part of
 * @param version The version wrapper object
 */
private void processMetadataVersion(UUID ehrId, UUID contributionId, Version version) {
    // access audit and extract method, e.g. CREATION
    I_ConceptAccess.ContributionChangeType changeType = I_ConceptAccess.ContributionChangeType.valueOf(version.getCommitAudit().getChangeType().getValue().toUpperCase());
    switch(changeType) {
        case DELETED:
            // deleting an object without knowing which type it is requires checking of type, here with nested try-catch blocks
            UUID objectUid = getVersionedUidFromVersion(version);
            try {
                // throw exception to signal no matching composition was found
                CompositionDto compo = compositionService.retrieve(objectUid, null).orElseThrow(Exception::new);
                String actualPreceding = getAndCheckActualPreceding(version);
                compositionService.delete(ehrId, new ObjectVersionId(actualPreceding), contributionId);
            } catch (Exception e) {
                // given version ID is not of type composition - ignoring the exception because it is expected possible outcome
                try {
                // TODO-396: add folder handling
                } catch (Exception ee) {
                    // given version ID is not of type folder - ignoring the exception because it is expected possible outcome
                    // current end of going through supported types - last step is checking for EHR_STATUS and throwing specific error
                    ehrService.getEhrStatus(ehrId).ifPresent(st -> {
                        if (st.getUid().equals(version.getPrecedingVersionUid()))
                            throw new InvalidApiParameterException("Invalid change type. EHR_STATUS can't be deleted.");
                    });
                    // TODO: type is technically wrong, if more than one type gets tested
                    throw new ObjectNotFoundException(Composition.class.getName(), "Couldn't find object matching id: " + objectUid);
                }
            }
            break;
        // TODO
        case SYNTHESIS:
        // TODO
        case UNKNOWN:
        // not expected in a metadata version (i.e. without payload)
        case CREATION:
        // not expected in a metadata version (i.e. without payload)
        case MODIFICATION:
        // not expected in a metadata version (i.e. without payload)
        case AMENDMENT:
        default:
            throw new UnexpectedSwitchCaseException(changeType);
    }
}
Also used : Composition(com.nedap.archie.rm.composition.Composition) CompositionDto(org.ehrbase.response.ehrscape.CompositionDto) ObjectVersionId(com.nedap.archie.rm.support.identification.ObjectVersionId)

Example 4 with Composition

use of com.nedap.archie.rm.composition.Composition in project ehrbase by ehrbase.

the class EntryAccess method retrieveInstanceInCompositionVersion.

public static List<I_EntryAccess> retrieveInstanceInCompositionVersion(I_DomainAccess domainAccess, I_CompositionAccess compositionHistoryAccess, int version) {
    Result<EntryHistoryRecord> entryHistoryRecords = domainAccess.getContext().selectFrom(ENTRY_HISTORY).where(ENTRY_HISTORY.COMPOSITION_ID.eq(compositionHistoryAccess.getId())).and(ENTRY_HISTORY.SYS_TRANSACTION.eq(compositionHistoryAccess.getSysTransaction())).fetch();
    // build the list of parameters to recreate the composition
    Map<SystemValue, Object> values = new HashMap<>();
    values.put(SystemValue.COMPOSER, new PersistedPartyProxy(domainAccess).retrieve(compositionHistoryAccess.getComposerId()));
    EventContext context = I_ContextAccess.retrieveHistoricalEventContext(domainAccess, compositionHistoryAccess.getId(), compositionHistoryAccess.getSysTransaction());
    if (context == null) {
        // unchanged context use the current one!
        // also optional handling of context, because persistent compositions don't have a context
        compositionHistoryAccess.getContextId().ifPresent(uuid -> I_ContextAccess.retrieveInstance(domainAccess, uuid).mapRmEventContext());
    }
    values.put(SystemValue.CONTEXT, context);
    values.put(SystemValue.LANGUAGE, new CodePhrase(new TerminologyId("ISO_639-1"), compositionHistoryAccess.getLanguageCode()));
    String territory2letters = domainAccess.getContext().fetchOne(TERRITORY, TERRITORY.CODE.eq(compositionHistoryAccess.getTerritoryCode())).getTwoletter();
    values.put(SystemValue.TERRITORY, new CodePhrase(new TerminologyId("ISO_3166-1"), territory2letters));
    values.put(SystemValue.FEEDER_AUDIT, new FeederAuditEncoding().fromDB(compositionHistoryAccess.getFeederAudit()));
    List<I_EntryAccess> content = new ArrayList<>();
    try {
        EntryAccess entryAccess = new EntryAccess(domainAccess);
        for (EntryHistoryRecord record : entryHistoryRecords) {
            // set the record UID in the composition
            UUID compositionId = compositionHistoryAccess.getId();
            values.put(SystemValue.UID, new ObjectVersionId(compositionId.toString() + "::" + domainAccess.getServerConfig().getNodename() + "::" + version));
            entryAccess.entryRecord = domainAccess.getContext().newRecord(ENTRY);
            entryAccess.entryRecord.from(record);
            entryAccess.composition = new RawJson().unmarshal(record.getEntry().data(), Composition.class);
            setCompositionAttributes(entryAccess.composition, values);
            buildArchetypeDetails(entryAccess);
            content.add(entryAccess);
        }
    } catch (Exception e) {
        throw new IllegalArgumentException(DB_INCONSISTENCY + e);
    }
    return content;
}
Also used : TerminologyId(com.nedap.archie.rm.support.identification.TerminologyId) I_EntryAccess(org.ehrbase.dao.access.interfaces.I_EntryAccess) Composition(com.nedap.archie.rm.composition.Composition) CodePhrase(com.nedap.archie.rm.datatypes.CodePhrase) HashMap(java.util.HashMap) RawJson(org.ehrbase.serialisation.dbencoding.RawJson) EntryHistoryRecord(org.ehrbase.jooq.pg.tables.records.EntryHistoryRecord) ArrayList(java.util.ArrayList) ObjectVersionId(com.nedap.archie.rm.support.identification.ObjectVersionId) InternalServerException(org.ehrbase.api.exception.InternalServerException) PersistedPartyProxy(org.ehrbase.dao.access.jooq.party.PersistedPartyProxy) I_EntryAccess(org.ehrbase.dao.access.interfaces.I_EntryAccess) EventContext(com.nedap.archie.rm.composition.EventContext) FeederAuditEncoding(org.ehrbase.serialisation.dbencoding.rmobject.FeederAuditEncoding) UUID(java.util.UUID)

Example 5 with Composition

use of com.nedap.archie.rm.composition.Composition in project ehrbase by ehrbase.

the class OpenehrVersionedCompositionController method getOriginalVersionResponseDataResponseEntity.

private ResponseEntity<OriginalVersionResponseData<Composition>> getOriginalVersionResponseDataResponseEntity(String accept, UUID ehrId, UUID versionedObjectId, int version) {
    Optional<OriginalVersion<Composition>> compositionOriginalVersion = compositionService.getOriginalVersionComposition(versionedObjectId, version);
    UUID contributionId = compositionOriginalVersion.map(i -> UUID.fromString(i.getContribution().getId().getValue())).orElseThrow(() -> new InvalidApiParameterException("Couldn't retrieve Composition with given parameters"));
    Optional<ContributionDto> optionalContributionDto = contributionService.getContribution(ehrId, contributionId);
    // shouldn't happen
    ContributionDto contributionDto = optionalContributionDto.orElseThrow(() -> new InternalServerException("Couldn't fetch contribution for existing Composition"));
    OriginalVersionResponseData<Composition> originalVersionResponseData = new OriginalVersionResponseData<>(compositionOriginalVersion.orElseThrow(() -> new InternalServerException("Composition exists but can't be retrieved as Original Version.")), contributionDto);
    HttpHeaders respHeaders = new HttpHeaders();
    respHeaders.setContentType(resolveContentType(accept));
    return ResponseEntity.ok().headers(respHeaders).body(originalVersionResponseData);
}
Also used : OriginalVersion(com.nedap.archie.rm.changecontrol.OriginalVersion) PathVariable(org.springframework.web.bind.annotation.PathVariable) RequestParam(org.springframework.web.bind.annotation.RequestParam) ContributionService(org.ehrbase.api.service.ContributionService) Composition(com.nedap.archie.rm.composition.Composition) LocalDateTime(java.time.LocalDateTime) ObjectNotFoundException(org.ehrbase.api.exception.ObjectNotFoundException) Autowired(org.springframework.beans.factory.annotation.Autowired) RequestMapping(org.springframework.web.bind.annotation.RequestMapping) EhrService(org.ehrbase.api.service.EhrService) DateTimeFormat(org.springframework.format.annotation.DateTimeFormat) VersionedComposition(com.nedap.archie.rm.ehr.VersionedComposition) VersionedCompositionApiSpecification(org.ehrbase.rest.openehr.specification.VersionedCompositionApiSpecification) RevisionHistoryResponseData(org.ehrbase.response.openehr.RevisionHistoryResponseData) GetMapping(org.springframework.web.bind.annotation.GetMapping) ObjectVersionId(com.nedap.archie.rm.support.identification.ObjectVersionId) HttpHeaders(org.springframework.http.HttpHeaders) VersionedObjectResponseData(org.ehrbase.response.openehr.VersionedObjectResponseData) MediaType(org.springframework.http.MediaType) PostAuthorize(org.springframework.security.access.prepost.PostAuthorize) UUID(java.util.UUID) RestController(org.springframework.web.bind.annotation.RestController) BaseController(org.ehrbase.rest.BaseController) Objects(java.util.Objects) ContributionDto(org.ehrbase.response.ehrscape.ContributionDto) CompositionService(org.ehrbase.api.service.CompositionService) InternalServerException(org.ehrbase.api.exception.InternalServerException) InvalidApiParameterException(org.ehrbase.api.exception.InvalidApiParameterException) Optional(java.util.Optional) RevisionHistory(com.nedap.archie.rm.generic.RevisionHistory) ResponseEntity(org.springframework.http.ResponseEntity) RequestHeader(org.springframework.web.bind.annotation.RequestHeader) OriginalVersion(com.nedap.archie.rm.changecontrol.OriginalVersion) OriginalVersionResponseData(org.ehrbase.response.openehr.OriginalVersionResponseData) InvalidApiParameterException(org.ehrbase.api.exception.InvalidApiParameterException) HttpHeaders(org.springframework.http.HttpHeaders) Composition(com.nedap.archie.rm.composition.Composition) VersionedComposition(com.nedap.archie.rm.ehr.VersionedComposition) InternalServerException(org.ehrbase.api.exception.InternalServerException) ContributionDto(org.ehrbase.response.ehrscape.ContributionDto) UUID(java.util.UUID) OriginalVersionResponseData(org.ehrbase.response.openehr.OriginalVersionResponseData)

Aggregations

Composition (com.nedap.archie.rm.composition.Composition)138 Test (org.junit.Test)103 CanonicalJson (org.ehrbase.serialisation.jsonencoding.CanonicalJson)66 CompositionTestDataCanonicalJson (org.ehrbase.test_data.composition.CompositionTestDataCanonicalJson)53 LightRawJsonEncoder (org.ehrbase.serialisation.dbencoding.rawjson.LightRawJsonEncoder)30 TestDataTemplateProvider (org.ehrbase.client.templateprovider.TestDataTemplateProvider)29 RMDataFormat (org.ehrbase.serialisation.RMDataFormat)28 IOException (java.io.IOException)21 List (java.util.List)21 CoronaAnamneseComposition (org.ehrbase.client.classgenerator.examples.coronaanamnesecomposition.CoronaAnamneseComposition)20 Tuple (org.assertj.core.groups.Tuple)19 EhrbaseBloodPressureSimpleDeV0Composition (org.ehrbase.client.classgenerator.examples.ehrbasebloodpressuresimpledev0composition.EhrbaseBloodPressureSimpleDeV0Composition)19 StandardCharsets (java.nio.charset.StandardCharsets)18 IOUtils (org.apache.commons.io.IOUtils)18 Assertions.assertThat (org.assertj.core.api.Assertions.assertThat)18 EhrbaseMultiOccurrenceDeV1Composition (org.ehrbase.client.classgenerator.examples.ehrbasemultioccurrencedev1composition.EhrbaseMultiOccurrenceDeV1Composition)18 OPERATIONALTEMPLATE (org.openehr.schemas.v1.OPERATIONALTEMPLATE)18 EpisodeOfCareComposition (org.ehrbase.client.classgenerator.examples.episodeofcarecomposition.EpisodeOfCareComposition)17 CompositionTestDataCanonicalXML (org.ehrbase.test_data.composition.CompositionTestDataCanonicalXML)17 WebTemplate (org.ehrbase.webtemplate.model.WebTemplate)16