
dev.dsf.fhir.dao.command.ReferencesHelperImpl Maven / Gradle / Ivy
package dev.dsf.fhir.dao.command;
import java.sql.Connection;
import java.util.Map;
import java.util.Optional;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.hl7.fhir.r4.model.Attachment;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.RelatedArtifact;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.Type;
import dev.dsf.common.auth.conf.Identity;
import dev.dsf.fhir.help.ResponseGenerator;
import dev.dsf.fhir.service.ReferenceExtractor;
import dev.dsf.fhir.service.ReferenceResolver;
import dev.dsf.fhir.service.ResourceReference;
import dev.dsf.fhir.service.ResourceReference.ReferenceType;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.Response.Status;
public final class ReferencesHelperImpl implements ReferencesHelper
{
private final int index;
private final Identity identity;
private final R resource;
private final String serverBase;
private final ReferenceExtractor referenceExtractor;
private final ReferenceResolver referenceResolver;
private final ResponseGenerator responseGenerator;
public ReferencesHelperImpl(int index, Identity identity, R resource, String serverBase,
ReferenceExtractor referenceExtractor, ReferenceResolver referenceResolver,
ResponseGenerator responseGenerator)
{
this.index = index;
this.identity = identity;
this.resource = resource;
this.serverBase = serverBase;
this.referenceExtractor = referenceExtractor;
this.referenceResolver = referenceResolver;
this.responseGenerator = responseGenerator;
}
@Override
public void resolveTemporaryAndConditionalReferencesOrLiteralInternalRelatedArtifactOrAttachmentUrls(
Map idTranslationTable, Connection connection) throws WebApplicationException
{
referenceExtractor.getReferences(resource)
.filter(ref -> referenceResolver.referenceCanBeResolved(ref, connection)).forEach(ref ->
{
Optional outcome = resolveTemporaryOrConditionalReferenceOrLiteralInternalRelatedArtifactOrAttachmentUrl(
ref, idTranslationTable, connection);
if (outcome.isPresent())
{
Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build();
throw new WebApplicationException(response);
}
});
}
private Optional resolveTemporaryOrConditionalReferenceOrLiteralInternalRelatedArtifactOrAttachmentUrl(
ResourceReference reference, Map idTranslationTable, Connection connection)
{
return switch (reference.getType(serverBase))
{
case TEMPORARY -> resolveTemporary(reference, idTranslationTable, reference.getReference()::getReference,
reference.getReference()::setReferenceElement);
case RELATED_ARTEFACT_TEMPORARY_URL -> resolveTemporary(reference, idTranslationTable,
reference.getRelatedArtifact()::getUrl, newIdToAbsoluteUrl(reference.getRelatedArtifact()::setUrl));
case ATTACHMENT_TEMPORARY_URL -> resolveTemporary(reference, idTranslationTable,
reference.getAttachment()::getUrl, newIdToAbsoluteUrl(reference.getAttachment()::setUrl));
case CONDITIONAL ->
resolveConditional(reference, connection, target -> reference.getReference().setReferenceElement(
new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())));
case RELATED_ARTEFACT_CONDITIONAL_URL ->
resolveConditional(reference, connection, targetToAbsoluteUrl(reference.getRelatedArtifact()::setUrl));
case ATTACHMENT_CONDITIONAL_URL ->
resolveConditional(reference, connection, targetToAbsoluteUrl(reference.getAttachment()::setUrl));
case RELATED_ARTEFACT_LITERAL_INTERNAL_URL -> resolveLiteralInternalUrl(reference::getRelatedArtifact,
RelatedArtifact::getUrl, RelatedArtifact::setUrl);
case ATTACHMENT_LITERAL_INTERNAL_URL ->
resolveLiteralInternalUrl(reference::getAttachment, Attachment::getUrl, Attachment::setUrl);
default -> Optional.empty();
};
}
private Consumer newIdToAbsoluteUrl(Consumer absoluteUrlConsumer)
{
return newId ->
{
String absoluteUrl = newId.withServerBase(serverBase, newId.getResourceType()).getValue();
absoluteUrlConsumer.accept(absoluteUrl);
};
}
private Consumer targetToAbsoluteUrl(Consumer absoluteUrlConsumer)
{
return target ->
{
IdType newId = new IdType(target.getResourceType().name(), target.getIdElement().getIdPart());
String absoluteUrl = newId.withServerBase(serverBase, newId.getResourceType()).getValue();
absoluteUrlConsumer.accept(absoluteUrl);
};
}
private Optional resolveTemporary(ResourceReference reference,
Map idTranslationTable, Supplier temporaryIdSupplier,
Consumer newIdConsumer)
{
IdType newId = idTranslationTable.get(temporaryIdSupplier.get());
if (newId != null)
{
newIdConsumer.accept(newId);
return Optional.empty();
}
else
return Optional.of(responseGenerator.unknownReference(resource, reference, index));
}
private Optional resolveConditional(ResourceReference reference, Connection connection,
Consumer targetConsumer)
{
Optional resolvedResource = referenceResolver.resolveReference(identity, reference, connection);
if (resolvedResource.isPresent())
{
Resource target = resolvedResource.get();
targetConsumer.accept(target);
return Optional.empty();
}
else
return Optional.of(responseGenerator.referenceTargetNotFoundLocallyByCondition(index, resource, reference));
}
private Optional resolveLiteralInternalUrl(Supplier element,
Function oldUrlValue, BiConsumer newAbsoluteUrlConsumer)
{
T type = element.get();
if (type != null)
{
IdType newId = new IdType(oldUrlValue.apply(type));
String absoluteUrl = newId.withServerBase(serverBase, newId.getResourceType()).getValue();
newAbsoluteUrlConsumer.accept(type, absoluteUrl);
return Optional.empty();
}
return Optional.empty();
}
@Override
public void resolveLogicalReferences(Connection connection) throws WebApplicationException
{
referenceExtractor.getReferences(resource).filter(ref -> ReferenceType.LOGICAL.equals(ref.getType(serverBase)))
.filter(ref -> referenceResolver.referenceCanBeResolved(ref, connection)).forEach(ref ->
{
Optional outcome = resolveLogicalReference(ref, connection);
if (outcome.isPresent())
{
Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build();
throw new WebApplicationException(response);
}
});
}
private Optional resolveLogicalReference(ResourceReference reference, Connection connection)
{
Optional resolvedResource = referenceResolver.resolveReference(identity, reference, connection);
if (resolvedResource.isPresent())
{
Resource target = resolvedResource.get();
reference.getReference().setReferenceElement(
new IdType(target.getResourceType().name(), target.getIdElement().getIdPart()));
return Optional.empty();
}
else
return Optional
.of(responseGenerator.referenceTargetNotFoundLocallyByIdentifier(index, resource, reference));
}
@Override
public void checkReferences(Map idTranslationTable, Connection connection,
Predicate checkReference) throws WebApplicationException
{
referenceExtractor.getReferences(resource).filter(checkReference)
.filter(ref -> referenceResolver.referenceCanBeChecked(ref, connection)).forEach(ref ->
{
Optional outcome = checkReference(ref, connection);
if (outcome.isPresent())
{
Response response = Response.status(Status.FORBIDDEN).entity(outcome.get()).build();
throw new WebApplicationException(response);
}
});
}
private Optional checkReference(ResourceReference reference, Connection connection)
throws WebApplicationException
{
return switch (reference.getType(serverBase))
{
case LITERAL_INTERNAL, RELATED_ARTEFACT_LITERAL_INTERNAL_URL, ATTACHMENT_LITERAL_INTERNAL_URL ->
referenceResolver.checkLiteralInternalReference(resource, reference, connection, index);
case LITERAL_EXTERNAL, RELATED_ARTEFACT_LITERAL_EXTERNAL_URL, ATTACHMENT_LITERAL_EXTERNAL_URL ->
referenceResolver.checkLiteralExternalReference(resource, reference, index);
case LOGICAL -> referenceResolver.checkLogicalReference(identity, resource, reference, connection, index);
// unknown URLs to non FHIR servers in related artifacts must not be checked
case RELATED_ARTEFACT_UNKNOWN_URL, ATTACHMENT_UNKNOWN_URL -> Optional.empty();
case UNKNOWN -> Optional.of(responseGenerator.unknownReference(resource, reference, index));
default -> Optional.of(responseGenerator.unknownReference(resource, reference, index));
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy