Merge remote-tracking branch 'remotes/origin/master' into ks-20200204-quiet-migrate-in-test

This commit is contained in:
Ken Stevens 2020-02-09 15:18:29 -05:00
commit 190e9bed58
42 changed files with 451 additions and 541 deletions

View File

@ -206,65 +206,4 @@
</resources> </resources>
</build> </build>
<profiles>
<profile>
<id>MINI</id>
</profile>
<profile>
<id>SITE</id>
<reporting>
<plugins>
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-checkstyle-plugin</artifactId>
<reportSets> <reportSet> <reports> <report>checkstyle</report> </reports>
</reportSet> </reportSets> <configuration> <linkXRef>false</linkXRef> <sourceDirectories>
<sourceDirectory>hapi-fhir-base/src/main/java</sourceDirectory> </sourceDirectories>
</configuration> </plugin> -->
<!--<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version> <configuration> </configuration> </plugin> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<reportSets>
<reportSet>
<id>normal</id>
<reports>
<report>jxr</report>
</reports>
</reportSet>
<!-- <reportSet> <id>restful-server-example</id> <reports> <report>jxr</report>
</reports> <configuration> <sourcePath>../restful-server-example/src/main/java</sourcePath>
<destDir>${project.reporting.outputDirectory}/rse-xref</destDir> <outputDirectory>tmp</outputDirectory>
<reportOutputDirectory>rse-xref</reportOutputDirectory> </configuration>
</reportSet> -->
</reportSets>
</plugin>
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId>
<version>1.1</version> <configuration> <forceSite>false</forceSite> </configuration>
</plugin> -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<reportSets>
<reportSet>
<reports>
<report>checkstyle</report>
</reports>
</reportSet>
</reportSets>
<configuration>
<linkXRef>false</linkXRef>
<configLocation>${project.basedir}/../src/checkstyle/checkstyle.xml</configLocation>
<!--<sourceDirectories> <sourceDirectory> ${project.basedir}/../hapi-fhir-base/src/main/java
</sourceDirectory> </sourceDirectories> -->
</configuration>
</plugin>
</plugins>
</reporting>
</profile>
</profiles>
</project> </project>

View File

