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");
}
}
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);
}
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);
}
}
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;
}
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);
}
Aggregations