
dev.dsf.fhir.help.ParameterConverter Maven / Gradle / Ivy
package dev.dsf.fhir.help;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ca.uhn.fhir.rest.api.Constants;
import dev.dsf.fhir.adapter.AbstractAdapter;
import dev.dsf.fhir.prefer.PreferHandlingType;
import dev.dsf.fhir.prefer.PreferReturnType;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.EntityTag;
import jakarta.ws.rs.core.HttpHeaders;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response.Status;
import jakarta.ws.rs.core.UriInfo;
import jakarta.ws.rs.ext.RuntimeDelegate;
public class ParameterConverter
{
private static final Logger logger = LoggerFactory.getLogger(ParameterConverter.class);
public static final String HTML_FORMAT = "html";
public static final String JSON_FORMAT = "json";
public static final List JSON_FORMATS = List.of(Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON_NEW,
MediaType.APPLICATION_JSON);
public static final String XML_FORMAT = "xml";
public static final List XML_FORMATS = List.of(Constants.CT_FHIR_XML, Constants.CT_FHIR_XML_NEW,
MediaType.APPLICATION_XML, MediaType.TEXT_XML);
private final ExceptionHandler exceptionHandler;
public ParameterConverter(ExceptionHandler exceptionHandler)
{
this.exceptionHandler = exceptionHandler;
}
/**
* @param resourceTypeName
* not null
, will be part of the {@link WebApplicationException} if the given id can't be
* parsed (aka is not a {@link UUID})
* @param id
* may be null
* @return null
if the given id is null
*/
public UUID toUuid(String resourceTypeName, String id)
{
if (id == null)
return null;
return toUuid(id).orElseThrow(() -> exceptionHandler.notFound(resourceTypeName));
}
/**
* @param id
* may be null
* @return {@link Optional#empty()} if the given id is null
or is not a {@link UUID}
*/
public Optional toUuid(String id)
{
if (id == null)
return Optional.empty();
// TODO control flow by exception
try
{
return Optional.of(UUID.fromString(id));
}
catch (IllegalArgumentException e)
{
return Optional.empty();
}
}
public MediaType getMediaTypeThrowIfNotSupported(UriInfo uri, HttpHeaders headers) throws WebApplicationException
{
return getMediaTypeIfSupported(uri, headers).orElseThrow(() ->
{
logger.warn("Media type not supported");
return new WebApplicationException(Status.UNSUPPORTED_MEDIA_TYPE);
});
}
public Optional getMediaTypeIfSupported(UriInfo uri, HttpHeaders headers)
{
String format = uri.getQueryParameters().getFirst("_format");
boolean pretty = "true".equals(uri.getQueryParameters().getFirst("_pretty"));
SummaryMode summaryMode = SummaryMode.fromString(uri.getQueryParameters().getFirst("_summary"));
String accept = headers.getHeaderString(HttpHeaders.ACCEPT);
if (format == null || format.isBlank())
return getMediaType(accept, pretty, summaryMode);
else if (XML_FORMATS.contains(format) || JSON_FORMATS.contains(format) || MediaType.TEXT_HTML.equals(format))
return getMediaType(format, pretty, summaryMode);
else if (XML_FORMAT.equals(format))
return Optional.of(mediaType("application", "fhir+xml", pretty, summaryMode));
else if (JSON_FORMAT.equals(format))
return Optional.of(mediaType("application", "fhir+json", pretty, summaryMode));
else if (HTML_FORMAT.equals(format))
return Optional.of(mediaType("text", "html", pretty, summaryMode));
else
return Optional.empty();
}
private Optional getMediaType(String mediaType, boolean pretty, SummaryMode summaryMode)
{
if (mediaType == null || mediaType.isBlank())
mediaType = MediaType.WILDCARD;
if (mediaType.contains(MediaType.TEXT_HTML))
return Optional.of(mediaType("text", "html", pretty, summaryMode));
else if (mediaType.contains(Constants.CT_FHIR_JSON_NEW))
return Optional.of(mediaType("application", "fhir+json", pretty, summaryMode));
else if (mediaType.contains(Constants.CT_FHIR_JSON))
return Optional.of(mediaType("application", "json+fhir", pretty, summaryMode));
else if (mediaType.contains(MediaType.APPLICATION_JSON))
return Optional.of(mediaType("application", "json", pretty, summaryMode));
else if (mediaType.contains(Constants.CT_FHIR_XML_NEW))
return Optional.of(mediaType("application", "fhir+xml", pretty, summaryMode));
else if (mediaType.contains(Constants.CT_FHIR_XML))
return Optional.of(mediaType("application", "xml+fhir", pretty, summaryMode));
else if (mediaType.contains(MediaType.APPLICATION_XML))
return Optional.of(mediaType("application", "xml", pretty, summaryMode));
else if (mediaType.contains(MediaType.TEXT_XML))
return Optional.of(mediaType("text", "xml", pretty, summaryMode));
else if (mediaType.contains(MediaType.WILDCARD))
return Optional.of(mediaType("application", "fhir+xml", pretty, summaryMode));
else
return Optional.empty();
}
private MediaType mediaType(String type, String subtype, boolean pretty, SummaryMode summaryMode)
{
Map parameters = new HashMap<>();
if (pretty)
parameters.put(AbstractAdapter.PRETTY, "true");
if (summaryMode != null)
parameters.put(AbstractAdapter.SUMMARY, summaryMode.toString());
return new MediaType(type, subtype, parameters);
}
public PreferReturnType getPreferReturn(HttpHeaders headers)
{
List preferHeaders = headers.getRequestHeader(Constants.HEADER_PREFER);
if (preferHeaders == null)
return PreferReturnType.REPRESENTATION;
else
return preferHeaders.stream().map(PreferReturnType::fromString).findFirst()
.orElse(PreferReturnType.REPRESENTATION);
}
public PreferHandlingType getPreferHandling(HttpHeaders headers)
{
List preferHeaders = headers.getRequestHeader(Constants.HEADER_PREFER);
if (preferHeaders == null)
return PreferHandlingType.LENIENT;
else
return preferHeaders.stream().map(PreferHandlingType::fromString).findFirst()
.orElse(PreferHandlingType.LENIENT);
}
public Integer getFirstInt(Map> queryParameters, String key)
{
List listForKey = queryParameters.getOrDefault(key, Collections.emptyList());
if (listForKey.isEmpty())
return null;
else
{
// TODO control flow by exception
try
{
return Integer.valueOf(listForKey.get(0));
}
catch (NumberFormatException e)
{
return null;
}
}
}
/**
* URL-decodes all query-parameter values
*
* @param queryParameters
* not null
* @return {@link Map} containing the supplied query-parameters in URL-decoded form
*/
public Map> urlDecodeQueryParameters(Map> queryParameters)
{
Map> cleaned = new LinkedHashMap<>((int) (queryParameters.size() / 0.75) + 1);
for (Entry> entry : queryParameters.entrySet())
cleaned.put(entry.getKey(), urlDecodeQueryParameter(entry.getValue()));
return cleaned;
}
private List urlDecodeQueryParameter(List queryParameterValues)
{
return queryParameterValues.stream().map(v -> URLDecoder.decode(v, StandardCharsets.UTF_8))
.collect(Collectors.toList());
}
/**
* @param eTagValue
* ETag string value
* @return {@link Optional} of {@link EntityTag} for the given value or {@link Optional#empty()} if the given value
* could not be parsed or was null/blank
*/
public Optional toEntityTag(String eTagValue)
{
if (eTagValue == null || eTagValue.isBlank())
return Optional.empty();
try
{
EntityTag eTag = RuntimeDelegate.getInstance().createHeaderDelegate(EntityTag.class).fromString(eTagValue);
if (eTag.isWeak())
return Optional.of(eTag);
else
{
logger.warn("{} not a weak ETag", eTag.getValue());
return Optional.empty();
}
}
catch (IllegalArgumentException e)
{
logger.debug("Unable to parse ETag value", e);
logger.warn("Unable to parse ETag value: {} - {}", e.getClass().getName(), e.getMessage());
return Optional.empty();
}
}
/**
* @param tag
* may be null
* @return {@link Optional} long version for the given tag or {@link Optional#empty()} if the given tags value could
* not be parsed as long or was null/blank
*/
public Optional toVersion(EntityTag tag)
{
if (tag == null || tag.getValue() == null || tag.getValue().isBlank())
return Optional.empty();
return toVersion(tag.getValue());
}
/**
* @param version
* may be null
* @return {@link Optional} long version for the given {@link String} value or {@link Optional#empty()} if the given
* {@link String} value could not be parsed as long or was null/blank
*/
public Optional toVersion(String version)
{
if (version == null || version.isBlank())
return Optional.empty();
try
{
return Optional.of(Long.parseLong(version));
}
catch (NumberFormatException e)
{
logger.debug("Version not a Long value", e);
logger.warn("Version not a Long value: {} - {}", e.getClass().getName(), e.getMessage());
return Optional.empty();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy