com.ibm.fhir.server.util.FHIROperationUtil Maven / Gradle / Ivy
/*
* (C) Copyright IBM Corp. 2016, 2021
*
* SPDX-License-Identifier: Apache-2.0
*/
package com.ibm.fhir.server.util;
import static com.ibm.fhir.model.type.String.string;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ibm.fhir.config.FHIRConfigHelper;
import com.ibm.fhir.config.FHIRConfiguration;
import com.ibm.fhir.exception.FHIROperationException;
import com.ibm.fhir.model.resource.OperationDefinition;
import com.ibm.fhir.model.resource.OperationOutcome;
import com.ibm.fhir.model.resource.OperationOutcome.Issue;
import com.ibm.fhir.model.resource.Parameters;
import com.ibm.fhir.model.resource.Parameters.Parameter;
import com.ibm.fhir.model.resource.Resource;
import com.ibm.fhir.model.type.Canonical;
import com.ibm.fhir.model.type.Code;
import com.ibm.fhir.model.type.Date;
import com.ibm.fhir.model.type.DateTime;
import com.ibm.fhir.model.type.Element;
import com.ibm.fhir.model.type.Id;
import com.ibm.fhir.model.type.Instant;
import com.ibm.fhir.model.type.Oid;
import com.ibm.fhir.model.type.PositiveInt;
import com.ibm.fhir.model.type.Time;
import com.ibm.fhir.model.type.UnsignedInt;
import com.ibm.fhir.model.type.Uri;
import com.ibm.fhir.model.type.Url;
import com.ibm.fhir.model.type.Uuid;
import com.ibm.fhir.model.type.code.FHIRAllTypes;
import com.ibm.fhir.model.type.code.IssueSeverity;
import com.ibm.fhir.model.type.code.IssueType;
import com.ibm.fhir.model.type.code.OperationParameterUse;
import com.ibm.fhir.model.util.FHIRUtil;
public final class FHIROperationUtil {
public static final String ENV_DISABLED_OPERATIONS = "DISABLED_OPERATIONS";
private static Set DISABLED_OPERATIONS = new HashSet<>();
private FHIROperationUtil() {
// No Operation
}
/**
* Initializes the FHIR Operation Utility so disallowedOperations are loaded one time.
* First, the code checks the environment operations.
* Second, the code checks the configuration.
* This is initialized one time for the system.
*/
public static void init() {
String operationStr = System.getenv(ENV_DISABLED_OPERATIONS);
if (operationStr != null) {
DISABLED_OPERATIONS.addAll(Arrays.asList(operationStr.split(",")));
}
// Check the Configuration and also add to the Set
operationStr = FHIRConfigHelper.getStringProperty(FHIRConfiguration.PROPERTY_DISABLED_OPERATIONS, null);
if (operationStr != null) {
DISABLED_OPERATIONS.addAll(Arrays.asList(operationStr.split(",")));
}
}
public static Parameters getInputParameters(OperationDefinition definition,
Map> queryParameters) throws FHIROperationException {
try {
Parameters.Builder parametersBuilder = Parameters.builder();
parametersBuilder.id("InputParameters");
if (definition != null) {
for (OperationDefinition.Parameter parameter : definition.getParameter()) {
if (OperationParameterUse.IN.getValue().equals(parameter.getUse().getValue())) {
String name = parameter.getName().getValue();
FHIRAllTypes type = parameter.getType();
if (type == null) {
continue;
}
String typeName = type.getValue();
List values = queryParameters.get(name);
if (values != null) {
String value = values.get(0);
Parameter.Builder parameterBuilder = Parameter.builder().name(string(name));
if ("boolean".equals(typeName)) {
parameterBuilder.value(com.ibm.fhir.model.type.Boolean.of(value));
} else if ("integer".equals(typeName)) {
parameterBuilder.value(com.ibm.fhir.model.type.Integer.of(value));
} else if ("string".equals(typeName)) {
parameterBuilder.value(com.ibm.fhir.model.type.String.of(value));
} else if ("decimal".equals(typeName)) {
parameterBuilder.value(com.ibm.fhir.model.type.Decimal.of(value));
} else if ("uri".equals(typeName)) {
parameterBuilder.value(Uri.of(value));
} else if ("url".equals(typeName)) {
parameterBuilder.value(Url.of(value));
} else if ("canonical".equals(typeName)) {
parameterBuilder.value(Canonical.of(value));
} else if ("instant".equals(typeName)) {
parameterBuilder.value(Instant.of(value));
} else if ("date".equals(typeName)) {
parameterBuilder.value(Date.of(value));
} else if ("dateTime".equals(typeName)) {
parameterBuilder.value(DateTime.of(value));
} else if ("time".equals(typeName)) {
parameterBuilder.value(Time.of(value));
} else if ("code".equals(typeName)) {
parameterBuilder.value(Code.of(value));
} else if ("oid".equals(typeName)) {
parameterBuilder.value(Oid.of(value));
} else if ("id".equals(typeName)) {
parameterBuilder.value(Id.of(value));
} else if ("unsignedInt".equals(typeName)) {
parameterBuilder.value(UnsignedInt.of(value));
} else if ("positiveInt".equals(typeName)) {
parameterBuilder.value(PositiveInt.of(value));
} else if ("uuid".equals(typeName)) {
parameterBuilder.value(Uuid.of(value));
} else {
// Originally returned 500 when it should be 400 (it's on the client).
FHIROperationException operationException =
new FHIROperationException("Query parameter '" + name + "' is an invalid type: '" + typeName + "'");
List issues = new ArrayList<>();
Issue.Builder builder = Issue.builder();
builder.code(IssueType.INVALID);
builder.diagnostics(string("Query parameter '" + name + "' is an invalid type: '" + typeName + "'"));
builder.severity(IssueSeverity.ERROR);
issues.add(builder.build());
operationException.setIssues(issues);
throw operationException;
}
parametersBuilder.parameter(parameterBuilder.build());
}
}
}
}
return parametersBuilder.build();
} catch (FHIROperationException e) {
throw e;
} catch (Exception e) {
// Originally returned 500 when it should be 400 (it's on the client).
FHIROperationException operationException =
new FHIROperationException("Unable to process query parameters", e);
List issues = new ArrayList<>();
Issue.Builder builder = Issue.builder();
builder.code(IssueType.INVALID);
builder.diagnostics(string("Unable to process query parameters"));
builder.severity(IssueSeverity.ERROR);
issues.add(builder.build());
operationException.setIssues(issues);
throw operationException;
}
}
public static Parameters getInputParameters(OperationDefinition definition, Resource resource)
throws Exception {
Parameters.Builder parametersBuilder = Parameters.builder();
parametersBuilder.id("InputParameters");
for (OperationDefinition.Parameter parameterDefinition : definition.getParameter()) {
if (parameterDefinition.getType() == null) {
continue;
}
String parameterTypeName = parameterDefinition.getType().getValue();
String resourceTypeName = resource.getClass().getSimpleName();
if ((resourceTypeName.equals(parameterTypeName) || "Resource".equals(parameterTypeName))
&& OperationParameterUse.IN.getValue().equals(parameterDefinition.getUse().getValue())) {
Parameter.Builder parameterBuilder =
Parameter.builder().name(string(parameterDefinition.getName().getValue()));
parametersBuilder.parameter(parameterBuilder.resource(resource).build());
}
}
return parametersBuilder.build();
}
/**
* Generates an output Parameter resource
* @param resource
* @return
*/
public static Parameters getOutputParameters(Resource resource) {
return getOutputParameters("return", resource);
}
/**
* generates an output parameter with a specific name.
*
* @param name
* @param resource
* @return
*/
public static Parameters getOutputParameters(String name, Resource resource) {
return Parameters.builder()
.parameter(Parameter.builder()
.name(string(name))
.resource(resource)
.build())
.build();
}
/**
* Generates an output parameters, with a parameter for a specified element.
* @param name the parameter name
* @param element the element, or null
* @return output parameters
*/
public static Parameters getOutputParameters(String name, Element element) {
Parameters.Builder builder = Parameters.builder();
if (element != null) {
builder.parameter(Parameter.builder()
.name(string(name))
.value(element)
.build());
}
return builder.build();
}
public static boolean hasSingleResourceOutputParameter(Parameters parameters) {
if (parameters == null) {
return false;
}
return parameters.getParameter().size() == 1 && parameters.getParameter().get(0).getResource() != null;
}
public static Resource getSingleResourceOutputParameter(Parameters parameters) throws Exception {
return parameters.getParameter().get(0).getResource();
}
/**
* check and verify operation allowed
* @param operationName
* @throws FHIROperationException
*/
public static void checkAndVerifyOperationAllowed(String operationName) throws FHIROperationException {
if (DISABLED_OPERATIONS.contains(operationName)) {
throw generateForbiddenOperationException(operationName);
}
}
public static FHIROperationException generateForbiddenOperationException(String operationName) {
FHIROperationException operationException =
new FHIROperationException("Access to the operation is forbidden");
List issues = new ArrayList<>();
Issue.Builder builder = Issue.builder();
builder.code(IssueType.FORBIDDEN);
builder.diagnostics(string("Access to the operation is forbidden - '$" + operationName +"'"));
builder.severity(IssueSeverity.ERROR);
issues.add(builder.build());
operationException.setIssues(issues);
return operationException;
}
/**
* Helper method to generate a FHIROperationException with a fixed IssueType
* @param msg the message to be packed in the exception
* @param issueType the type of the issue
* @return
*/
public static FHIROperationException buildExceptionWithIssue(final String msg, IssueType issueType) {
return buildExceptionWithIssue(msg, issueType, null);
}
/**
* Helper method to generate a FHIROperationException with a fixed IssueType
* @param msg the message to be packed in the exception
* @param issueType the type of the issue
* @param cause the throwable that causes this OperationOutcome/Exception
* @return
*/
public static FHIROperationException buildExceptionWithIssue(final String msg, IssueType issueType, final Throwable cause) {
OperationOutcome.Issue ooi = FHIRUtil.buildOperationOutcomeIssue(msg, issueType);
return new FHIROperationException(msg, cause).withIssue(ooi);
}
}