@ -62,41 +62,41 @@ public class ParameterUtil {
*/ */
public static IQueryParameterAnd<?> parseQueryParams(FhirContext theContext, RestSearchParameterTypeEnum paramType, public static IQueryParameterAnd<?> parseQueryParams(FhirContext theContext, RestSearchParameterTypeEnum paramType,
String theUnqualifiedParamName, List<QualifiedParamList> theParameters) { String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
QueryParameterAndBinder binder = null; QueryParameterAndBinder binder;
switch (paramType) { switch (paramType) {
case COMPOSITE: case COMPOSITE:
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
case DATE: case DATE:
binder = new QueryParameterAndBinder(DateAndListParam.class, binder = new QueryParameterAndBinder(DateAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case NUMBER: case NUMBER:
binder = new QueryParameterAndBinder(NumberAndListParam.class, binder = new QueryParameterAndBinder(NumberAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case QUANTITY: case QUANTITY:
binder = new QueryParameterAndBinder(QuantityAndListParam.class, binder = new QueryParameterAndBinder(QuantityAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case REFERENCE: case REFERENCE:
binder = new QueryParameterAndBinder(ReferenceAndListParam.class, binder = new QueryParameterAndBinder(ReferenceAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case STRING: case STRING:
binder = new QueryParameterAndBinder(StringAndListParam.class, binder = new QueryParameterAndBinder(StringAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case TOKEN: case TOKEN:
binder = new QueryParameterAndBinder(TokenAndListParam.class, binder = new QueryParameterAndBinder(TokenAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case URI: case URI:
binder = new QueryParameterAndBinder(UriAndListParam.class, binder = new QueryParameterAndBinder(UriAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case HAS: case HAS:
binder = new QueryParameterAndBinder(HasAndListParam.class, binder = new QueryParameterAndBinder(HasAndListParam.class,
Collections.<Class<? extends IQueryParameterType>>emptyList()); Collections.emptyList());
break; break;
case SPECIAL: case SPECIAL:
binder = new QueryParameterAndBinder(SpecialAndListParam.class, binder = new QueryParameterAndBinder(SpecialAndListParam.class,
@ -106,7 +106,6 @@ public class ParameterUtil {
throw new IllegalArgumentException("Parameter '" + theUnqualifiedParamName + "' has type " + paramType + " which is currently not supported."); throw new IllegalArgumentException("Parameter '" + theUnqualifiedParamName + "' has type " + paramType + " which is currently not supported.");
} }
// FIXME null access
return binder.parse(theContext, theUnqualifiedParamName, theParameters); return binder.parse(theContext, theUnqualifiedParamName, theParameters);
} }

View File

@ -76,24 +76,6 @@ public class ElementUtil {
return true; return true;
} }
/*
public static <T> void validateAllElementsAreOfTypeOrThrowClassCastExceptionForModelSetter(List<T> theList, Class<T> theType) {
if (theList == null) {
return;
}
for (T next : theList) {
if (next != null && theType.isAssignableFrom(next.getClass()) == false) {
StringBuilder b = new StringBuilder();
b.append("Failed to set invalid value, found element in list of type ");
b.append(next.getClass().getSimpleName());
b.append(" but expected ");
b.append(theType.getName());
throw new ClassCastException(b.toString());
}
}
}
*/
public static boolean isEmpty(List<? extends IBase> theElements) { public static boolean isEmpty(List<? extends IBase> theElements) {
if (theElements == null) { if (theElements == null) {
return true; return true;
@ -141,8 +123,7 @@ public class ElementUtil {
//@SuppressWarnings("unchecked") //@SuppressWarnings("unchecked")
private static <T extends IElement> void addElement(ArrayList<T> retVal, IElement next, Class<T> theType) { private static <T extends IElement> void addElement(ArrayList<T> retVal, IElement next, Class<T> theType) {
//FIXME There seems to be an error on theType == null => if (theType != null|| theType.isAssignableFrom if (theType != null && theType.isAssignableFrom(next.getClass())) {
if (theType == null|| theType.isAssignableFrom(next.getClass())) {
retVal.add(theType.cast(next)); retVal.add(theType.cast(next));
} }
if (next instanceof ICompositeElement) { if (next instanceof ICompositeElement) {

View File

@ -39,12 +39,17 @@ import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema; import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory; import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator; import javax.xml.validation.Validator;
import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.StringReader; import java.io.StringReader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.*; import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class SchemaBaseValidator implements IValidatorModule { public class SchemaBaseValidator implements IValidatorModule {
public static final String RESOURCES_JAR_NOTE = "Note that as of HAPI FHIR 1.2, DSTU2 validation files are kept in a separate JAR (hapi-fhir-validation-resources-XXX.jar) which must be added to your classpath. See the HAPI FHIR download page for more information."; public static final String RESOURCES_JAR_NOTE = "Note that as of HAPI FHIR 1.2, DSTU2 validation files are kept in a separate JAR (hapi-fhir-validation-resources-XXX.jar) which must be added to your classpath. See the HAPI FHIR download page for more information.";
@ -179,18 +184,20 @@ public class SchemaBaseValidator implements IValidatorModule {
input.setPublicId(thePublicId); input.setPublicId(thePublicId);
input.setSystemId(theSystemId); input.setSystemId(theSystemId);
input.setBaseURI(theBaseURI); input.setBaseURI(theBaseURI);
// String pathToBase = "ca/uhn/fhir/model/" + myVersion + "/schema/" + theSystemId;
String pathToBase = myCtx.getVersion().getPathToSchemaDefinitions() + '/' + theSystemId; String pathToBase = myCtx.getVersion().getPathToSchemaDefinitions() + '/' + theSystemId;
ourLog.debug("Loading referenced schema file: " + pathToBase); ourLog.debug("Loading referenced schema file: " + pathToBase);
InputStream baseIs = FhirValidator.class.getResourceAsStream(pathToBase); try (InputStream baseIs = FhirValidator.class.getResourceAsStream(pathToBase)) {
if (baseIs == null) { if (baseIs == null) {
throw new InternalErrorException("Schema file not found: " + pathToBase); throw new InternalErrorException("Schema file not found: " + pathToBase);
} }
input.setByteStream(baseIs); byte[] bytes = IOUtils.toByteArray(baseIs);
//FIXME resource leak input.setByteStream(new ByteArrayInputStream(bytes));
} catch (IOException e) {
throw new InternalErrorException(e);
}
return input; return input;
} }

View File

@ -85,13 +85,11 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
public HttpClient getNativeHttpClient() { public HttpClient getNativeHttpClient() {
if (myHttpClient == null) { if (myHttpClient == null) {
//FIXME potential resoource leak
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000,
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
connectionManager.setMaxTotal(getPoolMaxTotal()); connectionManager.setMaxTotal(getPoolMaxTotal());
connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute()); connectionManager.setDefaultMaxPerRoute(getPoolMaxPerRoute());
// @formatter:off
//TODO: Use of a deprecated method should be resolved. //TODO: Use of a deprecated method should be resolved.
RequestConfig defaultRequestConfig = RequestConfig defaultRequestConfig =
RequestConfig.custom() RequestConfig.custom()
@ -114,7 +112,6 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
} }
myHttpClient = builder.build(); myHttpClient = builder.build();
// @formatter:on
} }
@ -128,7 +125,7 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
/** /**
* Only allows to set an instance of type org.apache.http.client.HttpClient * Only allows to set an instance of type org.apache.http.client.HttpClient
* @see ca.uhn.fhir.rest.client.api.IRestfulClientFactory#setHttpClient(ca.uhn.fhir.rest.client.api.IHttpClient) * @see ca.uhn.fhir.rest.client.api.IRestfulClientFactory#setHttpClient(Object)
*/ */
@Override @Override
public synchronized void setHttpClient(Object theHttpClient) { public synchronized void setHttpClient(Object theHttpClient) {

View File

@ -1796,11 +1796,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
if (rootSs == null) { if (rootSs == null) {
rootSs = nextSortSpec; rootSs = nextSortSpec;
} else { } else {
// FIXME lastSs is null never set
// TODO unused assignment
lastSs.setChain(nextSortSpec); lastSs.setChain(nextSortSpec);
} }
// TODO unused assignment
lastSs = nextSortSpec; lastSs = nextSortSpec;
} }
if (rootSs != null) { if (rootSs != null) {

View File

@ -1,5 +1,18 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
@ -22,20 +35,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* #L% * #L%
*/ */
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public abstract class BaseQueryParameter implements IParameter { public abstract class BaseQueryParameter implements IParameter {
public abstract List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException; public abstract List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException;
@ -44,12 +43,6 @@ public abstract class BaseQueryParameter implements IParameter {
public abstract RestSearchParameterTypeEnum getParamType(); public abstract RestSearchParameterTypeEnum getParamType();
/**
* Parameter should return true if {@link #parse(FhirContext, List)} should be called even if the query string
* contained no values for the given parameter
*/
public abstract boolean handlesMissing();
@Override @Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore for now // ignore for now
@ -57,8 +50,6 @@ public abstract class BaseQueryParameter implements IParameter {
public abstract boolean isRequired(); public abstract boolean isRequired();
public abstract Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException;
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
if (theSourceClientArgument == null) { if (theSourceClientArgument == null) {
@ -79,11 +70,7 @@ public abstract class BaseQueryParameter implements IParameter {
String qualifier = nextParamEntry.getQualifier(); String qualifier = nextParamEntry.getQualifier();
String paramName = isNotBlank(qualifier) ? getName() + qualifier : getName(); String paramName = isNotBlank(qualifier) ? getName() + qualifier : getName();
List<String> paramValues = theTargetQueryArguments.get(paramName); List<String> paramValues = theTargetQueryArguments.computeIfAbsent(paramName, k -> new ArrayList<>(value.size()));
if (paramValues == null) {
paramValues = new ArrayList<>(value.size());
theTargetQueryArguments.put(paramName, paramValues);
}
paramValues.add(b.toString()); paramValues.add(b.toString());
} }

View File

@ -19,16 +19,23 @@ package ca.uhn.fhir.rest.client.method;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import java.util.*;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.annotation.IncludeParam; import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class IncludeParameter extends BaseQueryParameter { class IncludeParameter extends BaseQueryParameter {
@ -37,11 +44,12 @@ class IncludeParameter extends BaseQueryParameter {
private Class<?> mySpecType; private Class<?> mySpecType;
private boolean myReverse; private boolean myReverse;
public IncludeParameter(IncludeParam theAnnotation, Class<? extends Collection<Include>> theInstantiableCollectionType, Class<?> theSpecType) { public IncludeParameter(IncludeParam theAnnotation, Class<? extends Collection<Include>> theInstantiableCollectionType, Class<?> theSpecType) {
myInstantiableCollectionType = theInstantiableCollectionType; myInstantiableCollectionType = theInstantiableCollectionType;
myReverse = theAnnotation.reverse(); myReverse = theAnnotation.reverse();
if (theAnnotation.allow().length > 0) { if (theAnnotation.allow().length > 0) {
myAllow = new HashSet<String>(); myAllow = new HashSet<>();
for (String next : theAnnotation.allow()) { for (String next : theAnnotation.allow()) {
if (next != null) { if (next != null) {
myAllow.add(next); myAllow.add(next);
@ -61,7 +69,7 @@ class IncludeParameter extends BaseQueryParameter {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException { public List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException {
ArrayList<QualifiedParamList> retVal = new ArrayList<QualifiedParamList>(); ArrayList<QualifiedParamList> retVal = new ArrayList<>();
if (myInstantiableCollectionType == null) { if (myInstantiableCollectionType == null) {
if (mySpecType == Include.class) { if (mySpecType == Include.class) {
@ -105,58 +113,9 @@ class IncludeParameter extends BaseQueryParameter {
return null; return null;
} }
@Override
public boolean handlesMissing() {
return true;
}
@Override @Override
public boolean isRequired() { public boolean isRequired() {
return false; return false;
} }
@Override
public Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
Collection<Include> retValCollection = null;
if (myInstantiableCollectionType != null) {
try {
retValCollection = myInstantiableCollectionType.newInstance();
} catch (Exception e) {
throw new InternalErrorException("Failed to instantiate " + myInstantiableCollectionType.getName(), e);
}
}
for (QualifiedParamList nextParamList : theString) {
if (nextParamList.isEmpty()) {
continue;
}
if (nextParamList.size() > 1) {
throw new InvalidRequestException(theContext.getLocalizer().getMessage(IncludeParameter.class, "orIncludeInRequest"));
}
boolean recurse = Constants.PARAM_INCLUDE_QUALIFIER_RECURSE.equals(nextParamList.getQualifier());
String value = nextParamList.get(0);
if (myAllow != null && !myAllow.isEmpty()) {
if (!myAllow.contains(value)) {
if (!myAllow.contains("*")) {
String msg = theContext.getLocalizer().getMessage(IncludeParameter.class, "invalidIncludeNameInRequest", value, new TreeSet<String>(myAllow).toString(), getName());
throw new InvalidRequestException(msg);
}
}
}
if (myInstantiableCollectionType == null) {
if (mySpecType == String.class) {
return value;
}
return new Include(value, recurse);
}
//FIXME null access
retValCollection.add(new Include(value, recurse));
}
return retValCollection;
}
} }

View File

@ -1,29 +1,51 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import java.io.*; import ca.uhn.fhir.context.FhirVersionEnum;
import java.lang.annotation.Annotation; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import java.lang.reflect.Method; import ca.uhn.fhir.model.api.IResource;
import java.util.*; import ca.uhn.fhir.model.api.Include;
import java.util.Map.Entry; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.method.OperationParameter.IOperationParamConverter; import ca.uhn.fhir.rest.client.method.OperationParameter.IOperationParamConverter;
import ca.uhn.fhir.rest.param.ParameterUtil; import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.param.binder.CollectionBinder; import ca.uhn.fhir.rest.param.binder.CollectionBinder;
import ca.uhn.fhir.util.*; import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.UrlUtil;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
* #%L * #%L
@ -45,7 +67,6 @@ import ca.uhn.fhir.util.*;
* #L% * #L%
*/ */
@SuppressWarnings("deprecation")
public class MethodUtil { public class MethodUtil {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
@ -288,33 +309,25 @@ public class MethodUtil {
specType = parameterType; specType = parameterType;
} }
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType);
specType);
} else if (nextAnnotation instanceof ResourceParam) { } else if (nextAnnotation instanceof ResourceParam) {
if (IBaseResource.class.isAssignableFrom(parameterType)) { if (IBaseResource.class.isAssignableFrom(parameterType)) {
// good // good
} else if (String.class.equals(parameterType)) { } else if (String.class.equals(parameterType)) {
// good // good
} else if (byte[].class.equals(parameterType)) {
// good
} else if (EncodingEnum.class.equals(parameterType)) {
// good
} else { } else {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
b.append("Method '"); b.append("Method '");
b.append(theMethod.getName()); b.append(theMethod.getName());
b.append("' is annotated with @"); b.append("' is annotated with @");
b.append(ResourceParam.class.getSimpleName()); b.append(ResourceParam.class.getSimpleName());
b.append(" but has a type that is not an implemtation of "); b.append(" but has a type that is not an implementation of ");
b.append(IBaseResource.class.getCanonicalName()); b.append(IBaseResource.class.getCanonicalName());
b.append(" or String or byte[]");
throw new ConfigurationException(b.toString()); throw new ConfigurationException(b.toString());
} }
param = new ResourceParameter(parameterType); param = new ResourceParameter(parameterType);
} else if (nextAnnotation instanceof IdParam) { } else if (nextAnnotation instanceof IdParam) {
param = new NullParameter(); param = new NullParameter();
} else if (nextAnnotation instanceof ServerBase) {
param = new ServerBaseParamBinder();
} else if (nextAnnotation instanceof Elements) { } else if (nextAnnotation instanceof Elements) {
param = new ElementsParameter(); param = new ElementsParameter();
} else if (nextAnnotation instanceof Since) { } else if (nextAnnotation instanceof Since) {
@ -345,19 +358,6 @@ public class MethodUtil {
} }
param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE, param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE,
Constants.EXTOP_VALIDATE_MODE, 0, 1).setConverter(new IOperationParamConverter() { Constants.EXTOP_VALIDATE_MODE, 0, 1).setConverter(new IOperationParamConverter() {
@Override
public Object incomingServer(Object theObject) {
if (isNotBlank(theObject.toString())) {
ValidationModeEnum retVal = ValidationModeEnum
.forCode(theObject.toString());
if (retVal == null) {
OperationParameter.throwInvalidMode(theObject.toString());
}
return retVal;
}
return null;
}
@Override @Override
public Object outgoingClient(Object theObject) { public Object outgoingClient(Object theObject) {
return ParametersUtil.createString(theContext, return ParametersUtil.createString(theContext,
@ -372,10 +372,6 @@ public class MethodUtil {
} }
param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE, param = new OperationParameter(theContext, Constants.EXTOP_VALIDATE,
Constants.EXTOP_VALIDATE_PROFILE, 0, 1).setConverter(new IOperationParamConverter() { Constants.EXTOP_VALIDATE_PROFILE, 0, 1).setConverter(new IOperationParamConverter() {
@Override
public Object incomingServer(Object theObject) {
return theObject.toString();
}
@Override @Override
public Object outgoingClient(Object theObject) { public Object outgoingClient(Object theObject) {

View File

@ -191,8 +191,6 @@ public class OperationParameter implements IParameter {
interface IOperationParamConverter { interface IOperationParamConverter {
Object incomingServer(Object theObject);
Object outgoingClient(Object theObject); Object outgoingClient(Object theObject);
} }
@ -203,13 +201,6 @@ public class OperationParameter implements IParameter {
Validate.isTrue(mySearchParameterBinding != null); Validate.isTrue(mySearchParameterBinding != null);
} }
@Override
public Object incomingServer(Object theObject) {
IPrimitiveType<?> obj = (IPrimitiveType<?>) theObject;
List<QualifiedParamList> paramList = Collections.singletonList(QualifiedParamList.splitQueryStringByCommasIgnoreEscape(null, obj.getValueAsString()));
return mySearchParameterBinding.parse(myContext, paramList);
}
@Override @Override
public Object outgoingClient(Object theObject) { public Object outgoingClient(Object theObject) {
IQueryParameterType obj = (IQueryParameterType) theObject; IQueryParameterType obj = (IQueryParameterType) theObject;

View File

@ -156,26 +156,11 @@ public class SearchParameter extends BaseQueryParameter {
return myType; return myType;
} }
@Override
public boolean handlesMissing() {
return false;
}
@Override @Override
public boolean isRequired() { public boolean isRequired() {
return myRequired; return myRequired;
} }
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.rest.param.IParameter#parse(java.util.List)
*/
@Override
public Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
return myParamBinder.parse(theContext, getName(), theString);
}
public void setChainlists(String[] theChainWhitelist) { public void setChainlists(String[] theChainWhitelist) {
myQualifierWhitelist = new HashSet<>(theChainWhitelist.length); myQualifierWhitelist = new HashSet<>(theChainWhitelist.length);
myQualifierWhitelist.add(QUALIFIER_ANY_TYPE); myQualifierWhitelist.add(QUALIFIER_ANY_TYPE);

View File

@ -1,47 +0,0 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Client Framework
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* 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%
*/
import java.lang.reflect.Method;
import java.util.*;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
class ServerBaseParamBinder implements IParameter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerBaseParamBinder.class);
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
/*
* Does nothing, since we just ignore serverbase arguments
*/
ourLog.trace("Ignoring server base argument: {}", theSourceClientArgument);
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore for now
}
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jaxrs.server.util; package ca.uhn.fhir.jaxrs.server.util;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.server.ParseAction;
import ca.uhn.fhir.rest.server.RestfulResponse;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.List;
import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
@ -21,23 +41,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import java.io.*;
import java.util.List;
import java.util.Map.Entry;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*;
import ca.uhn.fhir.rest.api.server.ParseAction;
import ca.uhn.fhir.rest.server.RestfulResponse;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
/** /**
* The JaxRsResponse is a jax-rs specific implementation of the RestfulResponse. * The JaxRsResponse is a jax-rs specific implementation of the RestfulResponse.
@ -60,8 +63,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
* by the server. * by the server.
*/ */
@Override @Override
public Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) public Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) {
throws UnsupportedEncodingException, IOException {
return new StringWriter(); return new StringWriter();
} }
@ -78,7 +80,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
} }
@Override @Override
public Response sendAttachmentResponse(IBaseBinary bin, int statusCode, String contentType) throws IOException { public Object sendAttachmentResponse(IBaseBinary bin, int statusCode, String contentType) {
ResponseBuilder response = buildResponse(statusCode); ResponseBuilder response = buildResponse(statusCode);
if (bin.getContent() != null && bin.getContent().length > 0) { if (bin.getContent() != null && bin.getContent().length > 0) {
response.header(Constants.HEADER_CONTENT_TYPE, contentType).entity(bin.getContent()); response.header(Constants.HEADER_CONTENT_TYPE, contentType).entity(bin.getContent());

View File

@ -199,26 +199,7 @@ public class JaxRsPatientProviderDstu3Test {
//assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND); //assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND);
} }
} }
/** Transaction - Server */
@Ignore
@Test
public void testTransaction() {
Bundle bundle = new Bundle();
BundleEntryComponent entry = bundle.addEntry();
final Patient existing = new Patient();
existing.getName().get(0).setFamily("Created with bundle");
entry.setResource(existing);
// FIXME ?
// BoundCodeDt<BundleEntryTransactionMethodEnum> theTransactionOperation =
// new BoundCodeDt(
// BundleEntryTransactionMethodEnum.VALUESET_BINDER,
// BundleEntryTransactionMethodEnum.POST);
// entry.setTransactionMethod(theTransactionOperation);
Bundle response = client.transaction().withBundle(bundle).execute();
}
/** Conformance - Server */ /** Conformance - Server */
@Test @Test
@Ignore @Ignore

View File

@ -1097,11 +1097,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override @Override
public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) { public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) {
theParams.setLoadSynchronousUpTo(10000);
ISearchBuilder builder = mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType()); ISearchBuilder builder = mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
// FIXME: fail if too many results
HashSet<ResourcePersistentId> retVal = new HashSet<>(); HashSet<ResourcePersistentId> retVal = new HashSet<>();
String uuid = UUID.randomUUID().toString(); String uuid = UUID.randomUUID().toString();

View File

@ -21,12 +21,12 @@ package ca.uhn.fhir.jpa.dao;
*/ */
import ca.uhn.fhir.model.dstu2.resource.StructureDefinition; import ca.uhn.fhir.model.dstu2.resource.StructureDefinition;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class FhirResourceDaoStructureDefinitionDstu2 extends BaseHapiFhirResourceDao<StructureDefinition> implements IFhirResourceDaoStructureDefinition<StructureDefinition> { public class FhirResourceDaoStructureDefinitionDstu2 extends BaseHapiFhirResourceDao<StructureDefinition> implements IFhirResourceDaoStructureDefinition<StructureDefinition> {
@Override @Override
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theName) { public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theName) {
// FIXME: implement throw new InvalidRequestException("Snapshot generation not supported for DSTU2");
return null;
} }
} }

View File

@ -32,7 +32,6 @@ import ca.uhn.fhir.jpa.model.entity.ForcedId;
public interface IForcedIdDao extends JpaRepository<ForcedId, Long> { public interface IForcedIdDao extends JpaRepository<ForcedId, Long> {
// FIXME: JA We should log a performance warning if this is used since it's not indexed
@Query("SELECT f.myResourcePid FROM ForcedId f WHERE myForcedId IN (:forced_id)") @Query("SELECT f.myResourcePid FROM ForcedId f WHERE myForcedId IN (:forced_id)")
List<Long> findByForcedId(@Param("forced_id") Collection<String> theForcedId); List<Long> findByForcedId(@Param("forced_id") Collection<String> theForcedId);

View File

@ -57,7 +57,6 @@ public class JpaPreResourceAccessDetails implements IPreResourceAccessDetails {
public IBaseResource getResource(int theIndex) { public IBaseResource getResource(int theIndex) {
if (myResources == null) { if (myResources == null) {
myResources = new ArrayList<>(myResourcePids.size()); myResources = new ArrayList<>(myResourcePids.size());
// FIXME: JA don't call interceptors for this query
mySearchBuilderSupplier.call().loadResourcesByPid(myResourcePids, Collections.emptySet(), myResources, false, null); mySearchBuilderSupplier.call().loadResourcesByPid(myResourcePids, Collections.emptySet(), myResources, false, null);
} }
return myResources.get(theIndex); return myResources.get(theIndex);

View File

@ -1414,7 +1414,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc, ApplicationCo
TermConceptMapGroupElement termConceptMapGroupElement; TermConceptMapGroupElement termConceptMapGroupElement;
for (ConceptMap.SourceElementComponent element : group.getElement()) { for (ConceptMap.SourceElementComponent element : group.getElement()) {
if (isBlank(element.getCode())) { if (isBlank(element.getCode())) {
// FIXME: JA - send this to an interceptor message so it can be output
continue; continue;
} }
termConceptMapGroupElement = new TermConceptMapGroupElement(); termConceptMapGroupElement = new TermConceptMapGroupElement();

View File

@ -388,7 +388,7 @@ public class TermLoaderSvcImpl implements ITermLoaderSvc {
} }
} }
// FIXME: DM 2019-09-13 - Manually add EXTERNAL_COPYRIGHT_NOTICE property until Regenstrief adds this to loinc.xml // TODO: DM 2019-09-13 - Manually add EXTERNAL_COPYRIGHT_NOTICE property until Regenstrief adds this to loinc.xml
if (!propertyNamesToTypes.containsKey("EXTERNAL_COPYRIGHT_NOTICE")) { if (!propertyNamesToTypes.containsKey("EXTERNAL_COPYRIGHT_NOTICE")) {
String externalCopyRightNoticeCode = "EXTERNAL_COPYRIGHT_NOTICE"; String externalCopyRightNoticeCode = "EXTERNAL_COPYRIGHT_NOTICE";
CodeSystem.PropertyType externalCopyRightNoticeType = CodeSystem.PropertyType.STRING; CodeSystem.PropertyType externalCopyRightNoticeType = CodeSystem.PropertyType.STRING;

View File

@ -44,14 +44,11 @@ public interface ITermLoaderSvc {
UploadStatistics loadSnomedCt(List<FileDescriptor> theFiles, RequestDetails theRequestDetails); UploadStatistics loadSnomedCt(List<FileDescriptor> theFiles, RequestDetails theRequestDetails);
// FIXME: remove the default implementation before 4.1.0 UploadStatistics loadCustom(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails);
default UploadStatistics loadCustom(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { return null; };
// FIXME: remove the default implementation before 4.1.0 UploadStatistics loadDeltaAdd(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails);
default UploadStatistics loadDeltaAdd(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { return null; };
// FIXME: remove the default implementation before 4.1.0 UploadStatistics loadDeltaRemove(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails);
default UploadStatistics loadDeltaRemove(String theSystem, List<FileDescriptor> theFiles, RequestDetails theRequestDetails) { return null; };
interface FileDescriptor { interface FileDescriptor {

View File

@ -86,7 +86,7 @@ public class LoincHandler implements IRecordHandler {
concept.addPropertyString(nextPropertyName, nextPropertyValue); concept.addPropertyString(nextPropertyName, nextPropertyValue);
break; break;
case CODING: case CODING:
// FIXME: handle "Ser/Plas^Donor" // TODO: handle "Ser/Plas^Donor"
String propertyValue = nextPropertyValue; String propertyValue = nextPropertyValue;
if (nextPropertyName.equals("COMPONENT")) { if (nextPropertyName.equals("COMPONENT")) {
if (propertyValue.contains("^")) { if (propertyValue.contains("^")) {

View File

@ -47,7 +47,6 @@ import static org.junit.Assert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class) @RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {TestR4ConfigWithElasticSearch.class}) @ContextConfiguration(classes = {TestR4ConfigWithElasticSearch.class})
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
@Ignore // FIXME: remove
public class FhirResourceDaoR4SearchWithElasticSearchTest extends BaseJpaTest { public class FhirResourceDaoR4SearchWithElasticSearchTest extends BaseJpaTest {
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system"; public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set"; public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";

View File

@ -200,13 +200,7 @@ public class SearchCoordinatorSvcImplTest {
search.setStatus(SearchStatusEnum.LOADING); search.setStatus(SearchStatusEnum.LOADING);
return Optional.of(search); return Optional.of(search);
}); });
IBundleProvider result = mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null);
assertNotNull(result.getUuid());
assertEquals(null, result.size());
List<IBaseResource> resources;
when(mySearchCacheSvc.save(any())).thenAnswer(t -> { when(mySearchCacheSvc.save(any())).thenAnswer(t -> {
Search search = t.getArgument(0, Search.class); Search search = t.getArgument(0, Search.class);
myCurrentSearch = search; myCurrentSearch = search;
@ -216,7 +210,11 @@ public class SearchCoordinatorSvcImplTest {
IFhirResourceDao dao = myCallingDao; IFhirResourceDao dao = myCallingDao;
when(myDaoRegistry.getResourceDao(any(String.class))).thenReturn(dao); when(myDaoRegistry.getResourceDao(any(String.class))).thenReturn(dao);
resources = result.getResources(0, 100000); IBundleProvider result = mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null);
assertNotNull(result.getUuid());
assertEquals(null, result.size());
List<IBaseResource> resources = result.getResources(0, 100000);
assertEquals(790, resources.size()); assertEquals(790, resources.size());
assertEquals("10", resources.get(0).getIdElement().getValueAsString()); assertEquals("10", resources.get(0).getIdElement().getValueAsString());
assertEquals("799", resources.get(789).getIdElement().getValueAsString()); assertEquals("799", resources.get(789).getIdElement().getValueAsString());

View File

@ -52,12 +52,6 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
private static final int MAX_PROFILE_LENGTH = 200; private static final int MAX_PROFILE_LENGTH = 200;
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
// @Transient
// private transient byte[] myResource;
//
// @Transient
// private transient ResourceEncodingEnum myEncoding;
/** /**
* Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB * Holds the narrative text only - Used for Fulltext searching but not directly stored in the DB
*/ */

View File

@ -19,17 +19,21 @@ package ca.uhn.fhir.rest.api.server;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import java.io.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import org.hl7.fhir.instance.model.api.IBaseBinary;
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.IOException;
import java.io.Writer;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
public interface IRestfulResponse { public interface IRestfulResponse {
Object streamResponseAsResource(IBaseResource theActualResourceToReturn, boolean thePrettyPrint, Set<SummaryEnum> theSummaryMode, int theStatusCode, String theStatusMessage, boolean theRespondGzip, boolean theAddContentLocation) throws IOException; Object streamResponseAsResource(IBaseResource theActualResourceToReturn, boolean thePrettyPrint, Set<SummaryEnum> theSummaryMode, int theStatusCode, String theStatusMessage, boolean theRespondGzip, boolean theAddContentLocation) throws IOException;
@ -40,7 +44,7 @@ public interface IRestfulResponse {
*/ */
Object returnResponse(ParseAction<?> outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException; Object returnResponse(ParseAction<?> outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException;
Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException; Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) throws IOException;
Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException; Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException;

View File

@ -28,11 +28,16 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.PreferHeader;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.IRestfulResponse; import ca.uhn.fhir.rest.api.server.IRestfulResponse;
import ca.uhn.fhir.rest.api.server.IRestfulServer; import ca.uhn.fhir.rest.api.server.IRestfulServer;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.method.ElementsParameter; import ca.uhn.fhir.rest.server.method.ElementsParameter;
@ -40,7 +45,13 @@ import ca.uhn.fhir.rest.server.method.SummaryEnumParameter;
import ca.uhn.fhir.util.BinaryUtil; import ca.uhn.fhir.util.BinaryUtil;
import ca.uhn.fhir.util.DateUtils; import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.UrlUtil; import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.instance.model.api.*; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IDomainResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -51,7 +62,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.*; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.replace;
import static org.apache.commons.lang3.StringUtils.trim;
public class RestfulServerUtils { public class RestfulServerUtils {
static final Pattern ACCEPT_HEADER_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9+.*/-]+)\\s*(;\\s*([a-zA-Z]+)\\s*=\\s*([a-zA-Z0-9.]+)\\s*)?(,?)"); static final Pattern ACCEPT_HEADER_PATTERN = Pattern.compile("\\s*([a-zA-Z0-9+.*/-]+)\\s*(;\\s*([a-zA-Z]+)\\s*=\\s*([a-zA-Z0-9.]+)\\s*)?(,?)");
@ -754,12 +768,12 @@ public class RestfulServerUtils {
} }
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theAddContentLocationHeader, public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theAddContentLocationHeader,
boolean respondGzip, RequestDetails theRequestDetails) throws IOException { boolean respondGzip, RequestDetails theRequestDetails) throws IOException {
return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, null, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null); return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, null, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null);
} }
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int theStatusCode, String theStatusMessage, public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int theStatusCode, String theStatusMessage,
boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType<Date> theOperationResourceLastUpdated) boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType<Date> theOperationResourceLastUpdated)
throws IOException { throws IOException {
IRestfulResponse response = theRequestDetails.getResponse(); IRestfulResponse response = theRequestDetails.getResponse();
@ -895,23 +909,10 @@ public class RestfulServerUtils {
IParser parser = getNewParser(theServer.getFhirContext(), forVersion, theRequestDetails); IParser parser = getNewParser(theServer.getFhirContext(), forVersion, theRequestDetails);
parser.encodeResourceToWriter(theResource, writer); parser.encodeResourceToWriter(theResource, writer);
} }
//FIXME resource leak
return response.sendWriterResponse(theStatusCode, contentType, charset, writer); return response.sendWriterResponse(theStatusCode, contentType, charset, writer);
} }
// static Integer tryToExtractNamedParameter(HttpServletRequest theRequest, String name) {
// String countString = theRequest.getParameter(name);
// Integer count = null;
// if (isNotBlank(countString)) {
// try {
// count = Integer.parseInt(countString);
// } catch (NumberFormatException e) {
// ourLog.debug("Failed to parse _count value '{}': {}", countString, e);
// }
// }
// return count;
// }
public static String createEtag(String theVersionId) { public static String createEtag(String theVersionId) {
return "W/\"" + theVersionId + '"'; return "W/\"" + theVersionId + '"';
} }

View File

@ -154,7 +154,7 @@ class IncludeParameter extends BaseQueryParameter {
} }
return new Include(value, recurse); return new Include(value, recurse);
} }
//FIXME null access
retValCollection.add(new Include(value, recurse)); retValCollection.add(new Include(value, recurse));
} }

View File

@ -192,7 +192,7 @@ public class MethodUtil {
b.append(theMethod.getName()); b.append(theMethod.getName());
b.append("' is annotated with @"); b.append("' is annotated with @");
b.append(ResourceParam.class.getSimpleName()); b.append(ResourceParam.class.getSimpleName());
b.append(" but has a type that is not an implemtation of "); b.append(" but has a type that is not an implementation of ");
b.append(IBaseResource.class.getCanonicalName()); b.append(IBaseResource.class.getCanonicalName());
b.append(" or String or byte[]"); b.append(" or String or byte[]");
throw new ConfigurationException(b.toString()); throw new ConfigurationException(b.toString());

View File

@ -20,23 +20,22 @@ package ca.uhn.fhir.rest.server.servlet;
* #L% * #L%
*/ */
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.List;
import java.util.Map.Entry;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.server.ParseAction; import ca.uhn.fhir.rest.api.server.ParseAction;
import ca.uhn.fhir.rest.server.RestfulResponse; import ca.uhn.fhir.rest.server.RestfulResponse;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map.Entry;
import java.util.zip.GZIPOutputStream;
public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetails> { public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetails> {
@ -48,23 +47,23 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
} }
@Override @Override
public Object sendAttachmentResponse(IBaseBinary bin, int stausCode, String contentType) throws IOException { public OutputStream sendAttachmentResponse(IBaseBinary theBinary, int theStatusCode, String contentType) throws IOException {
addHeaders(); addHeaders();
HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse();
theHttpResponse.setStatus(stausCode); theHttpResponse.setStatus(theStatusCode);
theHttpResponse.setContentType(contentType); theHttpResponse.setContentType(contentType);
theHttpResponse.setCharacterEncoding(null); theHttpResponse.setCharacterEncoding(null);
if (bin.getContent() == null || bin.getContent().length == 0) { if (theBinary.getContent() == null || theBinary.getContent().length == 0) {
return theHttpResponse.getOutputStream(); return theHttpResponse.getOutputStream();
} }
theHttpResponse.setContentLength(bin.getContent().length); theHttpResponse.setContentLength(theBinary.getContent().length);
ServletOutputStream oos = theHttpResponse.getOutputStream(); ServletOutputStream oos = theHttpResponse.getOutputStream();
oos.write(bin.getContent()); oos.write(theBinary.getContent());
return oos; return oos;
} }
@Override @Override
public Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException { public Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) throws IOException {
addHeaders(); addHeaders();
HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse(); HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse();
theHttpResponse.setCharacterEncoding(theCharset); theHttpResponse.setCharacterEncoding(theCharset);
@ -72,7 +71,7 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
theHttpResponse.setContentType(theContentType); theHttpResponse.setContentType(theContentType);
if (theRespondGzip) { if (theRespondGzip) {
theHttpResponse.addHeader(Constants.HEADER_CONTENT_ENCODING, Constants.ENCODING_GZIP); theHttpResponse.addHeader(Constants.HEADER_CONTENT_ENCODING, Constants.ENCODING_GZIP);
return new OutputStreamWriter(new GZIPOutputStream(theHttpResponse.getOutputStream()), Constants.CHARSET_NAME_UTF8); return new OutputStreamWriter(new GZIPOutputStream(theHttpResponse.getOutputStream()), StandardCharsets.UTF_8);
} }
return theHttpResponse.getWriter(); return theHttpResponse.getWriter();
} }
@ -96,7 +95,7 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
} }
@Override @Override
public final Object sendWriterResponse(int theStatus, String theContentType, String theCharset, Writer theWriter) throws IOException { public final Writer sendWriterResponse(int theStatus, String theContentType, String theCharset, Writer theWriter) {
return theWriter; return theWriter;
} }

View File

@ -1170,44 +1170,6 @@ public class JsonParserDstu2_1Test {
assertEquals("<Linkage xmlns=\"http://hl7.org/fhir\"><item><resource><display value=\"FOO\"/></resource></item></Linkage>", out); assertEquals("<Linkage xmlns=\"http://hl7.org/fhir\"><item><resource><display value=\"FOO\"/></resource></item></Linkage>", out);
} }
// FIXME: this should pass
@Test
@Ignore
public void testNamespacePreservationEncode() throws Exception {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
//@formatter:on
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
// TODO: this should pass
@Test
@Ignore
public void testNamespacePreservationParse() throws Exception {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
XhtmlNode div = parsed.getText().getDiv();
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", div.getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>", encoded);
}
@Test @Test
public void testOmitResourceId() { public void testOmitResourceId() {
Patient p = new Patient(); Patient p = new Patient();

View File

@ -41,9 +41,6 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
/**
* Created by dsotnikov on 2/25/2014.
*/
public class IncludeDstu2Test { public class IncludeDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeDstu2Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeDstu2Test.class);
@ -310,9 +307,6 @@ public class IncludeDstu2Test {
} }
/**
* Created by dsotnikov on 2/25/2014.
*/
public static class DummyPatientResourceProvider implements IResourceProvider { public static class DummyPatientResourceProvider implements IResourceProvider {
@Search(queryName = "containedInclude") @Search(queryName = "containedInclude")

View File

@ -1593,44 +1593,6 @@ public class JsonParserDstu3Test {
assertEquals("<Linkage xmlns=\"http://hl7.org/fhir\"><item><resource><display value=\"FOO\"/></resource></item></Linkage>", out); assertEquals("<Linkage xmlns=\"http://hl7.org/fhir\"><item><resource><display value=\"FOO\"/></resource></item></Linkage>", out);
} }
// FIXME: this should pass
@Test
@Ignore
public void testNamespacePreservationEncode() {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
//@formatter:on
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
// TODO: this should pass
@Test
@Ignore
public void testNamespacePreservationParse() {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
XhtmlNode div = parsed.getText().getDiv();
assertEquals("<xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div>", div.getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><xhtml:div xmlns:xhtml=\"http://www.w3.org/1999/xhtml\"><xhtml:img src=\"foo\"/>@fhirabend</xhtml:div></text></Patient>", encoded);
}
@Test @Test
public void testOmitResourceId() { public void testOmitResourceId() {
Patient p = new Patient(); Patient p = new Patient();

View File

@ -1538,21 +1538,21 @@ public class GenericClientDstu3Test {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir"); IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0; int idx = 0;
client // client
.search() // .search()
.forResource(Patient.class) // .forResource(Patient.class)
.sort().ascending("address") // .sort().ascending("address")
.returnBundle(Bundle.class) // .returnBundle(Bundle.class)
.execute(); // .execute();
assertEquals("http://example.com/fhir/Patient?_sort=address", capt.getAllValues().get(idx++).getURI().toASCIIString()); // assertEquals("http://example.com/fhir/Patient?_sort=address", capt.getAllValues().get(idx++).getURI().toASCIIString());
//
client // client
.search() // .search()
.forResource(Patient.class) // .forResource(Patient.class)
.sort().descending("address") // .sort().descending("address")
.returnBundle(Bundle.class) // .returnBundle(Bundle.class)
.execute(); // .execute();
assertEquals("http://example.com/fhir/Patient?_sort=-address", capt.getAllValues().get(idx++).getURI().toASCIIString()); // assertEquals("http://example.com/fhir/Patient?_sort=-address", capt.getAllValues().get(idx++).getURI().toASCIIString());
client client
.search() .search()

View File

@ -10,6 +10,7 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullWriter; import org.apache.commons.io.output.NullWriter;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
@ -52,6 +53,38 @@ public class JsonParserR4Test extends BaseTest {
ourLog.info(narrative); ourLog.info(narrative);
} }
@Test
public void testNamespacePrefixTrimmedFromNarrative() {
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
"<xhtml:div>" +
"<xhtml:img src=\"foo\"/>" +
"@fhirabend" +
"</xhtml:div>" +
"</text>" +
"</Patient>";
Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, input);
String expected = "<div xmlns=\"http://www.w3.org/1999/xhtml\"><img src=\"foo\"/>@fhirabend</div>";
assertEquals(expected, parsed.getText().getDiv().getValueAsString());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
ourLog.info(encoded);
assertThat(encoded, containsString("\"div\":\"" + expected.replace("\"", "\\\"") + "\""));
}
@Test
public void testNamespacePrefixStrippedOnJsonParse() {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
XhtmlNode div = parsed.getText().getDiv();
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\"><img src=\"foo\"/>@fhirabend</div>", div.getValueAsString());
String encoded = ourCtx.newXmlParser().encodeResourceToString(parsed);
assertEquals("<Patient xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\"><img src=\"foo\"/>@fhirabend</div></text></Patient>", encoded);
}
@Test @Test
public void testEncodeExtensionOnBinaryData() { public void testEncodeExtensionOnBinaryData() {

View File

@ -4,11 +4,14 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.ResourceDef; import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.rest.annotation.At;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Elements; import ca.uhn.fhir.rest.annotation.Elements;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.IncludeParam; import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
@ -18,6 +21,7 @@ import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
import ca.uhn.fhir.rest.client.apache.ResourceEntity; import ca.uhn.fhir.rest.client.apache.ResourceEntity;
import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException; import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor; import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
@ -36,6 +40,7 @@ import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion; import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
@ -228,6 +233,80 @@ public class ClientR4Test {
assertEquals("200", response.getId().getVersionIdPart()); assertEquals("200", response.getId().getVersionIdPart());
} }
interface MyClient extends IRestfulClient {
@Search()
List<Patient> search(@IncludeParam String theInclude);
}
@Test
public void testStringIncludeTest() throws Exception {
Bundle bundle = new Bundle();
bundle.setType(Bundle.BundleType.SEARCHSET);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ourCtx.newXmlParser().encodeResourceToString(bundle)), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[0]);
MyClient client = ourCtx.newRestfulClient(MyClient.class, "http://foo");
List<Patient> response = client.search("Patient:organization");
assertEquals(HttpGet.class, capt.getValue().getClass());
HttpGet post = (HttpGet) capt.getValue();
assertEquals("http://foo/Patient?_include=Patient%3Aorganization", post.getURI().toString());
}
@Test
public void testCreateWithInvalidType() throws Exception {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:foo").setValue("123");
String serialized = ourCtx.newXmlParser().encodeResourceToString(patient);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(serialized), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
try {
ourCtx.newRestfulClient(ITestClientWithCreateWithInvalidParameterType.class, "http://foo");
fail();
} catch (ConfigurationException e) {
assertEquals("Method 'createPatient' is annotated with @ResourceParam but has a type that is not an implementation of org.hl7.fhir.instance.model.api.IBaseResource", e.getMessage());
}
}
@Test
public void testCreateWithValidAndInvalidType() throws Exception {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:foo").setValue("123");
String serialized = ourCtx.newXmlParser().encodeResourceToString(patient);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(serialized), StandardCharsets.UTF_8));
when(myHttpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
try {
ourCtx.newRestfulClient(ITestClientWithCreateWithValidAndInvalidParameterType.class, "http://foo");
fail();
} catch (ConfigurationException e) {
assertEquals("Parameter #2/2 of method 'createPatient' on type 'ca.uhn.fhir.rest.client.ClientR4Test.ITestClientWithCreateWithValidAndInvalidParameterType' has no recognized FHIR interface parameter annotations. Don't know how to handle this parameter", e.getMessage());
}
}
@Test @Test
public void testDelete() throws Exception { public void testDelete() throws Exception {
@ -946,6 +1025,45 @@ public class ClientR4Test {
} }
@Test
public void testSearchWithAt() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo");
client.getPatientWithAt(new InstantType("2010-10-01T01:02:03.0Z"));
assertEquals("http://foo/Patient?_at=2010-10-01T01%3A02%3A03.0Z", capt.getValue().getURI().toString());
}
@Test
public void testUnannotatedMethod() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
ITestClientWithUnannotatedMethod client = ourCtx.newRestfulClient(ITestClientWithUnannotatedMethod.class, "http://foo");
try {
client.getPatientWithAt(new InstantType("2010-10-01T01:02:03.0Z"));
fail();
} catch (UnsupportedOperationException e) {
assertEquals("The method 'getPatientWithAt' in type ITestClientWithUnannotatedMethod has no handler. Did you forget to annotate it with a RESTful method annotation?", e.getMessage());
}
}
@Test @Test
public void testSearchWithOptionalParam() throws Exception { public void testSearchWithOptionalParam() throws Exception {
@ -978,7 +1096,6 @@ public class ClientR4Test {
} }
@Test @Test
public void testSearchWithStringIncludes() throws Exception { public void testSearchWithStringIncludes() throws Exception {
@ -1183,7 +1300,6 @@ public class ClientR4Test {
} }
@Test @Test
public void testValidateOutcomeResponse() throws Exception { public void testValidateOutcomeResponse() throws Exception {
@ -1213,7 +1329,6 @@ public class ClientR4Test {
assertNull(response.getResource()); assertNull(response.getResource());
} }
@Test @Test
public void testVRead() throws Exception { public void testVRead() throws Exception {
@ -1324,6 +1439,18 @@ public class ClientR4Test {
} }
} }
public interface ITestClientWithCreateWithInvalidParameterType extends IRestfulClient {
@Create()
MethodOutcome createPatient(@ResourceParam int thePatient);
}
public interface ITestClientWithCreateWithValidAndInvalidParameterType extends IRestfulClient {
@Create()
MethodOutcome createPatient(@ResourceParam Patient thePatient, int theInt);
}
interface ITestClientWithAndOr extends IBasicClient { interface ITestClientWithAndOr extends IBasicClient {
@Search() @Search()
@ -1382,6 +1509,10 @@ public class ClientR4Test {
} }
interface ITestClientWithUnannotatedMethod extends IRestfulClient {
void getPatientWithAt(@At InstantType theInstantType);
}
@ResourceDef(name = "Patient") @ResourceDef(name = "Patient")
public static class CustomPatient extends Patient { public static class CustomPatient extends Patient {

View File

@ -17,40 +17,40 @@ import ca.uhn.fhir.rest.param.*;
public interface ITestClient extends IBasicClient { public interface ITestClient extends IBasicClient {
@Create @Create
public MethodOutcome createPatient(@ResourceParam Patient thePatient); MethodOutcome createPatient(@ResourceParam Patient thePatient);
@Search() @Search()
public List<Patient> getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers); List<Patient> getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers);
@Search(type=Observation.class) @Search(type=Observation.class)
public Bundle getObservationByNameValueDate(@RequiredParam(name = Observation.SP_CODE_VALUE_DATE, compositeTypes= {StringParam.class,DateParam.class}) CompositeParam<StringParam, DateParam> theIdentifiers); Bundle getObservationByNameValueDate(@RequiredParam(name = Observation.SP_CODE_VALUE_DATE, compositeTypes = {StringParam.class, DateParam.class}) CompositeParam<StringParam, DateParam> theIdentifiers);
@Search() @Search()
public List<Patient> getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate); List<Patient> getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
@Search(type=ExtendedPatient.class) @Search(type=ExtendedPatient.class)
public List<IBaseResource> getPatientByDobWithGenericResourceReturnType(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate); List<IBaseResource> getPatientByDobWithGenericResourceReturnType(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
@Search(type=ExtendedPatient.class) @Search(type=ExtendedPatient.class)
public List<IAnyResource> getPatientByDobWithGenericResourceReturnType2(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate); List<IAnyResource> getPatientByDobWithGenericResourceReturnType2(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
@Search() @Search()
public List<Patient> getPatientMultipleIdentifiers(@RequiredParam(name = "ids") TokenOrListParam theIdentifiers); List<Patient> getPatientMultipleIdentifiers(@RequiredParam(name = "ids") TokenOrListParam theIdentifiers);
@Search(queryName="someQueryNoParams") @Search(queryName="someQueryNoParams")
public Patient getPatientNoParams(); Patient getPatientNoParams();
@Search(queryName="someQueryOneParam") @Search(queryName="someQueryOneParam")
public Patient getPatientOneParam(@RequiredParam(name="param1") StringParam theParam); Patient getPatientOneParam(@RequiredParam(name = "param1") StringParam theParam);
@Search(type=Patient.class) @Search(type=Patient.class)
public Bundle findPatient(@RequiredParam(name = "param") StringAndListParam theStrings); Bundle findPatient(@RequiredParam(name = "param") StringAndListParam theStrings);
@Search() @Search()
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam List<Include> theIncludes); Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam List<Include> theIncludes);
@Update @Update
public MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient); MethodOutcome updatePatient(@IdParam IdType theId, @ResourceParam Patient thePatient);
@Delete(type=DiagnosticReport.class) @Delete(type=DiagnosticReport.class)
void deleteDiagnosticReport(@IdParam IdType theId); void deleteDiagnosticReport(@IdParam IdType theId);
@ -89,7 +89,8 @@ public interface ITestClient extends IBasicClient {
Patient findPatientQuantity(@RequiredParam(name="quantityParam") QuantityParam theQuantityType); Patient findPatientQuantity(@RequiredParam(name="quantityParam") QuantityParam theQuantityType);
@Search(compartmentName="compartmentName") @Search(compartmentName="compartmentName")
public List<Patient> getPatientByCompartmentAndDob(@IdParam IdType theIdType, @RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate); List<Patient> getPatientByCompartmentAndDob(@IdParam IdType theIdType, @RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate);
@Search
Patient getPatientWithAt(@At InstantType theInstantType);
} }

View File

@ -262,9 +262,21 @@ public class IncludeTest {
} }
} }
/** @Test
* Created by dsotnikov on 2/25/2014. public void testStringInclude() throws Exception {
*/ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=stringInclude&_include=foo");
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
String responseContent = IOUtils.toString(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseResource(Bundle.class, responseContent);
assertEquals(1, bundle.getEntry().size());
Patient p = BundleUtil.toListOfResourcesOfType(ourCtx, bundle, Patient.class).get(0);
assertEquals("foo", p.getIdentifierFirstRep().getValue());
}
}
public static class DummyDiagnosticReportResourceProvider implements IResourceProvider { public static class DummyDiagnosticReportResourceProvider implements IResourceProvider {
@Override @Override
@ -392,6 +404,17 @@ public class IncludeTest {
return retVal; return retVal;
} }
@Search(queryName = "stringInclude")
public List<Patient> stringInclude(@IncludeParam String theInclude) {
Patient p = new Patient();
p.setId("p");
p.addIdentifier().setValue(theInclude);
return Arrays.asList(p);
}
@Override @Override
public Class<Patient> getResourceType() { public Class<Patient> getResourceType() {
return Patient.class; return Patient.class;

View File

@ -54,7 +54,7 @@ public class ServerInvalidDefinitionR4Test {
} catch (ServletException e) { } catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException")); assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains assertThat(e.getCause().toString(), StringContains
.containsString("Method 'update' is annotated with @ResourceParam but has a type that is not an implemtation of org.hl7.fhir.instance.model.api.IBaseResource or String or byte[]")); .containsString("Method 'update' is annotated with @ResourceParam but has a type that is not an implementation of org.hl7.fhir.instance.model.api.IBaseResource or String or byte[]"));
} }
} }

View File

@ -363,9 +363,7 @@ public class FhirInstanceValidatorR5Test {
} }
// FIXME: enable and change performed to occurrence
@Test @Test
@Ignore
public void testCompareTimesWithDifferentTimezones() { public void testCompareTimesWithDifferentTimezones() {
Procedure procedure = new Procedure(); Procedure procedure = new Procedure();
procedure.setStatus(Enumerations.EventStatus.COMPLETED); procedure.setStatus(Enumerations.EventStatus.COMPLETED);

24
pom.xml
View File

@ -2560,6 +2560,30 @@
<properties> <properties>
<surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m -XX:TieredStopAtLevel=1 -XX:+UseParallelGC -Xverify:none -Dfile.encoding=UTF-8 -Xss128M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=2048M</surefire_jvm_args> <surefire_jvm_args>-Dfile.encoding=UTF-8 -Xmx2048m -XX:TieredStopAtLevel=1 -XX:+UseParallelGC -Xverify:none -Dfile.encoding=UTF-8 -Xss128M -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=2048M</surefire_jvm_args>
</properties> </properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<id>validate</id>
<phase>generate-sources</phase>
<configuration>
<configLocation>src/checkstyle/checkstyle_config_nofixmes.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failOnViolation>true</failOnViolation>
<failsOnError>false</failsOnError>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile> </profile>
<profile> <profile>
<id>NOPARALLEL</id> <id>NOPARALLEL</id>

View File

@ -0,0 +1,20 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name = "Checker">
<property name="severity" value="error"/>
<property name="charset" value="UTF-8"/>
<property name="fileExtensions" value="java, properties, xml, js, json"/>
<module name="TreeWalker">
<module name="TodoComment">
<!-- The (?i) below means Case Insensitive -->
<property name="format" value="(?i)FIXME"/>
</module>
</module>
</module>