Merge remote-tracking branch 'origin/master' into consent_service_resource_filtering_leads_to_empty_pages_with_next_link

This commit is contained in:
peartree 2023-12-15 10:40:23 -05:00
commit bdf831e803
1820 changed files with 54208 additions and 38960 deletions

View File

@ -25,7 +25,7 @@ jobs:
if: ${{ github.event_name == 'pull_request' }}
- name: Setup java
uses: actions/setup-java@v2
uses: actions/setup-java@v3
with:
distribution: zulu
java-version: 17

View File

@ -13,9 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.net.*;
import java.io.*;
import java.nio.channels.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Properties;
public class MavenWrapperDownloader {

View File

@ -4,7 +4,7 @@
repos:
- repo: https://github.com/ejba/pre-commit-maven
rev: v0.3.3
rev: v0.3.4
hooks:
- id: maven-spotless-apply
stages: [pre-push]

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -45,7 +45,6 @@
<checkRuntimeClasspath>false</checkRuntimeClasspath>
<checkTestClasspath>false</checkTestClasspath>
<skip>false</skip>
<quiet>false</quiet>
<preferLocal>true</preferLocal>
<useResultFile>true</useResultFile>
<resultFileMinClasspathCount>2</resultFileMinClasspathCount>
@ -103,14 +102,6 @@
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
</ignoredDependencies>
<ignoredResourcePatterns>
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -131,12 +131,6 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<classFolders>
<classFolder>${basedir}/target/classes</classFolder>
</classFolders>
<sourceFolders>
<sourceFolder>${basedir}/src/main/java</sourceFolder>
</sourceFolders>
<dumpOnExit>true</dumpOnExit>
</configuration>
<executions>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -52,19 +52,13 @@
<!-- Only required for Schematron Validator Support -->
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-schematron</artifactId>
<groupId>com.helger.schematron</groupId>
<artifactId>ph-schematron-api</artifactId>
<optional>true</optional>
<exclusions>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-commons</artifactId>
<groupId>com.helger.schematron</groupId>
<artifactId>ph-schematron-xslt</artifactId>
<optional>true</optional>
</dependency>
@ -122,10 +116,16 @@
</dependency>
<!-- @Nonnull annotation -->
<!-- We need to leave this in because otherwise hapi-fhir-structures-dstu3: will fail to generate javadoc -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
@ -221,7 +221,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${maven_checkstyle_version}</version>
<configuration>
<!--suppress UnresolvedMavenProperty -->
<configLocation>${maven.multiModuleProjectDirectory}/hapi-fhir-checkstyle/src/checkstyle/hapi-base-checkstyle.xml</configLocation>

View File

@ -20,6 +20,7 @@
package ca.uhn.fhir.context;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.model.api.annotation.Child;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseReference;
@ -78,6 +79,10 @@ public abstract class BaseRuntimeChildDefinition {
this.myReplacedParentDefinition = myReplacedParentDefinition;
}
public boolean isMultipleCardinality() {
return this.getMax() > 1 || this.getMax() == Child.MAX_UNLIMITED;
}
public interface IAccessor {
List<IBase> getValues(IBase theTarget);

View File

@ -21,6 +21,8 @@ package ca.uhn.fhir.context;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.util.UrlUtil;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
@ -31,8 +33,6 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class BaseRuntimeElementDefinition<T extends IBase> {

View File

@ -49,6 +49,8 @@ import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.VersionUtil;
import ca.uhn.fhir.validation.FhirValidator;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.jena.riot.Lang;
@ -77,8 +79,6 @@ import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* The FHIR context is the central starting point for the use of the HAPI FHIR API. It should be created once, and then

View File

@ -38,6 +38,7 @@ import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.util.ReflectionUtil;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
@ -67,7 +68,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import javax.annotation.Nonnull;
import static org.apache.commons.lang3.StringUtils.isBlank;
@ -498,7 +498,7 @@ class ModelScanner {
nextElementType = ReflectionUtil.getGenericCollectionTypeOfField(next);
} else if (Collection.class.isAssignableFrom(nextElementType)) {
throw new ConfigurationException(Msg.code(1722) + "Field '" + next.getName() + "' in type '"
+ next.getClass().getCanonicalName()
+ nextElementType.getCanonicalName()
+ "' is a Collection - Only java.util.List curently supported");
}
return nextElementType;

View File

@ -21,6 +21,8 @@ package ca.uhn.fhir.context;
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
@ -37,8 +39,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.trim;

View File

@ -23,6 +23,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.util.ILockable;
import ca.uhn.fhir.util.ReflectionUtil;
import jakarta.annotation.Nullable;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -32,7 +33,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
/**
* This class returns the vocabulary that is shipped with the base FHIR
@ -99,6 +99,11 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
}
}
@Override
public String getName() {
return myCtx.getVersion().getVersion() + " FHIR Standard Profile Validation Support";
}
@Override
public List<IBaseResource> fetchAllConformanceResources() {
return myDelegate.fetchAllConformanceResources();

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.parser.LenientErrorHandler;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.ClasspathUtil;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -43,7 +44,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -24,9 +24,12 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.UrlUtil;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseParameters;
@ -41,8 +44,6 @@ import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -294,8 +295,8 @@ public interface IValidationSupport {
*/
@Nullable
default CodeValidationResult validateCode(
@Nonnull ValidationSupportContext theValidationSupportContext,
@Nonnull ConceptValidationOptions theOptions,
ValidationSupportContext theValidationSupportContext,
ConceptValidationOptions theOptions,
String theCodeSystem,
String theCode,
String theDisplay,
@ -328,14 +329,16 @@ public interface IValidationSupport {
}
/**
* Look up a code using the system and code value
* Look up a code using the system and code value.
* @deprecated This method has been deprecated in HAPI FHIR 7.0.0. Use {@link IValidationSupport#lookupCode(ValidationSupportContext, LookupCodeRequest)} instead.
*
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
* @param theSystem The CodeSystem URL
* @param theCode The code
* @param theDisplayLanguage to filter out the designation by the display language. To return all designation, set this value to <code>null</code>.
* @param theDisplayLanguage Used to filter out the designation by the display language. To return all designation, set this value to <code>null</code>.
*/
@Deprecated
@Nullable
default LookupCodeResult lookupCode(
ValidationSupportContext theValidationSupportContext,
@ -347,12 +350,14 @@ public interface IValidationSupport {
/**
* Look up a code using the system and code value
* @deprecated This method has been deprecated in HAPI FHIR 7.0.0. Use {@link IValidationSupport#lookupCode(ValidationSupportContext, LookupCodeRequest)} instead.
*
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
* @param theSystem The CodeSystem URL
* @param theCode The code
*/
@Deprecated
@Nullable
default LookupCodeResult lookupCode(
ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) {
@ -360,7 +365,26 @@ public interface IValidationSupport {
}
/**
* Returns <code>true</code> if the given valueset can be validated by the given
* Look up a code using the system, code and other parameters captured in {@link LookupCodeRequest}.
* @since 7.0.0
*
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
* other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter.
* @param theLookupCodeRequest The parameters used to perform the lookup, including system and code.
*/
@Nullable
default LookupCodeResult lookupCode(
ValidationSupportContext theValidationSupportContext, @Nonnull LookupCodeRequest theLookupCodeRequest) {
// TODO: can change to return null once the deprecated methods are removed
return lookupCode(
theValidationSupportContext,
theLookupCodeRequest.getSystem(),
theLookupCodeRequest.getCode(),
theLookupCodeRequest.getDisplayLanguage());
}
/**
* Returns <code>true</code> if the given ValueSet can be validated by the given
* validation support module
*
* @param theValidationSupportContext The validation support module will be passed in to this method. This is convenient in cases where the operation needs to make calls to
@ -409,6 +433,13 @@ public interface IValidationSupport {
return null;
}
/**
* This field is used by the Terminology Troubleshooting Log to log which validation support module was used for the operation being logged.
*/
default String getName() {
return "Unknown " + getFhirContext().getVersion().getVersion() + " Validation Support";
}
enum IssueSeverity {
/**
* The issue caused the action to fail, and no further checking could be performed.
@ -495,8 +526,13 @@ public interface IValidationSupport {
public String getPropertyName() {
return myPropertyName;
}
public abstract String getType();
}
String TYPE_STRING = "string";
String TYPE_CODING = "Coding";
class StringConceptProperty extends BaseConceptProperty {
private final String myValue;
@ -513,6 +549,10 @@ public interface IValidationSupport {
public String getValue() {
return myValue;
}
public String getType() {
return TYPE_STRING;
}
}
class CodingConceptProperty extends BaseConceptProperty {
@ -543,9 +583,18 @@ public interface IValidationSupport {
public String getDisplay() {
return myDisplay;
}
public String getType() {
return TYPE_CODING;
}
}
class CodeValidationResult {
public static final String SOURCE_DETAILS = "sourceDetails";
public static final String RESULT = "result";
public static final String MESSAGE = "message";
public static final String DISPLAY = "display";
private String myCode;
private String myMessage;
private IssueSeverity mySeverity;
@ -674,6 +723,23 @@ public interface IValidationSupport {
setSeverity(IssueSeverity.valueOf(theIssueSeverity.toUpperCase()));
return this;
}
public IBaseParameters toParameters(FhirContext theContext) {
IBaseParameters retVal = ParametersUtil.newInstance(theContext);
ParametersUtil.addParameterToParametersBoolean(theContext, retVal, RESULT, isOk());
if (isNotBlank(getMessage())) {
ParametersUtil.addParameterToParametersString(theContext, retVal, MESSAGE, getMessage());
}
if (isNotBlank(getDisplay())) {
ParametersUtil.addParameterToParametersString(theContext, retVal, DISPLAY, getDisplay());
}
if (isNotBlank(getSourceDetails())) {
ParametersUtil.addParameterToParametersString(theContext, retVal, SOURCE_DETAILS, getSourceDetails());
}
return retVal;
}
}
class ValueSetExpansionOutcome {
@ -806,7 +872,7 @@ public interface IValidationSupport {
}
public IBaseParameters toParameters(
FhirContext theContext, List<? extends IPrimitiveType<String>> theProperties) {
FhirContext theContext, List<? extends IPrimitiveType<String>> thePropertyNames) {
IBaseParameters retVal = ParametersUtil.newInstance(theContext);
if (isNotBlank(getCodeSystemDisplayName())) {
@ -821,32 +887,42 @@ public interface IValidationSupport {
if (myProperties != null) {
Set<String> properties = Collections.emptySet();
if (theProperties != null) {
properties = theProperties.stream()
if (thePropertyNames != null) {
properties = thePropertyNames.stream()
.map(IPrimitiveType::getValueAsString)
.collect(Collectors.toSet());
}
for (BaseConceptProperty next : myProperties) {
String propertyName = next.getPropertyName();
if (!properties.isEmpty()) {
if (!properties.contains(next.getPropertyName())) {
if (!properties.isEmpty() && !properties.contains(propertyName)) {
continue;
}
}
IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "property");
ParametersUtil.addPartCode(theContext, property, "code", next.getPropertyName());
ParametersUtil.addPartCode(theContext, property, "code", propertyName);
if (next instanceof StringConceptProperty) {
StringConceptProperty prop = (StringConceptProperty) next;
ParametersUtil.addPartString(theContext, property, "value", prop.getValue());
} else if (next instanceof CodingConceptProperty) {
CodingConceptProperty prop = (CodingConceptProperty) next;
String propertyType = next.getType();
switch (propertyType) {
case TYPE_STRING:
StringConceptProperty stringConceptProperty = (StringConceptProperty) next;
ParametersUtil.addPartString(
theContext, property, "value", stringConceptProperty.getValue());
break;
case TYPE_CODING:
CodingConceptProperty codingConceptProperty = (CodingConceptProperty) next;
ParametersUtil.addPartCoding(
theContext, property, "value", prop.getCodeSystem(), prop.getCode(), prop.getDisplay());
} else {
throw new IllegalStateException(Msg.code(1739) + "Don't know how to handle " + next.getClass());
theContext,
property,
"value",
codingConceptProperty.getCodeSystem(),
codingConceptProperty.getCode(),
codingConceptProperty.getDisplay());
break;
default:
throw new IllegalStateException(
Msg.code(1739) + "Don't know how to handle " + next.getClass());
}
}
}
@ -990,6 +1066,16 @@ public interface IValidationSupport {
public boolean isReverse() {
return myReverse;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("sourceValueSetUrl", mySourceValueSetUrl)
.append("targetSystemUrl", myTargetSystemUrl)
.append("targetValueSetUrl", myTargetValueSetUrl)
.append("reverse", myReverse)
.toString();
}
}
/**

View File

@ -0,0 +1,75 @@
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.context.support;
import java.util.Collection;
import java.util.Collections;
/**
* Represents parameters which can be passed to the $lookup operation for codes.
* @since 7.0.0
*/
public class LookupCodeRequest {
private final String mySystem;
private final String myCode;
private String myDisplayLanguage;
private Collection<String> myPropertyNames;
/**
* @param theSystem The CodeSystem URL
* @param theCode The code
*/
public LookupCodeRequest(String theSystem, String theCode) {
mySystem = theSystem;
myCode = theCode;
}
/**
* @param theSystem The CodeSystem URL
* @param theCode The code
* @param theDisplayLanguage Used to filter out the designation by the display language. To return all designation, set this value to <code>null</code>.
* @param thePropertyNames The collection of properties to be returned in the output. If no properties are specified, the implementor chooses what to return.
*/
public LookupCodeRequest(
String theSystem, String theCode, String theDisplayLanguage, Collection<String> thePropertyNames) {
this(theSystem, theCode);
myDisplayLanguage = theDisplayLanguage;
myPropertyNames = thePropertyNames;
}
public String getSystem() {
return mySystem;
}
public String getCode() {
return myCode;
}
public String getDisplayLanguage() {
return myDisplayLanguage;
}
public Collection<String> getPropertyNames() {
if (myPropertyNames == null) {
return Collections.emptyList();
}
return myPropertyNames;
}
}

View File

@ -19,11 +19,11 @@
*/
package ca.uhn.fhir.fhirpath;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBase;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
public interface IFhirPath {

View File

@ -19,12 +19,11 @@
*/
package ca.uhn.fhir.fhirpath;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IIdType;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public interface IFhirPathEvaluationContext {
/**

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.interceptor.api;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.Validate;
import java.util.Collection;
@ -29,7 +30,6 @@ import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
public class HookParams {

View File

@ -19,10 +19,11 @@
*/
package ca.uhn.fhir.interceptor.api;
import jakarta.annotation.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
import javax.annotation.Nullable;
public interface IBaseInterceptorService<POINTCUT extends IPointcut> extends IBaseInterceptorBroadcaster<POINTCUT> {

View File

@ -19,8 +19,9 @@
*/
package ca.uhn.fhir.interceptor.api;
import jakarta.annotation.Nonnull;
import java.util.List;
import javax.annotation.Nonnull;
public interface IPointcut {
@Nonnull

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.validation.ValidationResult;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBaseConformance;
import java.io.Writer;
@ -33,7 +34,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
/**
* Value for {@link Hook#value()}
@ -93,6 +93,10 @@ public enum Pointcut implements IPointcut {
* <li>
* ca.uhn.fhir.rest.client.api.IRestfulClient - The client object making the request
* </li>
* <li>
* ca.uhn.fhir.rest.client.api.ClientResponseContext - Contains an IHttpRequest, an IHttpResponse, and an IRestfulClient
* and also allows the client to mutate the contained IHttpResponse
* </li>
* </ul>
* </p>
* Hook methods must return <code>void</code>.
@ -101,7 +105,8 @@ public enum Pointcut implements IPointcut {
void.class,
"ca.uhn.fhir.rest.client.api.IHttpRequest",
"ca.uhn.fhir.rest.client.api.IHttpResponse",
"ca.uhn.fhir.rest.client.api.IRestfulClient"),
"ca.uhn.fhir.rest.client.api.IRestfulClient",
"ca.uhn.fhir.rest.client.api.ClientResponseContext"),
/**
* <b>Server Hook:</b>
@ -153,10 +158,10 @@ public enum Pointcut implements IPointcut {
* Hooks may accept the following parameters:
* <ul>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* </ul>
* </p>
@ -166,7 +171,7 @@ public enum Pointcut implements IPointcut {
* no further processing will occur and no further interceptors will be called.
*/
SERVER_INCOMING_REQUEST_PRE_PROCESSED(
boolean.class, "javax.servlet.http.HttpServletRequest", "javax.servlet.http.HttpServletResponse"),
boolean.class, "jakarta.servlet.http.HttpServletRequest", "jakarta.servlet.http.HttpServletResponse"),
/**
* <b>Server Hook:</b>
@ -193,10 +198,10 @@ public enum Pointcut implements IPointcut {
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
* </li>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* <li>
* ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException - The exception that was thrown
@ -215,8 +220,8 @@ public enum Pointcut implements IPointcut {
boolean.class,
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"javax.servlet.http.HttpServletRequest",
"javax.servlet.http.HttpServletResponse",
"jakarta.servlet.http.HttpServletRequest",
"jakarta.servlet.http.HttpServletResponse",
"ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException"),
/**
@ -239,10 +244,10 @@ public enum Pointcut implements IPointcut {
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
* </li>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* </ul>
* <p>
@ -263,8 +268,8 @@ public enum Pointcut implements IPointcut {
boolean.class,
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"javax.servlet.http.HttpServletRequest",
"javax.servlet.http.HttpServletResponse"),
"jakarta.servlet.http.HttpServletRequest",
"jakarta.servlet.http.HttpServletResponse"),
/**
* <b>Server Hook:</b>
@ -286,10 +291,10 @@ public enum Pointcut implements IPointcut {
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
* </li>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* </ul>
* <p>
@ -308,8 +313,8 @@ public enum Pointcut implements IPointcut {
boolean.class,
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"javax.servlet.http.HttpServletRequest",
"javax.servlet.http.HttpServletResponse"),
"jakarta.servlet.http.HttpServletRequest",
"jakarta.servlet.http.HttpServletResponse"),
/**
* <b>Server Hook:</b>
@ -411,10 +416,10 @@ public enum Pointcut implements IPointcut {
* {@link NullPointerException} in the case of a bug being triggered.
* </li>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* </ul>
* <p>
@ -429,8 +434,8 @@ public enum Pointcut implements IPointcut {
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"java.lang.Throwable",
"javax.servlet.http.HttpServletRequest",
"javax.servlet.http.HttpServletResponse"),
"jakarta.servlet.http.HttpServletRequest",
"jakarta.servlet.http.HttpServletResponse"),
/**
* <b>Server Hook:</b>
@ -458,10 +463,10 @@ public enum Pointcut implements IPointcut {
* ca.uhn.fhir.rest.api.server.ResponseDetails - This object contains details about the response, including the contents. Hook methods may modify this object to change or replace the response.
* </li>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* </ul>
* </p>
@ -482,8 +487,8 @@ public enum Pointcut implements IPointcut {
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"org.hl7.fhir.instance.model.api.IBaseResource",
"ca.uhn.fhir.rest.api.server.ResponseDetails",
"javax.servlet.http.HttpServletRequest",
"javax.servlet.http.HttpServletResponse"),
"jakarta.servlet.http.HttpServletRequest",
"jakarta.servlet.http.HttpServletResponse"),
/**
* <b>Server Hook:</b>
@ -549,10 +554,10 @@ public enum Pointcut implements IPointcut {
* java.lang.String - The GraphQL response
* </li>
* <li>
* javax.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* jakarta.servlet.http.HttpServletRequest - The servlet request, when running in a servlet environment
* </li>
* <li>
* javax.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* jakarta.servlet.http.HttpServletResponse - The servlet response, when running in a servlet environment
* </li>
* </ul>
* </p>
@ -573,8 +578,8 @@ public enum Pointcut implements IPointcut {
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
"java.lang.String",
"java.lang.String",
"javax.servlet.http.HttpServletRequest",
"javax.servlet.http.HttpServletResponse"),
"jakarta.servlet.http.HttpServletRequest",
"jakarta.servlet.http.HttpServletResponse"),
/**
* <b>Server Hook:</b>
@ -2930,6 +2935,31 @@ public enum Pointcut implements IPointcut {
"ca.uhn.fhir.rest.api.server.RequestDetails",
"org.hl7.fhir.instance.model.api.IBaseResource"),
/**
* <b>Storage Hook:</b>
* Invoked before a batch job is persisted to the database.
* <p>
* Hooks will have access to the content of the job being created
* and may choose to make modifications to it. These changes will be
* reflected in permanent storage.
* </p>
* Hooks may accept the following parameters:
* <ul>
* <li>
* ca.uhn.fhir.batch2.model.JobInstance
* </li>
* <li>
* ca.uhn.fhir.rest.api.server.RequestDetails - A bean containing details about the request that lead to the creation
* of the jobInstance.
* </li>
* </ul>
* <p>
* Hooks should return <code>void</code>.
* </p>
*/
STORAGE_PRESTORAGE_BATCH_JOB_CREATE(
void.class, "ca.uhn.fhir.batch2.model.JobInstance", "ca.uhn.fhir.rest.api.server.RequestDetails"),
/**
* This pointcut is used only for unit tests. Do not use in production code as it may be changed or
* removed at any time.

View File

@ -31,6 +31,8 @@ import ca.uhn.fhir.util.ReflectionUtil;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@ -57,8 +59,6 @@ import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & IPointcut>
implements IBaseInterceptorService<POINTCUT>, IBaseInterceptorBroadcaster<POINTCUT> {
@ -263,10 +263,14 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
return myRegisteredPointcuts.contains(thePointcut);
}
protected Class<?> getBooleanReturnType() {
return boolean.class;
}
@Override
public boolean callHooks(POINTCUT thePointcut, HookParams theParams) {
assert haveAppropriateParams(thePointcut, theParams);
assert thePointcut.getReturnType() == void.class || thePointcut.getReturnType() == boolean.class;
assert thePointcut.getReturnType() == void.class || thePointcut.getReturnType() == getBooleanReturnType();
Object retValObj = doCallHooks(thePointcut, theParams, true);
return (Boolean) retValObj;
@ -282,14 +286,16 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
for (BaseInvoker nextInvoker : invokers) {
Object nextOutcome = nextInvoker.invoke(theParams);
Class<?> pointcutReturnType = thePointcut.getReturnType();
if (pointcutReturnType.equals(boolean.class)) {
if (pointcutReturnType.equals(getBooleanReturnType())) {
Boolean nextOutcomeAsBoolean = (Boolean) nextOutcome;
if (Boolean.FALSE.equals(nextOutcomeAsBoolean)) {
ourLog.trace("callHooks({}) for invoker({}) returned false", thePointcut, nextInvoker);
theRetVal = false;
break;
} else {
theRetVal = true;
}
} else if (pointcutReturnType.equals(void.class) == false) {
} else if (!pointcutReturnType.equals(void.class)) {
if (nextOutcome != null) {
theRetVal = nextOutcome;
break;
@ -349,7 +355,7 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
List<BaseInvoker> retVal;
if (haveMultiple == false) {
if (!haveMultiple) {
// The global list doesn't need to be sorted every time since it's sorted on
// insertion each time. Doing so is a waste of cycles..
@ -485,9 +491,9 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
myMethod = theHookMethod;
Class<?> returnType = theHookMethod.getReturnType();
if (myPointcut.getReturnType().equals(boolean.class)) {
if (myPointcut.getReturnType().equals(getBooleanReturnType())) {
Validate.isTrue(
boolean.class.equals(returnType) || void.class.equals(returnType),
getBooleanReturnType().equals(returnType) || void.class.equals(returnType),
"Method does not return boolean or void: %s",
theHookMethod);
} else if (myPointcut.getReturnType().equals(void.class)) {

View File

@ -24,6 +24,8 @@ import ca.uhn.fhir.util.JsonUtil;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@ -37,8 +39,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;

View File

@ -24,7 +24,11 @@ import ca.uhn.fhir.model.api.annotation.Description;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import java.util.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public abstract class BaseElement implements /*IElement, */ ISupportsUndeclaredExtensions {

View File

@ -19,10 +19,15 @@
*/
package ca.uhn.fhir.model.api;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
import org.hl7.fhir.instance.model.api.*;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.io.InputStream;
import java.util.Date;

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.Logs;
import jakarta.annotation.Nullable;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.INarrative;
@ -37,7 +38,6 @@ import java.util.EnumSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -20,12 +20,12 @@
package ca.uhn.fhir.narrative2;
import ca.uhn.fhir.context.FhirContext;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBase;
import java.util.Collection;
import java.util.EnumSet;
import java.util.List;
import javax.annotation.Nonnull;
public interface INarrativeTemplateManifest {
List<INarrativeTemplate> getTemplateByResourceName(

View File

@ -28,6 +28,7 @@ import com.google.common.base.Charsets;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimaps;
import jakarta.annotation.Nonnull;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
@ -41,10 +42,18 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.*;
import javax.annotation.Nonnull;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -45,6 +45,7 @@ import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.UrlUtil;
import com.google.common.base.Charsets;
import jakarta.annotation.Nullable;
import org.apache.commons.io.output.StringBuilderWriter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
@ -78,7 +79,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -39,7 +39,6 @@ import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.primitive.IdDt;
@ -659,9 +658,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
theEventWriter.endArray();
}
BaseRuntimeChildDefinition replacedParentDefinition = nextChild.getReplacedParentDefinition();
if (isMultipleCardinality(nextChild.getMax())
|| (replacedParentDefinition != null
&& isMultipleCardinality(replacedParentDefinition.getMax()))) {
if (nextChild.isMultipleCardinality()
|| (replacedParentDefinition != null && replacedParentDefinition.isMultipleCardinality())) {
beginArray(theEventWriter, nextChildSpecificName);
inArray = true;
encodeChildElementToStreamWriter(
@ -728,14 +726,14 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
List<HeldExtension> heldModExts = Collections.emptyList();
if (extensions.size() > i
&& extensions.get(i) != null
&& extensions.get(i).isEmpty() == false) {
&& !extensions.get(i).isEmpty()) {
haveContent = true;
heldExts = extensions.get(i);
}
if (modifierExtensions.size() > i
&& modifierExtensions.get(i) != null
&& modifierExtensions.get(i).isEmpty() == false) {
&& !modifierExtensions.get(i).isEmpty()) {
haveContent = true;
heldModExts = modifierExtensions.get(i);
}
@ -746,7 +744,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
} else {
nextComments = null;
}
if (nextComments != null && nextComments.isEmpty() == false) {
if (nextComments != null && !nextComments.isEmpty()) {
haveContent = true;
}
@ -804,10 +802,6 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
return myIsSupportsFhirComment;
}
private boolean isMultipleCardinality(int maxCardinality) {
return maxCardinality > 1 || maxCardinality == Child.MAX_UNLIMITED;
}
private void encodeCompositeElementToStreamWriter(
RuntimeResourceDefinition theResDef,
IBaseResource theResource,
@ -917,10 +911,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
// Undeclared extensions
extractUndeclaredExtensions(
theResourceId, extensions, modifierExtensions, null, null, theEncodeContext, theContainedResource);
boolean haveExtension = false;
if (!extensions.isEmpty()) {
haveExtension = true;
}
boolean haveExtension = !extensions.isEmpty();
if (theResourceId.hasFormatComment() || haveExtension) {
beginObject(theEventWriter, "_id");

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.parser.json.BaseJsonLikeWriter;
import ca.uhn.fhir.parser.json.JsonLikeStructure;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.StreamReadConstraints;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
@ -114,14 +115,38 @@ public class JacksonStructure implements JsonLikeStructure {
setNativeArray((ArrayNode) OBJECT_MAPPER.readTree(pbr));
}
} catch (Exception e) {
if (e.getMessage().startsWith("Unexpected char 39")) {
String message;
if (e instanceof JsonProcessingException) {
/*
* Currently there is no way of preventing Jackson from adding this
* annoying REDACTED message from certain messages we get back from
* the parser, so we just manually strip them. Hopefully Jackson
* will accept this request at some point:
* https://github.com/FasterXML/jackson-core/issues/1158
*/
JsonProcessingException jpe = (JsonProcessingException) e;
StringBuilder messageBuilder = new StringBuilder();
String originalMessage = jpe.getOriginalMessage();
originalMessage = originalMessage.replace(
"Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); ", "");
messageBuilder.append(originalMessage);
if (jpe.getLocation() != null) {
messageBuilder.append("\n at [");
jpe.getLocation().appendOffsetDescription(messageBuilder);
messageBuilder.append("]");
}
message = messageBuilder.toString();
} else {
message = e.getMessage();
}
if (message.startsWith("Unexpected char 39")) {
throw new DataFormatException(
Msg.code(1860) + "Failed to parse JSON encoded FHIR content: " + e.getMessage() + " - "
Msg.code(1860) + "Failed to parse JSON encoded FHIR content: " + message + " - "
+ "This may indicate that single quotes are being used as JSON escapes where double quotes are required",
e);
}
throw new DataFormatException(
Msg.code(1861) + "Failed to parse JSON encoded FHIR content: " + e.getMessage(), e);
throw new DataFormatException(Msg.code(1861) + "Failed to parse JSON encoded FHIR content: " + message, e);
}
}

View File

@ -45,29 +45,15 @@ public class JacksonWriter extends BaseJsonLikeWriter {
@Override
public BaseJsonLikeWriter init() {
if (isPrettyPrint()) {
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter() {
/**
* Objects should serialize as
* <pre>
* {
* "key": "value"
* }
* </pre>
* in order to be consistent with Gson behaviour, instead of the jackson default
* <pre>
* {
* "key" : "value"
* }
* </pre>
*/
@Override
public DefaultPrettyPrinter withSeparators(Separators separators) {
_separators = separators;
_objectFieldValueSeparatorWithSpaces = separators.getObjectFieldValueSeparator() + " ";
return this;
}
};
DefaultPrettyPrinter prettyPrinter = new DefaultPrettyPrinter()
.withSeparators(new Separators(
Separators.DEFAULT_ROOT_VALUE_SEPARATOR,
':',
Separators.Spacing.AFTER,
',',
Separators.Spacing.NONE,
',',
Separators.Spacing.NONE));
prettyPrinter = prettyPrinter.withObjectIndenter(new DefaultIndenter(" ", "\n"));
myJsonGenerator.setPrettyPrinter(prettyPrinter);

View File

@ -118,7 +118,7 @@ public @interface Operation {
* always the right choice), the framework will not attempt to generate a response to
* this method.
* <p>
* This is useful if you want to include an {@link javax.servlet.http.HttpServletResponse}
* This is useful if you want to include an {@link jakarta.servlet.http.HttpServletResponse}
* in your method parameters and create a response yourself directly from your
* <code>@Operation</code> method.
* </p>
@ -134,7 +134,7 @@ public @interface Operation {
* always the right choice), the framework will not attempt to parse the request body,
* but will instead delegate it to the <code>@Operation</code> method.
* <p>
* This is useful if you want to include an {@link javax.servlet.http.HttpServletRequest}
* This is useful if you want to include an {@link jakarta.servlet.http.HttpServletRequest}
* in your method parameters and parse the request yourself.
* </p>
*/

View File

@ -23,7 +23,10 @@ import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* RESTful method annotation to be used for the FHIR <a href="http://hl7.org/implement/standards/fhir/http.html#read">read</a> and <a

View File

@ -19,7 +19,10 @@
*/
package ca.uhn.fhir.rest.annotation;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* RESTful method annotation to be used for the FHIR <a href="http://hl7.org/implement/standards/fhir/http.html#transaction">transaction</a> method.

View File

@ -19,7 +19,10 @@
*/
package ca.uhn.fhir.rest.annotation;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
/**

View File

@ -22,7 +22,10 @@ package ca.uhn.fhir.rest.annotation;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.lang.annotation.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* RESTful method annotation to be used for the FHIR

View File

@ -199,6 +199,8 @@ public class Constants {
public static final String PARAM_PRETTY_VALUE_FALSE = "false";
public static final String PARAM_PRETTY_VALUE_TRUE = "true";
public static final String PARAM_PROFILE = "_profile";
public static final String PARAM_PID = "_pid";
public static final String PARAM_QUERY = "_query";
public static final String PARAM_RESPONSE_URL = "response-url"; // Used in messaging
public static final String PARAM_REVINCLUDE = "_revinclude";
@ -218,21 +220,6 @@ public class Constants {
public static final String PARAM_TEXT = "_text";
public static final String PARAM_VALIDATE = "_validate";
/**
* $member-match operation
*/
public static final String PARAM_MEMBER_PATIENT = "MemberPatient";
public static final String PARAM_MEMBER_IDENTIFIER = "MemberIdentifier";
public static final String PARAM_OLD_COVERAGE = "OldCoverage";
public static final String PARAM_NEW_COVERAGE = "NewCoverage";
public static final String PARAM_CONSENT = "Consent";
public static final String PARAM_MEMBER_PATIENT_NAME = PARAM_MEMBER_PATIENT + " Name";
public static final String PARAM_MEMBER_PATIENT_BIRTHDATE = PARAM_MEMBER_PATIENT + " Birthdate";
public static final String PARAM_CONSENT_PATIENT_REFERENCE = PARAM_CONSENT + "'s Patient Reference";
public static final String PARAM_CONSENT_PERFORMER_REFERENCE = PARAM_CONSENT + "'s Performer Reference";
public static final String PARAMQUALIFIER_MISSING = ":missing";
public static final String PARAMQUALIFIER_MISSING_FALSE = "false";
public static final String PARAMQUALIFIER_MISSING_TRUE = "true";
@ -331,6 +318,9 @@ public class Constants {
*/
public static final int UUID_LENGTH = 36;
public static final String BULK_DATA_ACCESS_IG_URL =
"http://hl7.org/fhir/uv/bulkdata/CapabilityStatement/bulk-data";
/**
* Application configuration key used to enable or disable Hibernate Envers.
*/

View File

@ -22,6 +22,8 @@ package ca.uhn.fhir.rest.api;
import ca.uhn.fhir.context.api.BundleInclusionRule;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -29,8 +31,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* This interface should be considered experimental and will likely change in future releases of HAPI. Use with caution!

View File

@ -23,10 +23,10 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.annotation.Patch;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import jakarta.annotation.Nonnull;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;

View File

@ -19,7 +19,7 @@
*/
package ca.uhn.fhir.rest.api;
import javax.annotation.Nullable;
import jakarta.annotation.Nullable;
public class PreferHeader {

View File

@ -19,8 +19,9 @@
*/
package ca.uhn.fhir.rest.api;
import jakarta.annotation.Nullable;
import java.util.HashMap;
import javax.annotation.Nullable;
/**
* Represents values for "return" value as provided in the the <a href="https://tools.ietf.org/html/rfc7240#section-4.2">HTTP Prefer header</a>.

View File

@ -20,11 +20,11 @@
package ca.uhn.fhir.rest.api;
import ca.uhn.fhir.util.CoverageIgnore;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.Validate;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nonnull;
@CoverageIgnore
public enum RestOperationTypeEnum {

View File

@ -0,0 +1,103 @@
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.rest.client.api;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.Pointcut;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.util.Objects;
import java.util.StringJoiner;
/**
* Used to pass context to {@link Pointcut#CLIENT_RESPONSE}, including a mutable {@link IHttpResponse}
*/
public class ClientResponseContext {
private final IHttpRequest myHttpRequest;
private IHttpResponse myHttpResponse;
private final IRestfulClient myRestfulClient;
private final FhirContext myFhirContext;
private final Class<? extends IBaseResource> myReturnType;
public ClientResponseContext(
IHttpRequest myHttpRequest,
IHttpResponse theHttpResponse,
IRestfulClient myRestfulClient,
FhirContext theFhirContext,
Class<? extends IBaseResource> theReturnType) {
this.myHttpRequest = myHttpRequest;
this.myHttpResponse = theHttpResponse;
this.myRestfulClient = myRestfulClient;
this.myFhirContext = theFhirContext;
this.myReturnType = theReturnType;
}
public IHttpRequest getHttpRequest() {
return myHttpRequest;
}
public IHttpResponse getHttpResponse() {
return myHttpResponse;
}
public IRestfulClient getRestfulClient() {
return myRestfulClient;
}
public FhirContext getFhirContext() {
return myFhirContext;
}
public Class<? extends IBaseResource> getReturnType() {
return myReturnType;
}
public void setHttpResponse(IHttpResponse theHttpResponse) {
this.myHttpResponse = theHttpResponse;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ClientResponseContext that = (ClientResponseContext) o;
return Objects.equals(myHttpRequest, that.myHttpRequest)
&& Objects.equals(myHttpResponse, that.myHttpResponse)
&& Objects.equals(myRestfulClient, that.myRestfulClient)
&& Objects.equals(myFhirContext, that.myFhirContext)
&& Objects.equals(myReturnType, that.myReturnType);
}
@Override
public int hashCode() {
return Objects.hash(myHttpRequest, myHttpResponse, myRestfulClient, myFhirContext, myReturnType);
}
@Override
public String toString() {
return new StringJoiner(", ", ClientResponseContext.class.getSimpleName() + "[", "]")
.add("myHttpRequest=" + myHttpRequest)
.add("myHttpResponse=" + myHttpResponse)
.add("myRestfulClient=" + myRestfulClient)
.add("myFhirContext=" + myFhirContext)
.add("myReturnType=" + myReturnType)
.toString();
}
}

View File

@ -24,10 +24,9 @@ import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBaseResource;
import javax.annotation.Nonnull;
public interface IRestfulClient {
/**

View File

@ -23,7 +23,9 @@ import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import org.apache.commons.lang3.ObjectUtils;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import java.util.*;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.defaultString;

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.DateUtils;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -34,7 +35,6 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.annotation.Nonnull;
import static ca.uhn.fhir.rest.param.ParamPrefixEnum.EQUAL;
import static ca.uhn.fhir.rest.param.ParamPrefixEnum.GREATERTHAN_OR_EQUALS;

View File

@ -19,7 +19,9 @@
*/
package ca.uhn.fhir.rest.param;
import java.util.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
* Comparator/qualifier for values used in REST params, such as {@link DateParam}, {@link NumberParam}, and

View File

@ -19,7 +19,11 @@
*/
package ca.uhn.fhir.util;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.ICompositeType;

View File

@ -25,6 +25,8 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.primitive.IdDt;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
@ -36,8 +38,6 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.util.Date;
import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* This class can be used to build a Bundle resource to be used as a FHIR transaction. Convenience methods provide
@ -196,11 +196,7 @@ public class BundleBuilder {
public UpdateBuilder addTransactionUpdateEntry(IBaseResource theResource) {
Validate.notNull(theResource, "theResource must not be null");
IIdType id = theResource.getIdElement();
if (id.hasIdPart() && !id.hasResourceType()) {
String resourceType = myContext.getResourceType(theResource);
id = id.withResourceType(resourceType);
}
IIdType id = getIdTypeForUpdate(theResource);
String requestUrl = id.toUnqualifiedVersionless().getValue();
String fullUrl = id.getValue();
@ -225,13 +221,29 @@ public class BundleBuilder {
myEntryRequestUrlChild.getMutator().setValue(request, url);
// Bundle.entry.request.method
IPrimitiveType<?> method = (IPrimitiveType<?>)
myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
method.setValueAsString(theHttpVerb);
myEntryRequestMethodChild.getMutator().setValue(request, method);
addRequestMethod(request, theHttpVerb);
return url;
}
/**
* Adds an entry containing an update (UPDATE) request without the body of the resource.
* Also sets the Bundle.type value to "transaction" if it is not already set.
*
* @param theResource The resource to update.
*/
public void addTransactionUpdateIdOnlyEntry(IBaseResource theResource) {
setBundleField("type", "transaction");
Validate.notNull(theResource, "theResource must not be null");
IIdType id = getIdTypeForUpdate(theResource);
String requestUrl = id.toUnqualifiedVersionless().getValue();
String fullUrl = id.getValue();
String httpMethod = "PUT";
addIdOnlyEntry(requestUrl, httpMethod, fullUrl);
}
/**
* Adds an entry containing an create (POST) request.
* Also sets the Bundle.type value to "transaction" if it is not already set.
@ -247,20 +259,47 @@ public class BundleBuilder {
String resourceType = myContext.getResourceType(theResource);
// Bundle.entry.request.url
IPrimitiveType<?> url =
(IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
url.setValueAsString(resourceType);
myEntryRequestUrlChild.getMutator().setValue(request, url);
addRequestUrl(request, resourceType);
// Bundle.entry.request.url
IPrimitiveType<?> method = (IPrimitiveType<?>)
myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
method.setValueAsString("POST");
myEntryRequestMethodChild.getMutator().setValue(request, method);
// Bundle.entry.request.method
addRequestMethod(request, "POST");
return new CreateBuilder(request);
}
/**
* Adds an entry containing a create (POST) request without the body of the resource.
* Also sets the Bundle.type value to "transaction" if it is not already set.
*
* @param theResource The resource to create
*/
public void addTransactionCreateEntryIdOnly(IBaseResource theResource) {
setBundleField("type", "transaction");
String requestUrl = myContext.getResourceType(theResource);
String fullUrl = theResource.getIdElement().getValue();
String httpMethod = "POST";
addIdOnlyEntry(requestUrl, httpMethod, fullUrl);
}
private void addIdOnlyEntry(String theRequestUrl, String theHttpMethod, String theFullUrl) {
IBase entry = addEntry();
// Bundle.entry.request
IBase request = myEntryRequestDef.newInstance();
myEntryRequestChild.getMutator().setValue(entry, request);
// Bundle.entry.request.url
addRequestUrl(request, theRequestUrl);
// Bundle.entry.request.method
addRequestMethod(request, theHttpMethod);
// Bundle.entry.fullUrl
addFullUrl(entry, theFullUrl);
}
/**
* Adds an entry containing a delete (DELETE) request.
* Also sets the Bundle.type value to "transaction" if it is not already set.
@ -341,20 +380,44 @@ public class BundleBuilder {
IBase request = addEntryAndReturnRequest();
// Bundle.entry.request.url
IPrimitiveType<?> url =
(IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
url.setValueAsString(theDeleteUrl);
myEntryRequestUrlChild.getMutator().setValue(request, url);
addRequestUrl(request, theDeleteUrl);
// Bundle.entry.request.method
IPrimitiveType<?> method = (IPrimitiveType<?>)
myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
method.setValueAsString("DELETE");
myEntryRequestMethodChild.getMutator().setValue(request, method);
addRequestMethod(request, "DELETE");
return new DeleteBuilder();
}
private IIdType getIdTypeForUpdate(IBaseResource theResource) {
IIdType id = theResource.getIdElement();
if (id.hasIdPart() && !id.hasResourceType()) {
String resourceType = myContext.getResourceType(theResource);
id = id.withResourceType(resourceType);
}
return id;
}
private void addFullUrl(IBase theEntry, String theFullUrl) {
IPrimitiveType<?> fullUrl =
(IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
fullUrl.setValueAsString(theFullUrl);
myEntryFullUrlChild.getMutator().setValue(theEntry, fullUrl);
}
private void addRequestUrl(IBase request, String theRequestUrl) {
IPrimitiveType<?> url =
(IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
url.setValueAsString(theRequestUrl);
myEntryRequestUrlChild.getMutator().setValue(request, url);
}
private void addRequestMethod(IBase theRequest, String theMethod) {
IPrimitiveType<?> method = (IPrimitiveType<?>)
myEntryRequestMethodDef.newInstance(myEntryRequestMethodChild.getInstanceConstructorArguments());
method.setValueAsString(theMethod);
myEntryRequestMethodChild.getMutator().setValue(theRequest, method);
}
/**
* Adds an entry for a Collection bundle type
*/
@ -406,10 +469,7 @@ public class BundleBuilder {
IBase entry = addEntry();
// Bundle.entry.fullUrl
IPrimitiveType<?> fullUrl =
(IPrimitiveType<?>) myContext.getElementDefinition("uri").newInstance();
fullUrl.setValueAsString(theFullUrl);
myEntryFullUrlChild.getMutator().setValue(entry, fullUrl);
addFullUrl(entry, theFullUrl);
// Bundle.entry.resource
myEntryResourceChild.getMutator().setValue(entry, theResource);

View File

@ -35,10 +35,12 @@ import ca.uhn.fhir.util.bundle.EntryListAccumulator;
import ca.uhn.fhir.util.bundle.ModifiableBundleEntry;
import ca.uhn.fhir.util.bundle.SearchBundleEntryParts;
import com.google.common.collect.Sets;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger;
@ -693,6 +695,25 @@ public class BundleUtil {
return bundleEntry;
}
/**
* Get resource from bundle by resource type and reference
* @param theContext FhirContext
* @param theBundle IBaseBundle
* @param theReference IBaseReference
* @return IBaseResource if found and null if not found.
*/
@Nonnull
public static IBaseResource getResourceByReferenceAndResourceType(
@Nonnull FhirContext theContext, @Nonnull IBaseBundle theBundle, @Nonnull IBaseReference theReference) {
return toListOfResources(theContext, theBundle).stream()
.filter(theResource -> theReference
.getReferenceElement()
.getIdPart()
.equals(theResource.getIdElement().getIdPart()))
.findFirst()
.orElse(null);
}
private static class SortLegality {
private boolean myIsLegal;

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import com.google.common.base.Charsets;
import jakarta.annotation.Nonnull;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.BOMInputStream;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -37,7 +38,6 @@ import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.function.Function;
import java.util.zip.GZIPInputStream;
import javax.annotation.Nonnull;
/**
* Use this API with caution, it may change!

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.util;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseReference;
@ -29,7 +30,6 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.util.Date;
import javax.annotation.Nonnull;
/**
* This class can be used to generate <code>Composition</code> resources in

View File

@ -20,10 +20,10 @@
package ca.uhn.fhir.util;
import ca.uhn.fhir.rest.param.DateRangeParam;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import java.util.Date;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class DateRangeUtil {

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.util;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
@ -33,7 +34,6 @@ import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
/**
* Utility for modifying with extensions in a FHIR version-independent approach.

View File

@ -42,6 +42,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import com.google.common.collect.Lists;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
@ -71,8 +73,6 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
@ -287,9 +287,33 @@ public class FhirTerser {
return retVal;
}
/**
* Extracts all outbound references from a resource
*
* @param theResource the resource to be analyzed
* @return a list of references to other resources
*/
public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) {
return getAllResourceReferencesExcluding(theResource, Lists.newArrayList());
}
/**
* Extracts all outbound references from a resource, excluding any that are located on black-listed parts of the
* resource
*
* @param theResource the resource to be analyzed
* @param thePathsToExclude a list of dot-delimited paths not to include in the result
* @return a list of references to other resources
*/
public List<ResourceReferenceInfo> getAllResourceReferencesExcluding(
final IBaseResource theResource, List<String> thePathsToExclude) {
final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<>();
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
List<List<String>> tokenizedPathsToExclude = thePathsToExclude.stream()
.map(path -> StringUtils.split(path, "."))
.map(Lists::newArrayList)
.collect(Collectors.toList());
visit(newMap(), theResource, theResource, null, null, def, new IModelVisitor() {
@Override
public void acceptElement(
@ -301,6 +325,10 @@ public class FhirTerser {
if (theElement == null || theElement.isEmpty()) {
return;
}
if (thePathToElement != null && pathShouldBeExcluded(tokenizedPathsToExclude, thePathToElement)) {
return;
}
if (IBaseReference.class.isAssignableFrom(theElement.getClass())) {
retVal.add(new ResourceReferenceInfo(
myContext, theOuterResource, thePathToElement, (IBaseReference) theElement));
@ -310,6 +338,19 @@ public class FhirTerser {
return retVal;
}
private boolean pathShouldBeExcluded(List<List<String>> theTokenizedPathsToExclude, List<String> thePathToElement) {
return theTokenizedPathsToExclude.stream().anyMatch(p -> {
// Check whether the path to the element starts with the path to be excluded
if (p.size() > thePathToElement.size()) {
return false;
}
List<String> prefix = thePathToElement.subList(0, p.size());
return Objects.equals(p, prefix);
});
}
private BaseRuntimeChildDefinition getDefinition(
BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));

View File

@ -27,12 +27,12 @@ import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import jakarta.annotation.Nonnull;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.List;
import javax.annotation.Nonnull;
public class JsonUtil {

View File

@ -28,6 +28,9 @@ public class Logs {
private static final Logger ourNarrativeGenerationTroubleshootingLog =
LoggerFactory.getLogger("ca.uhn.fhir.log.narrative_generation_troubleshooting");
private static final Logger ourTerminologyTroubleshootingLog =
LoggerFactory.getLogger("ca.uhn.fhir.log.terminology_troubleshooting");
private static final Logger ourSubscriptionTroubleshootingLog =
LoggerFactory.getLogger("ca.cdr.log.subscription_troubleshooting");
@ -42,6 +45,10 @@ public class Logs {
return ourBatchTroubleshootingLog;
}
public static Logger getTerminologyTroubleshootingLog() {
return ourTerminologyTroubleshootingLog;
}
public static Logger getSubscriptionTroubleshootingLog() {
return ourSubscriptionTroubleshootingLog;
}

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import jakarta.annotation.Nullable;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
@ -36,7 +37,6 @@ import org.hl7.fhir.instance.model.api.ICompositeType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.util.List;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.primitive.StringDt;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
@ -45,7 +46,6 @@ import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
@ -403,8 +403,15 @@ public class ParametersUtil {
public static void addPartDecimal(FhirContext theContext, IBase theParameter, String theName, Double theValue) {
IPrimitiveType<BigDecimal> value = (IPrimitiveType<BigDecimal>)
theContext.getElementDefinition("decimal").newInstance();
value.setValue(theValue == null ? null : BigDecimal.valueOf(theValue));
if (theValue == null) {
value.setValue(null);
} else {
BigDecimal decimalValue = BigDecimal.valueOf(theValue);
if (decimalValue.scale() < 0) {
decimalValue = decimalValue.setScale(0);
}
value.setValue(decimalValue);
}
addPart(theContext, theParameter, theName, value);
}

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.util;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import jakarta.annotation.Nonnull;
import org.apache.commons.lang3.Validate;
import java.lang.reflect.Constructor;
@ -39,7 +40,6 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import javax.annotation.Nonnull;
public class ReflectionUtil {

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.i18n.Msg;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -34,7 +35,6 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
public class SearchParameterUtil {

View File

@ -0,0 +1,57 @@
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2023 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.util;
import com.google.common.collect.Iterators;
import com.google.common.collect.UnmodifiableIterator;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public class StreamUtil {
/** Static util class */
private StreamUtil() {}
/**
* Chunk the stream into Lists of size theChunkSize.
* The last chunk will be smaller unless the stream size is evenly divisible.
* Closes the underlying stream when done.
*
* @param theStream the input stream
* @param theChunkSize the chunk size.
* @return a stream of chunks
*/
public static <T> Stream<List<T>> partition(Stream<T> theStream, int theChunkSize) {
Spliterator<T> spliterator = theStream.spliterator();
Iterator<T> iterator = Spliterators.iterator(spliterator);
UnmodifiableIterator<List<T>> partition = Iterators.partition(iterator, theChunkSize);
// we could be fancier here and support parallel, and sizes; but serial-only is fine for now.
Spliterator<List<T>> partitionedSpliterator = Spliterators.spliteratorUnknownSize(partition, 0);
Stream<List<T>> result = StreamSupport.stream(partitionedSpliterator, false);
// we lose close() via the Iterator. Add it back.
return result.onClose(theStream::close);
}
}

View File

@ -19,11 +19,12 @@
*/
package ca.uhn.fhir.util;
import jakarta.annotation.Nonnull;
import java.io.CharArrayWriter;
import java.nio.charset.StandardCharsets;
import java.text.Normalizer;
import java.util.Arrays;
import javax.annotation.Nonnull;
public class StringUtil {

View File

@ -348,7 +348,30 @@ public final class TerserUtil {
public static void clearField(FhirContext theFhirContext, IBaseResource theResource, String theFieldName) {
BaseRuntimeChildDefinition childDefinition =
getBaseRuntimeChildDefinition(theFhirContext, theFieldName, theResource);
clear(childDefinition.getAccessor().getValues(theResource));
childDefinition.getMutator().setValue(theResource, null);
}
/**
* Clears the specified field on the resource provided by the FHIRPath. If more than one value matches
* the FHIRPath, all values will be cleared.
*
* @param theFhirContext
* @param theResource
* @param theFhirPath
*/
public static void clearFieldByFhirPath(FhirContext theFhirContext, IBaseResource theResource, String theFhirPath) {
if (theFhirPath.contains(".")) {
String parentPath = theFhirPath.substring(0, theFhirPath.lastIndexOf("."));
String fieldName = theFhirPath.substring(theFhirPath.lastIndexOf(".") + 1);
FhirTerser terser = theFhirContext.newTerser();
List<IBase> parents = terser.getValues(theResource, parentPath);
for (IBase parent : parents) {
clearField(theFhirContext, fieldName, parent);
}
} else {
clearField(theFhirContext, theResource, theFhirPath);
}
}
/**
@ -362,7 +385,16 @@ public final class TerserUtil {
BaseRuntimeElementDefinition definition = theFhirContext.getElementDefinition(theBase.getClass());
BaseRuntimeChildDefinition childDefinition = definition.getChildByName(theFieldName);
Validate.notNull(childDefinition);
clear(childDefinition.getAccessor().getValues(theBase));
BaseRuntimeChildDefinition.IAccessor accessor = childDefinition.getAccessor();
clear(accessor.getValues(theBase));
List<IBase> newValue = accessor.getValues(theBase);
if (newValue != null && !newValue.isEmpty()) {
// Our clear failed, probably because it was an immutable SingletonList returned by a FieldPlainAccessor
// that cannot be cleared.
// Let's just null it out instead.
childDefinition.getMutator().setValue(theBase, null);
}
}
/**

View File

@ -28,6 +28,8 @@ import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import com.google.common.escape.Escaper;
import com.google.common.net.PercentEscaper;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
@ -50,8 +52,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.defaultString;

View File

@ -123,8 +123,15 @@ public enum VersionEnum {
V6_8_0,
V6_8_1,
V6_8_2,
V6_8_3,
V6_8_4,
V6_8_5,
V6_9_0,
V6_10_0,
V6_10_1,
V6_11_0,
V7_0_0;
public static VersionEnum latestVersion() {

View File

@ -24,7 +24,8 @@ import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.Lang;
import org.apache.jena.riot.RDFDataMgr;
import java.io.*;
import java.io.Reader;
import java.io.Writer;
public class RDFUtil {

View File

@ -21,9 +21,9 @@ package ca.uhn.fhir.validation;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import jakarta.annotation.Nonnull;
import java.util.List;
import javax.annotation.Nonnull;
public interface IValidationContext<T> {

View File

@ -26,11 +26,11 @@ import ca.uhn.fhir.parser.LenientErrorHandler;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.ObjectUtil;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;

View File

@ -37,8 +37,8 @@ import com.helger.commons.io.resource.ClassPathResource;
import com.helger.commons.io.resource.IReadableResource;
import com.helger.schematron.ISchematronResource;
import com.helger.schematron.SchematronHelper;
import com.helger.schematron.sch.SchematronResourceSCH;
import com.helger.schematron.svrl.jaxb.SchematronOutputType;
import com.helger.schematron.xslt.SchematronResourceSCH;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
@ -90,7 +90,12 @@ public class SchematronBaseValidator implements IValidatorModule {
}
StreamSource source = new StreamSource(new StringReader(resourceAsString));
SchematronOutputType results = SchematronHelper.applySchematron(sch, source);
SchematronOutputType results;
try {
results = sch.applySchematronValidationToSVRL(source);
} catch (Exception e) {
throw new InternalErrorException(Msg.code(2433) + e.getMessage(), e);
}
if (results == null) {
return;
}

View File

@ -19,7 +19,7 @@
*/
package org.hl7.fhir.instance.model.api;
import javax.annotation.Nullable;
import jakarta.annotation.Nullable;
public interface IPrimitiveType<T> extends IBaseDatatype {

View File

@ -206,10 +206,3 @@ ca.uhn.fhir.jpa.provider.DiffProvider.cantDiffDifferentTypes=Unable to diff two
ca.uhn.fhir.jpa.interceptor.validation.RuleRequireProfileDeclaration.noMatchingProfile=Resource of type "{0}" does not declare conformance to profile from: {1}
ca.uhn.fhir.jpa.interceptor.validation.RuleRequireProfileDeclaration.illegalProfile=Resource of type "{0}" must not declare conformance to profile: {1}
operation.member.match.error.coverage.not.found=Could not find coverage for member based on coverage id or coverage identifier.
operation.member.match.error.beneficiary.not.found=Could not find beneficiary for coverage.
operation.member.match.error.missing.parameter=Parameter "{0}" is required.
operation.member.match.error.beneficiary.without.identifier=Coverage beneficiary does not have an identifier.
operation.member.match.error.patient.not.found=Could not find matching patient for coverage.
operation.member.match.error.consent.release.data.mismatch=Consent policy does not match the data release segmentation capabilities.

View File

@ -1,12 +1,14 @@
package ca.uhn.fhir.i18n;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import org.junit.jupiter.api.Test;
import java.util.Set;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.matchesPattern;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class HapiLocalizerTest {

View File

@ -2,7 +2,8 @@ package ca.uhn.fhir.model.api;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
public class ResourceMetadataKeyEnumTest {

View File

@ -5,7 +5,10 @@ import org.junit.jupiter.api.Test;
import java.net.URI;
import java.net.URISyntaxException;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TagTest {

View File

@ -5,7 +5,9 @@ import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class CacheControlDirectiveTest {

View File

@ -2,7 +2,7 @@ package ca.uhn.fhir.rest.api;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class EncodingEnumTest {

View File

@ -7,7 +7,8 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class MethodOutcomeTest {

View File

@ -17,7 +17,9 @@ import static java.util.concurrent.TimeUnit.SECONDS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
public class DateParamTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DateParamTest.class);

View File

@ -3,7 +3,8 @@ package ca.uhn.fhir.rest.param;
import com.google.common.collect.Sets;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class QualifierDetailsTest {

View File

@ -1,14 +1,11 @@
package ca.uhn.fhir.rest.param;
import static ca.uhn.fhir.rest.api.Constants.PARAMQUALIFIER_STRING_TEXT;
import static org.junit.jupiter.api.Assertions.*;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.read.ListAppender;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
@ -18,12 +15,17 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import ch.qos.logback.classic.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.stream.Collectors;
import static ca.uhn.fhir.rest.api.Constants.PARAMQUALIFIER_STRING_TEXT;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ExtendWith(MockitoExtension.class)
public class StringParamTest {

View File

@ -2,7 +2,7 @@ package ca.uhn.fhir.rest.server.exceptions;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BaseServerResponseExceptionTest {

View File

@ -5,7 +5,6 @@ import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@ -19,7 +18,9 @@ import static ca.uhn.fhir.rest.param.ParamPrefixEnum.GREATERTHAN_OR_EQUALS;
import static ca.uhn.fhir.rest.param.ParamPrefixEnum.LESSTHAN;
import static ca.uhn.fhir.rest.param.ParamPrefixEnum.LESSTHAN_OR_EQUALS;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
class DateRangeUtilTest {

View File

@ -5,7 +5,11 @@ import org.slf4j.Logger;
import org.slf4j.event.Level;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
public class LogUtilTest {

View File

@ -1,15 +1,17 @@
package ca.uhn.fhir.util;
import static org.junit.jupiter.api.Assertions.*;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.i18n.Msg;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.i18n.Msg;
import org.junit.jupiter.api.Test;
import ca.uhn.fhir.context.ConfigurationException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class ReflectionUtilTest {

View File

@ -0,0 +1,65 @@
package ca.uhn.fhir.util;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
class StreamUtilTest {
@ParameterizedTest
@MethodSource("streamPartitionTestCases")
void testStreamPartitionBy4(String theCase, List<Integer> theInput, List<List<Integer>> theOutput) {
List<List<Integer>> result = StreamUtil.partition(theInput.stream(), 4).toList();
assertEquals(theOutput, result, theCase);
}
static Object[][] streamPartitionTestCases() {
return new Object[][]{
{
"empty list produces empty stream",
List.of(),
List.of()
},
{
"short list produces single chunk",
List.of(1, 2, 3),
List.of(List.of(1, 2, 3))
},
{
"longer list produces several chunks",
List.of(1, 2, 3, 1, 2, 3, 1, 2, 3),
List.of(List.of(1, 2, 3, 1), List.of(2, 3, 1, 2), List.of(3))
},
{
"even size produces even chunks",
List.of(1, 2, 3,4,5,6,7,8),
List.of(List.of(1, 2, 3,4), List.of(5,6,7,8))
},
};
}
@Test
void testStreamPartitionClosesOriginalStream() {
// given
AtomicBoolean closed = new AtomicBoolean(false);
Stream<Integer> baseStream = Stream.of(1, 2, 3).onClose(()->closed.set(true));
// when
StreamUtil.partition(baseStream, 2).close();
// then
assertThat("partition closed underlying stream", closed.get());
}
}

View File

@ -8,7 +8,7 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.annotation.Nonnull;
import jakarta.annotation.Nonnull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.verify;

View File

@ -1,9 +1,9 @@
package ca.uhn.fhir.validation;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class ResultSeverityEnumTest {
@Test

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
@ -12,7 +12,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -42,7 +42,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.2.0</version>
<dependencies>
<dependency>
<groupId>com.puppycrawl.tools</groupId>
@ -109,7 +108,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${maven_checkstyle_version}</version>
<configuration>
<excludes>**/osgi/**/*, **/.mvn/**/*, **/.mvn_/**/*</excludes>
<sourceDirectories>

View File

@ -18,15 +18,32 @@
<property name="format" value="(?i)FIXME"/>
</module>
<!-- Ban star imports - TODO: enable this -->
<!--
<module name="RegexpSinglelineJava">
<property name="format" value="^import .*\*;"/>
</module>
-->
<module name="RegexpSinglelineJava">
<property name="format" value="System\.out\.println"/>
<property name="ignoreComments" value="true"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="org\.jetbrains\.annotations\.NotNull"/>
<property name="message" value="Incorrect &quot;org.jetbrains.annotation.NotNull&quot; annotation used: The &quot;jakarta.annotation.Nonnull&quot; annotation should be used for non-null values"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="org\.jetbrains\.annotations\.Nullable"/>
<property name="message" value="Incorrect &quot;org.jetbrains.annotation.Nullable&quot; annotation used: The &quot;jakarta.annotation.Nullable&quot; annotation should be used for nullable values"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="javax\.annotation\.Nonnull"/>
<property name="message" value="Incorrect &quot;javax.annotation.Nonnull&quot; used: &quot;jakarta.annotation.Nonnull&quot; should be used for non-null values"/>
</module>
<module name="RegexpSinglelineJava">
<property name="format" value="javax\.annotation\.Nullable"/>
<property name="message" value="Incorrect &quot;javax.annotation.Nullable&quot; used: &quot;jakarta.annotation.Nonnull&quot; should be used for nullable values"/>
</module>
<!-- Should always use the Spring transactional interface, per: https://stackoverflow.com/questions/26387399/javax-transaction-transactional-vs-org-springframework-transaction-annotation-tr -->
<module name="RegexpSinglelineJava">

View File

@ -73,8 +73,12 @@ public final class HapiErrorCodeCheck extends AbstractCheck {
} else {
String location = getFilePath() + ":" + instantiation.getLineNo() + ":"
+ instantiation.getColumnNo() + "(" + code + ")";
// Ignore errors thrown in test for duplicates, as some fake implementations are throwing the same
// codes for test purpsoes.
if (!location.contains("/test/")) {
ourCache.put(code, location);
}
}
} else {
log(theAst.getLineNo(), "Called Msg.code() with a non-integer argument");
}

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.9.7-SNAPSHOT</version>
<version>6.11.7-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -152,38 +152,25 @@
<artifactId>spring-web</artifactId>
</dependency>
<!-- Web Server -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<groupId>org.eclipse.jetty.ee10.websocket</groupId>
<artifactId>jetty-ee10-websocket-jakarta-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<groupId>jakarta.websocket</groupId>
<artifactId>jakarta.websocket-client-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-core-client</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-jetty-client</artifactId>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
@ -195,39 +182,17 @@
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<artifactId>thymeleaf-spring6</artifactId>
</dependency>
<!-- Dependencies for Schematron -->
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-schematron</artifactId>
<exclusions>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
</exclusion>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.istack</groupId>
<artifactId>istack-commons-runtime</artifactId>
</exclusion>
</exclusions>
<groupId>com.helger.schematron</groupId>
<artifactId>ph-schematron-api</artifactId>
</dependency>
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-commons</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<groupId>com.helger.schematron</groupId>
<artifactId>ph-schematron-xslt</artifactId>
</dependency>
@ -257,11 +222,30 @@
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>simple-java-mail</artifactId>
<!-- Excluded in favor of jakarta.activation:jakarta.activation-api -->
<exclusions>
<exclusion>
<groupId>com.sun.activation</groupId>
<artifactId>jakarta.activation</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<parallel>none</parallel>
<reuseForks>false</reuseForks>
<forkCount>1</forkCount>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -34,6 +34,7 @@ import com.google.common.base.Charsets;
import com.google.common.collect.Sets;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import jakarta.annotation.Nullable;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
@ -75,7 +76,6 @@ import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import javax.annotation.Nullable;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -31,6 +31,7 @@ import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.util.ParametersUtil;
import jakarta.annotation.Nonnull;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
@ -40,11 +41,12 @@ import org.apache.commons.io.file.PathUtils;
import org.apache.commons.io.filefilter.FileFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.SuffixFileFilter;
import org.apache.commons.lang3.time.DateUtils;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -67,7 +69,6 @@ import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutionException;
import java.util.zip.GZIPInputStream;
import javax.annotation.Nonnull;
public class BulkImportCommand extends BaseCommand {
@ -234,7 +235,12 @@ public class BulkImportCommand extends BaseCommand {
private List<String> startServer(int thePort, List<File> files) {
List<String> indexes = new ArrayList<>();
myServer = new Server(thePort);
myServer = new Server();
ServerConnector connector = new ServerConnector(myServer);
connector.setIdleTimeout(DateUtils.MILLIS_PER_MINUTE);
connector.setPort(myPort);
myServer.setConnectors(new Connector[] {connector});
myServlet = new BulkImportFileServlet();
for (File t : files) {

View File

@ -36,6 +36,11 @@ public class LoadingValidationSupportDstu2 implements IValidationSupport {
private static final org.slf4j.Logger ourLog =
org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu2.class);
@Override
public String getName() {
return "Dstu2 CLI Loading Validation Support";
}
@Override
public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
String resName = myCtx.getResourceType(theClass);

View File

@ -35,6 +35,11 @@ public class LoadingValidationSupportDstu3 implements IValidationSupport {
private static final org.slf4j.Logger ourLog =
org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportDstu3.class);
@Override
public String getName() {
return "Dstu3 CLI Loading Validation Support";
}
@Override
public <T extends IBaseResource> T fetchResource(Class<T> theClass, String theUri) {
String resName = myCtx.getResourceType(theClass);

View File

@ -24,7 +24,7 @@ import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.util.ParametersUtil;
import joptsimple.internal.Strings;
import jakarta.annotation.Nonnull;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.hl7.fhir.instance.model.api.IBaseParameters;
@ -32,7 +32,6 @@ import org.hl7.fhir.r4.model.Parameters;
import java.util.List;
import java.util.Optional;
import javax.annotation.Nonnull;
import static ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider.RESP_PARAM_SUCCESS;
@ -111,7 +110,7 @@ public class ReindexTerminologyCommand extends BaseRequestGeneratingCommand {
@Nonnull
private String getResponseMessage(IBaseParameters response) {
List<String> message = ParametersUtil.getNamedParameterValuesAsString(myFhirCtx, response, "message");
return Strings.join(message, NL);
return String.join(NL, message);
}
public static final String NL = System.getProperty("line.separator");

View File

@ -21,19 +21,17 @@ package ca.uhn.fhir.cli;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.model.primitive.IdDt;
import jakarta.websocket.ClientEndpoint;
import jakarta.websocket.ContainerProvider;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.WebSocketContainer;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.eclipse.jetty.websocket.api.Frame;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import java.net.URI;
@ -46,6 +44,7 @@ public class WebsocketSubscribeCommand extends BaseCommand {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(WebsocketSubscribeCommand.class);
private boolean myQuit;
private Session mySession;
@Override
public String getCommandDescription() {
@ -75,14 +74,13 @@ public class WebsocketSubscribeCommand extends BaseCommand {
IdDt subsId = new IdDt(theCommandLine.getOptionValue("i"));
WebSocketClient client = new WebSocketClient();
SimpleEchoSocket socket = new SimpleEchoSocket(subsId.getIdPart());
try {
client.start();
URI echoUri = new URI(target);
ClientUpgradeRequest request = new ClientUpgradeRequest();
ourLog.info("Connecting to : {}", echoUri);
client.connect(socket, echoUri, request);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
mySession = container.connectToServer(socket, echoUri);
while (!myQuit) {
Thread.sleep(500L);
@ -93,7 +91,9 @@ public class WebsocketSubscribeCommand extends BaseCommand {
throw new CommandFailureException(Msg.code(1537) + e);
} finally {
try {
client.stop();
if (mySession != null) {
mySession.close();
}
} catch (Exception e) {
ourLog.error("Failure", e);
}
@ -103,7 +103,7 @@ public class WebsocketSubscribeCommand extends BaseCommand {
/**
* Basic Echo Client Socket
*/
@WebSocket(maxTextMessageSize = 64 * 1024)
@ClientEndpoint
public class SimpleEchoSocket {
private String mySubsId;
@ -115,37 +115,32 @@ public class WebsocketSubscribeCommand extends BaseCommand {
mySubsId = theSubsId;
}
@OnWebSocketClose
@OnClose
public void onClose(int statusCode, String reason) {
ourLog.info("Received CLOSE status={} reason={}", statusCode, reason);
}
@OnWebSocketConnect
@OnOpen
public void onConnect(Session theSession) {
ourLog.info("Successfully connected");
this.session = theSession;
try {
String sending = "bind " + mySubsId;
LOG_SEND.info("{}", sending);
theSession.getRemote().sendString(sending);
theSession.getBasicRemote().sendText(sending);
} catch (Throwable t) {
ourLog.error("Failure", t);
myQuit = true;
}
}
@OnWebSocketError
@OnError
public void onError(Throwable theError) {
ourLog.error("Websocket error: ", theError);
myQuit = true;
}
@OnWebSocketFrame
public void onFrame(Frame theFrame) {
ourLog.debug("Websocket frame: {}", theFrame);
}
@OnWebSocketMessage
@OnMessage
public void onMessage(String theMsg) {
LOG_RECV.info("{}", theMsg);
}

Some files were not shown because too many files have changed in this diff Show More