Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
044b9f584a
|
@ -1,42 +0,0 @@
|
||||||
package ca.uhn.fhir.rest.annotation;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Core Library
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2018 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.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.TagList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameter annotation for the {@link TagList} parameter in a {@link GetTags},
|
|
||||||
* {@link AddTags}, or {@link DeleteTags} method.
|
|
||||||
*
|
|
||||||
* @see GetTags
|
|
||||||
* @see AddTags
|
|
||||||
* @see DeleteTags
|
|
||||||
*/
|
|
||||||
@Target(value = ElementType.PARAMETER)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface TagListParam {
|
|
||||||
// nothing
|
|
||||||
}
|
|
|
@ -1,7 +1,28 @@
|
||||||
package ca.uhn.fhir.rest.param;
|
package ca.uhn.fhir.rest.param;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
|
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||||
|
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||||
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
||||||
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.param.binder.QueryParameterAndBinder;
|
||||||
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR - Core Library
|
* HAPI FHIR - Core Library
|
||||||
|
@ -21,29 +42,9 @@ import java.lang.reflect.Method;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.*;
|
|
||||||
import ca.uhn.fhir.model.api.*;
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
|
||||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
|
||||||
import ca.uhn.fhir.rest.annotation.TagListParam;
|
|
||||||
import ca.uhn.fhir.rest.api.QualifiedParamList;
|
|
||||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.param.binder.QueryParameterAndBinder;
|
|
||||||
import ca.uhn.fhir.util.ReflectionUtil;
|
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
|
||||||
|
|
||||||
public class ParameterUtil {
|
public class ParameterUtil {
|
||||||
|
|
||||||
private static final String LABEL = "label=\"";
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParameterUtil.class);
|
|
||||||
private static final String SCHEME = "scheme=\"";
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public static <T extends IIdType> T convertIdToType(IIdType value, Class<T> theIdParamType) {
|
public static <T extends IIdType> T convertIdToType(IIdType value, Class<T> theIdParamType) {
|
||||||
if (value != null && !theIdParamType.isAssignableFrom(value.getClass())) {
|
if (value != null && !theIdParamType.isAssignableFrom(value.getClass())) {
|
||||||
|
@ -179,8 +180,7 @@ public class ParameterUtil {
|
||||||
public static Integer findParamAnnotationIndex(Method theMethod, Class<?> toFind) {
|
public static Integer findParamAnnotationIndex(Method theMethod, Class<?> toFind) {
|
||||||
int paramIndex = 0;
|
int paramIndex = 0;
|
||||||
for (Annotation[] annotations : theMethod.getParameterAnnotations()) {
|
for (Annotation[] annotations : theMethod.getParameterAnnotations()) {
|
||||||
for (int annotationIndex = 0; annotationIndex < annotations.length; annotationIndex++) {
|
for (Annotation nextAnnotation : annotations) {
|
||||||
Annotation nextAnnotation = annotations[annotationIndex];
|
|
||||||
Class<? extends Annotation> class1 = nextAnnotation.annotationType();
|
Class<? extends Annotation> class1 = nextAnnotation.annotationType();
|
||||||
if (toFind.isAssignableFrom(class1)) {
|
if (toFind.isAssignableFrom(class1)) {
|
||||||
return paramIndex;
|
return paramIndex;
|
||||||
|
@ -191,10 +191,6 @@ public class ParameterUtil {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer findTagListParameterIndex(Method theMethod) {
|
|
||||||
return findParamAnnotationIndex(theMethod, TagListParam.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Object fromInteger(Class<?> theType, IntegerDt theArgument) {
|
public static Object fromInteger(Class<?> theType, IntegerDt theArgument) {
|
||||||
if (theType.equals(Integer.class)) {
|
if (theType.equals(Integer.class)) {
|
||||||
if (theArgument == null) {
|
if (theArgument == null) {
|
||||||
|
@ -271,12 +267,8 @@ public class ParameterUtil {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<String> splitParameterString(String theInput, boolean theUnescapeComponents) {
|
|
||||||
return splitParameterString(theInput, ',', theUnescapeComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<String> splitParameterString(String theInput, char theDelimiter, boolean theUnescapeComponents) {
|
static List<String> splitParameterString(String theInput, char theDelimiter, boolean theUnescapeComponents) {
|
||||||
ArrayList<String> retVal = new ArrayList<String>();
|
ArrayList<String> retVal = new ArrayList<>();
|
||||||
if (theInput != null) {
|
if (theInput != null) {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
for (int i = 0; i < theInput.length(); i++) {
|
for (int i = 0; i < theInput.length(); i++) {
|
||||||
|
@ -335,7 +327,7 @@ public class ParameterUtil {
|
||||||
*/
|
*/
|
||||||
public static String unescape(String theValue) {
|
public static String unescape(String theValue) {
|
||||||
if (theValue == null) {
|
if (theValue == null) {
|
||||||
return theValue;
|
return null;
|
||||||
}
|
}
|
||||||
if (theValue.indexOf('\\') == -1) {
|
if (theValue.indexOf('\\') == -1) {
|
||||||
return theValue;
|
return theValue;
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
|
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
|
||||||
|
|
||||||
class EncodedResource {
|
class EncodedResource {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import net.ttddyy.dsproxy.listener.ThreadQueryCountHolder;
|
||||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||||
import org.apache.commons.dbcp2.BasicDataSource;
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
|
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
@ -133,6 +134,8 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
||||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||||
|
extraProperties.put("hibernate.criteria.literal_handling_mode", LiteralHandlingMode.BIND);
|
||||||
|
|
||||||
return extraProperties;
|
return extraProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,11 @@ public abstract class BaseJpaTest {
|
||||||
protected ArrayList<IServerInterceptor> myServerInterceptorList;
|
protected ArrayList<IServerInterceptor> myServerInterceptorList;
|
||||||
protected IRequestOperationCallback myRequestOperationCallback = mock(IRequestOperationCallback.class);
|
protected IRequestOperationCallback myRequestOperationCallback = mock(IRequestOperationCallback.class);
|
||||||
|
|
||||||
|
@After
|
||||||
|
public final void afterPerformCleanup() {
|
||||||
|
BaseHapiFhirResourceDao.setDisableIncrementOnUpdateForUnitTest(false);
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeCreateSrd() {
|
public void beforeCreateSrd() {
|
||||||
mySrd = mock(ServletRequestDetails.class, Mockito.RETURNS_DEEP_STUBS);
|
mySrd = mock(ServletRequestDetails.class, Mockito.RETURNS_DEEP_STUBS);
|
||||||
|
@ -58,11 +63,6 @@ public abstract class BaseJpaTest {
|
||||||
when(mySrd.getUserData()).thenReturn(new HashMap<>());
|
when(mySrd.getUserData()).thenReturn(new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public final void afterPerformCleanup() {
|
|
||||||
BaseHapiFhirResourceDao.setDisableIncrementOnUpdateForUnitTest(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract FhirContext getContext();
|
protected abstract FhirContext getContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,11 +159,24 @@ public abstract class BaseJpaTest {
|
||||||
|
|
||||||
protected List<IIdType> toUnqualifiedVersionlessIds(IBundleProvider theFound) {
|
protected List<IIdType> toUnqualifiedVersionlessIds(IBundleProvider theFound) {
|
||||||
List<IIdType> retVal = new ArrayList<IIdType>();
|
List<IIdType> retVal = new ArrayList<IIdType>();
|
||||||
int size = theFound.size();
|
Integer size = theFound.size();
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
while (size == null) {
|
||||||
|
int timeout = 20000;
|
||||||
|
if (sw.getMillis() > timeout) {
|
||||||
|
fail("Waited over "+timeout+"ms for search");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch (InterruptedException theE) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ourLog.info("Found {} results", size);
|
ourLog.info("Found {} results", size);
|
||||||
List<IBaseResource> resources = theFound.getResources(0, size);
|
List<IBaseResource> resources = theFound.getResources(0, size);
|
||||||
for (IBaseResource next : resources) {
|
for (IBaseResource next : resources) {
|
||||||
retVal.add((IIdType) next.getIdElement().toUnqualifiedVersionless());
|
retVal.add(next.getIdElement().toUnqualifiedVersionless());
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -171,7 +184,7 @@ public abstract class BaseJpaTest {
|
||||||
protected List<IIdType> toUnqualifiedVersionlessIds(List<IBaseResource> theFound) {
|
protected List<IIdType> toUnqualifiedVersionlessIds(List<IBaseResource> theFound) {
|
||||||
List<IIdType> retVal = new ArrayList<IIdType>();
|
List<IIdType> retVal = new ArrayList<IIdType>();
|
||||||
for (IBaseResource next : theFound) {
|
for (IBaseResource next : theFound) {
|
||||||
retVal.add((IIdType) next.getIdElement().toUnqualifiedVersionless());
|
retVal.add(next.getIdElement().toUnqualifiedVersionless());
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +223,7 @@ public abstract class BaseJpaTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassShutdownDerby() throws SQLException {
|
public static void afterClassShutdownDerby() {
|
||||||
// DriverManager.getConnection("jdbc:derby:;shutdown=true");
|
// DriverManager.getConnection("jdbc:derby:;shutdown=true");
|
||||||
// try {
|
// try {
|
||||||
// DriverManager.getConnection("jdbc:derby:memory:myUnitTestDB;drop=true");
|
// DriverManager.getConnection("jdbc:derby:memory:myUnitTestDB;drop=true");
|
||||||
|
|
|
@ -48,118 +48,28 @@ import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
|
|
||||||
public class SystemProviderR4Test extends BaseJpaR4Test {
|
public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SystemProviderR4Test.class);
|
||||||
private static RestfulServer myRestServer;
|
private static RestfulServer myRestServer;
|
||||||
private static IGenericClient ourClient;
|
private static IGenericClient ourClient;
|
||||||
private static FhirContext ourCtx;
|
private static FhirContext ourCtx;
|
||||||
private static CloseableHttpClient ourHttpClient;
|
private static CloseableHttpClient ourHttpClient;
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SystemProviderR4Test.class);
|
|
||||||
private static Server ourServer;
|
private static Server ourServer;
|
||||||
private static String ourServerBase;
|
private static String ourServerBase;
|
||||||
private SimpleRequestHeaderInterceptor mySimpleHeaderInterceptor;
|
private SimpleRequestHeaderInterceptor mySimpleHeaderInterceptor;
|
||||||
|
|
||||||
@Test
|
@SuppressWarnings("deprecation")
|
||||||
public void testTransactionWithInlineConditionalUrl() throws Exception {
|
@After
|
||||||
myDaoConfig.setAllowInlineMatchUrlReferences(true);
|
public void after() {
|
||||||
|
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||||
Patient p = new Patient();
|
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||||
p.addName().setFamily("van de Heuvelcx85ioqWJbI").addGiven("Pietercx85ioqWJbI");
|
|
||||||
myPatientDao.create(p, mySrd);
|
|
||||||
|
|
||||||
Organization o = new Organization();
|
|
||||||
o.addIdentifier().setSystem("urn:oid:2.16.840.1.113883.2.4.6.1").setValue("07-8975469");
|
|
||||||
myOrganizationDao.create(o, mySrd);
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
|
||||||
" <id value=\"20160113160203\"/>\n" +
|
|
||||||
" <type value=\"transaction\"/>\n" +
|
|
||||||
" <entry>\n" +
|
|
||||||
" <fullUrl value=\"urn:uuid:c72aa430-2ddc-456e-7a09-dea8264671d8\"/>\n" +
|
|
||||||
" <resource>\n" +
|
|
||||||
" <Encounter>\n" +
|
|
||||||
" <identifier>\n" +
|
|
||||||
" <use value=\"official\"/>\n" +
|
|
||||||
" <system value=\"http://healthcare.example.org/identifiers/encounter\"/>\n" +
|
|
||||||
" <value value=\"845962.8975469\"/>\n" +
|
|
||||||
" </identifier>\n" +
|
|
||||||
" <status value=\"in-progress\"/>\n" +
|
|
||||||
" <class value=\"inpatient\"/>\n" +
|
|
||||||
" <patient>\n" +
|
|
||||||
" <reference value=\"Patient?family=van%20de%20Heuvelcx85ioqWJbI&given=Pietercx85ioqWJbI\"/>\n" +
|
|
||||||
" </patient>\n" +
|
|
||||||
" <serviceProvider>\n" +
|
|
||||||
" <reference value=\"Organization?identifier=urn:oid:2.16.840.1.113883.2.4.6.1|07-8975469\"/>\n" +
|
|
||||||
" </serviceProvider>\n" +
|
|
||||||
" </Encounter>\n" +
|
|
||||||
" </resource>\n" +
|
|
||||||
" <request>\n" +
|
|
||||||
" <method value=\"POST\"/>\n" +
|
|
||||||
" <url value=\"Encounter\"/>\n" +
|
|
||||||
" </request>\n" +
|
|
||||||
" </entry>\n" +
|
|
||||||
"</Bundle>";
|
|
||||||
//@formatter:off
|
|
||||||
|
|
||||||
HttpPost req = new HttpPost(ourServerBase);
|
|
||||||
req.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
|
||||||
|
|
||||||
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
|
||||||
try {
|
|
||||||
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info(encoded);
|
|
||||||
|
|
||||||
assertThat(encoded, containsString("transaction-response"));
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
@Test
|
public void before() {
|
||||||
public void testTransactionDeleteWithDuplicateDeletes() throws Exception {
|
mySimpleHeaderInterceptor = new SimpleRequestHeaderInterceptor();
|
||||||
myDaoConfig.setAllowInlineMatchUrlReferences(true);
|
ourClient.registerInterceptor(mySimpleHeaderInterceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("van de Heuvelcx85ioqWJbI").addGiven("Pietercx85ioqWJbI");
|
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
ourClient.read().resource(Patient.class).withId(id);
|
|
||||||
|
|
||||||
Bundle inputBundle = new Bundle();
|
|
||||||
inputBundle.setType(BundleType.TRANSACTION);
|
|
||||||
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl(id.getValue());
|
|
||||||
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl(id.getValue());
|
|
||||||
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl("Patient?name=Pietercx85ioqWJbI");
|
|
||||||
String input = myFhirCtx.newXmlParser().encodeResourceToString(inputBundle);
|
|
||||||
|
|
||||||
HttpPost req = new HttpPost(ourServerBase + "?_pretty=true");
|
|
||||||
req.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
|
||||||
|
|
||||||
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
|
||||||
try {
|
|
||||||
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info(encoded);
|
|
||||||
|
|
||||||
assertThat(encoded, containsString("transaction-response"));
|
|
||||||
|
|
||||||
Bundle response = myFhirCtx.newXmlParser().parseResource(Bundle.class, encoded);
|
|
||||||
assertEquals(3, response.getEntry().size());
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
ourClient.read().resource(Patient.class).withId(id).execute();
|
|
||||||
fail();
|
|
||||||
} catch (ResourceGoneException e) {
|
|
||||||
// good
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeStartServer() throws Exception {
|
public void beforeStartServer() throws Exception {
|
||||||
if (myRestServer == null) {
|
if (myRestServer == null) {
|
||||||
|
@ -213,101 +123,6 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
myRestServer.setPagingProvider(myPagingProvider);
|
myRestServer.setPagingProvider(myPagingProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
mySimpleHeaderInterceptor = new SimpleRequestHeaderInterceptor();
|
|
||||||
ourClient.registerInterceptor(mySimpleHeaderInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@After
|
|
||||||
public void after() {
|
|
||||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
|
||||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Test
|
|
||||||
public void testResponseUsesCorrectContentType() throws Exception {
|
|
||||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
|
||||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
|
||||||
|
|
||||||
HttpGet get = new HttpGet(ourServerBase);
|
|
||||||
// get.addHeader("Accept", "application/xml, text/html");
|
|
||||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
|
||||||
assertThat(http.getFirstHeader("Content-Type").getValue(), containsString("application/fhir+json"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FOrmat has changed, source is no longer valid
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
@Ignore
|
|
||||||
public void testValidateUsingIncomingResources() throws Exception {
|
|
||||||
FhirInstanceValidator val = new FhirInstanceValidator(myValidationSupport);
|
|
||||||
RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
|
|
||||||
interceptor.addValidatorModule(val);
|
|
||||||
interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
|
||||||
interceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
|
||||||
myRestServer.registerInterceptor(interceptor);
|
|
||||||
try {
|
|
||||||
|
|
||||||
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/questionnaire-sdc-profile-example-ussg-fht.xml");
|
|
||||||
String bundleStr = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
|
||||||
|
|
||||||
HttpPost req = new HttpPost(ourServerBase);
|
|
||||||
req.setEntity(new StringEntity(bundleStr, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
|
||||||
|
|
||||||
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
|
||||||
try {
|
|
||||||
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info(encoded);
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
assertThat(encoded, containsString("Questionnaire/54127-6/_history/"));
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
for (Header next : resp.getHeaders(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_NAME)) {
|
|
||||||
ourLog.info(next.toString());
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
IOUtils.closeQuietly(resp.getEntity().getContent());
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
myRestServer.unregisterInterceptor(interceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEverythingReturnsCorrectFormatInPagingLink() throws Exception {
|
|
||||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
|
||||||
myRestServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10));
|
|
||||||
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
|
|
||||||
myRestServer.registerInterceptor(interceptor);
|
|
||||||
|
|
||||||
for (int i = 0; i < 11; i++) {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("Name" + i);
|
|
||||||
ourClient.create().resource(p).execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
|
||||||
get.addHeader("Accept", "application/xml, text/html");
|
|
||||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
|
||||||
|
|
||||||
try {
|
|
||||||
String response = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info(response);
|
|
||||||
assertThat(response, containsString("_format=json"));
|
|
||||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
|
||||||
} finally {
|
|
||||||
http.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
myRestServer.unregisterInterceptor(interceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEverythingReturnsCorrectBundleType() throws Exception {
|
public void testEverythingReturnsCorrectBundleType() throws Exception {
|
||||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||||
|
@ -340,6 +155,35 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
myRestServer.unregisterInterceptor(interceptor);
|
myRestServer.unregisterInterceptor(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEverythingReturnsCorrectFormatInPagingLink() throws Exception {
|
||||||
|
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||||
|
myRestServer.setPagingProvider(new FifoMemoryPagingProvider(1).setDefaultPageSize(10));
|
||||||
|
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
|
||||||
|
myRestServer.registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
for (int i = 0; i < 11; i++) {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().setFamily("Name" + i);
|
||||||
|
ourClient.create().resource(p).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
||||||
|
get.addHeader("Accept", "application/xml, text/html");
|
||||||
|
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||||
|
|
||||||
|
try {
|
||||||
|
String response = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(response);
|
||||||
|
assertThat(response, containsString("_format=json"));
|
||||||
|
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||||
|
} finally {
|
||||||
|
http.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
myRestServer.unregisterInterceptor(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEverythingType() throws Exception {
|
public void testEverythingType() throws Exception {
|
||||||
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
HttpGet get = new HttpGet(ourServerBase + "/Patient/$everything");
|
||||||
|
@ -351,6 +195,12 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOperationDefinition() {
|
||||||
|
OperationDefinition op = ourClient.read(OperationDefinition.class, "-s-get-resource-counts");
|
||||||
|
assertEquals("get-resource-counts", op.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMarkResourcesForReindexing() throws Exception {
|
public void testMarkResourcesForReindexing() throws Exception {
|
||||||
HttpGet get = new HttpGet(ourServerBase + "/$mark-all-resources-for-reindexing");
|
HttpGet get = new HttpGet(ourServerBase + "/$mark-all-resources-for-reindexing");
|
||||||
|
@ -375,6 +225,18 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Test
|
||||||
|
public void testResponseUsesCorrectContentType() throws Exception {
|
||||||
|
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||||
|
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||||
|
|
||||||
|
HttpGet get = new HttpGet(ourServerBase);
|
||||||
|
// get.addHeader("Accept", "application/xml, text/html");
|
||||||
|
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||||
|
assertThat(http.getFirstHeader("Content-Type").getValue(), containsString("application/fhir+json"));
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(propagation = Propagation.NEVER)
|
@Transactional(propagation = Propagation.NEVER)
|
||||||
@Test
|
@Test
|
||||||
public void testSuggestKeywords() throws Exception {
|
public void testSuggestKeywords() throws Exception {
|
||||||
|
@ -460,9 +322,104 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOperationDefinition() {
|
public void testTransactionCount() throws Exception {
|
||||||
OperationDefinition op = ourClient.read(OperationDefinition.class, "-s-get-resource-counts");
|
for (int i = 0; i < 20; i++) {
|
||||||
assertEquals("get-resource-counts", op.getCode());
|
Patient p = new Patient();
|
||||||
|
p.addName().setFamily("PATIENT_" + i);
|
||||||
|
myPatientDao.create(p, mySrd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Bundle req = new Bundle();
|
||||||
|
req.setType(BundleType.TRANSACTION);
|
||||||
|
req.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?_summary=count");
|
||||||
|
Bundle resp = ourClient.transaction().withBundle(req).execute();
|
||||||
|
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||||
|
|
||||||
|
assertEquals(1, resp.getEntry().size());
|
||||||
|
Bundle respSub = (Bundle) resp.getEntry().get(0).getResource();
|
||||||
|
assertEquals(20, respSub.getTotal());
|
||||||
|
assertEquals(0, respSub.getEntry().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionCreateWithPreferHeader() throws Exception {
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(true);
|
||||||
|
|
||||||
|
Bundle req;
|
||||||
|
Bundle resp;
|
||||||
|
|
||||||
|
// No prefer header
|
||||||
|
req = new Bundle();
|
||||||
|
req.setType(BundleType.TRANSACTION);
|
||||||
|
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||||
|
resp = ourClient.transaction().withBundle(req).execute();
|
||||||
|
assertEquals(null, resp.getEntry().get(0).getResource());
|
||||||
|
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||||
|
|
||||||
|
// Prefer return=minimal
|
||||||
|
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
||||||
|
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_MINIMAL);
|
||||||
|
req = new Bundle();
|
||||||
|
req.setType(BundleType.TRANSACTION);
|
||||||
|
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||||
|
resp = ourClient.transaction().withBundle(req).execute();
|
||||||
|
assertEquals(null, resp.getEntry().get(0).getResource());
|
||||||
|
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||||
|
|
||||||
|
// Prefer return=representation
|
||||||
|
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
||||||
|
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_REPRESENTATION);
|
||||||
|
req = new Bundle();
|
||||||
|
req.setType(BundleType.TRANSACTION);
|
||||||
|
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||||
|
resp = ourClient.transaction().withBundle(req).execute();
|
||||||
|
assertEquals(Patient.class, resp.getEntry().get(0).getResource().getClass());
|
||||||
|
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionDeleteWithDuplicateDeletes() throws Exception {
|
||||||
|
myDaoConfig.setAllowInlineMatchUrlReferences(true);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().setFamily("van de Heuvelcx85ioqWJbI").addGiven("Pietercx85ioqWJbI");
|
||||||
|
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
ourClient.read().resource(Patient.class).withId(id);
|
||||||
|
|
||||||
|
Bundle inputBundle = new Bundle();
|
||||||
|
inputBundle.setType(BundleType.TRANSACTION);
|
||||||
|
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl(id.getValue());
|
||||||
|
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl(id.getValue());
|
||||||
|
inputBundle.addEntry().getRequest().setMethod(HTTPVerb.DELETE).setUrl("Patient?name=Pietercx85ioqWJbI");
|
||||||
|
String input = myFhirCtx.newXmlParser().encodeResourceToString(inputBundle);
|
||||||
|
|
||||||
|
HttpPost req = new HttpPost(ourServerBase + "?_pretty=true");
|
||||||
|
req.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||||
|
|
||||||
|
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
||||||
|
try {
|
||||||
|
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
assertThat(encoded, containsString("transaction-response"));
|
||||||
|
|
||||||
|
Bundle response = myFhirCtx.newXmlParser().parseResource(Bundle.class, encoded);
|
||||||
|
assertEquals(3, response.getEntry().size());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ourClient.read().resource(Patient.class).withId(id).execute();
|
||||||
|
fail();
|
||||||
|
} catch (ResourceGoneException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -473,23 +430,6 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
ourLog.info(response);
|
ourLog.info(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionWithIncompleteBundle() throws Exception {
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.setGender(AdministrativeGender.MALE);
|
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.setType(BundleType.TRANSACTION);
|
|
||||||
bundle.addEntry().setResource(patient);
|
|
||||||
|
|
||||||
try {
|
|
||||||
ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertThat(e.toString(), containsString("missing or invalid HTTP Verb"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionFromBundle2() throws Exception {
|
public void testTransactionFromBundle2() throws Exception {
|
||||||
|
|
||||||
|
@ -607,61 +547,118 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCount() throws Exception {
|
public void testTransactionWithIncompleteBundle() throws Exception {
|
||||||
for (int i = 0; i < 20; i++) {
|
Patient patient = new Patient();
|
||||||
Patient p = new Patient();
|
patient.setGender(AdministrativeGender.MALE);
|
||||||
p.addName().setFamily("PATIENT_" + i);
|
|
||||||
myPatientDao.create(p, mySrd);
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.setType(BundleType.TRANSACTION);
|
||||||
|
bundle.addEntry().setResource(patient);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ourClient.transaction().withBundle(bundle).prettyPrint().execute();
|
||||||
|
fail();
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
assertThat(e.toString(), containsString("missing or invalid HTTP Verb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Bundle req = new Bundle();
|
|
||||||
req.setType(BundleType.TRANSACTION);
|
|
||||||
req.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?_summary=count");
|
|
||||||
Bundle resp = ourClient.transaction().withBundle(req).execute();
|
|
||||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
|
||||||
|
|
||||||
assertEquals(1, resp.getEntry().size());
|
|
||||||
Bundle respSub = (Bundle) resp.getEntry().get(0).getResource();
|
|
||||||
assertEquals(20, respSub.getTotal());
|
|
||||||
assertEquals(0, respSub.getEntry().size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCreateWithPreferHeader() throws Exception {
|
public void testTransactionWithInlineConditionalUrl() throws Exception {
|
||||||
|
myDaoConfig.setAllowInlineMatchUrlReferences(true);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setActive(true);
|
p.addName().setFamily("van de Heuvelcx85ioqWJbI").addGiven("Pietercx85ioqWJbI");
|
||||||
|
myPatientDao.create(p, mySrd);
|
||||||
|
|
||||||
Bundle req;
|
Organization o = new Organization();
|
||||||
Bundle resp;
|
o.addIdentifier().setSystem("urn:oid:2.16.840.1.113883.2.4.6.1").setValue("07-8975469");
|
||||||
|
myOrganizationDao.create(o, mySrd);
|
||||||
|
|
||||||
// No prefer header
|
//@formatter:off
|
||||||
req = new Bundle();
|
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||||
req.setType(BundleType.TRANSACTION);
|
" <id value=\"20160113160203\"/>\n" +
|
||||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
" <type value=\"transaction\"/>\n" +
|
||||||
resp = ourClient.transaction().withBundle(req).execute();
|
" <entry>\n" +
|
||||||
assertEquals(null, resp.getEntry().get(0).getResource());
|
" <fullUrl value=\"urn:uuid:c72aa430-2ddc-456e-7a09-dea8264671d8\"/>\n" +
|
||||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
" <resource>\n" +
|
||||||
|
" <Encounter>\n" +
|
||||||
|
" <identifier>\n" +
|
||||||
|
" <use value=\"official\"/>\n" +
|
||||||
|
" <system value=\"http://healthcare.example.org/identifiers/encounter\"/>\n" +
|
||||||
|
" <value value=\"845962.8975469\"/>\n" +
|
||||||
|
" </identifier>\n" +
|
||||||
|
" <status value=\"in-progress\"/>\n" +
|
||||||
|
" <class value=\"inpatient\"/>\n" +
|
||||||
|
" <patient>\n" +
|
||||||
|
" <reference value=\"Patient?family=van%20de%20Heuvelcx85ioqWJbI&given=Pietercx85ioqWJbI\"/>\n" +
|
||||||
|
" </patient>\n" +
|
||||||
|
" <serviceProvider>\n" +
|
||||||
|
" <reference value=\"Organization?identifier=urn:oid:2.16.840.1.113883.2.4.6.1|07-8975469\"/>\n" +
|
||||||
|
" </serviceProvider>\n" +
|
||||||
|
" </Encounter>\n" +
|
||||||
|
" </resource>\n" +
|
||||||
|
" <request>\n" +
|
||||||
|
" <method value=\"POST\"/>\n" +
|
||||||
|
" <url value=\"Encounter\"/>\n" +
|
||||||
|
" </request>\n" +
|
||||||
|
" </entry>\n" +
|
||||||
|
"</Bundle>";
|
||||||
|
//@formatter:off
|
||||||
|
|
||||||
// Prefer return=minimal
|
HttpPost req = new HttpPost(ourServerBase);
|
||||||
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
req.setEntity(new StringEntity(input, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||||
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_MINIMAL);
|
|
||||||
req = new Bundle();
|
|
||||||
req.setType(BundleType.TRANSACTION);
|
|
||||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
|
||||||
resp = ourClient.transaction().withBundle(req).execute();
|
|
||||||
assertEquals(null, resp.getEntry().get(0).getResource());
|
|
||||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
|
||||||
|
|
||||||
// Prefer return=representation
|
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
||||||
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
try {
|
||||||
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_REPRESENTATION);
|
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
req = new Bundle();
|
ourLog.info(encoded);
|
||||||
req.setType(BundleType.TRANSACTION);
|
|
||||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
assertThat(encoded, containsString("transaction-response"));
|
||||||
resp = ourClient.transaction().withBundle(req).execute();
|
} finally {
|
||||||
assertEquals(Patient.class, resp.getEntry().get(0).getResource().getClass());
|
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FOrmat has changed, source is no longer valid
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testValidateUsingIncomingResources() throws Exception {
|
||||||
|
FhirInstanceValidator val = new FhirInstanceValidator(myValidationSupport);
|
||||||
|
RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
|
||||||
|
interceptor.addValidatorModule(val);
|
||||||
|
interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||||
|
interceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||||
|
myRestServer.registerInterceptor(interceptor);
|
||||||
|
try {
|
||||||
|
|
||||||
|
InputStream bundleRes = SystemProviderDstu2Test.class.getResourceAsStream("/questionnaire-sdc-profile-example-ussg-fht.xml");
|
||||||
|
String bundleStr = IOUtils.toString(bundleRes, StandardCharsets.UTF_8);
|
||||||
|
|
||||||
|
HttpPost req = new HttpPost(ourServerBase);
|
||||||
|
req.setEntity(new StringEntity(bundleStr, ContentType.parse(Constants.CT_FHIR_XML + "; charset=utf-8")));
|
||||||
|
|
||||||
|
CloseableHttpResponse resp = ourHttpClient.execute(req);
|
||||||
|
try {
|
||||||
|
String encoded = IOUtils.toString(resp.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
assertThat(encoded, containsString("Questionnaire/54127-6/_history/"));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
for (Header next : resp.getHeaders(RequestValidatingInterceptor.DEFAULT_RESPONSE_HEADER_NAME)) {
|
||||||
|
ourLog.info(next.toString());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
IOUtils.closeQuietly(resp.getEntity().getContent());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
myRestServer.unregisterInterceptor(interceptor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -875,12 +875,14 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
||||||
|
|
||||||
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
|
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
|
||||||
IServerInterceptor next = getInterceptors().get(i);
|
IServerInterceptor next = getInterceptors().get(i);
|
||||||
next.processingCompletedNormally(requestDetails);
|
try {
|
||||||
|
next.processingCompletedNormally(requestDetails);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
ourLog.error("Failure in interceptor method", t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outputStreamOrWriter != null) {
|
IOUtils.closeQuietly(outputStreamOrWriter);
|
||||||
outputStreamOrWriter.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (NotModifiedException | AuthenticationException e) {
|
} catch (NotModifiedException | AuthenticationException e) {
|
||||||
|
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package ca.uhn.fhir.rest.server.method;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Server Framework
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.rest.annotation.AddTags;
|
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IRestfulServer;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|
||||||
|
|
||||||
class AddTagsMethodBinding extends BaseAddOrDeleteTagsMethodBinding {
|
|
||||||
|
|
||||||
public AddTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, AddTags theAnnotation) {
|
|
||||||
super(theMethod, theContext, theProvider, theAnnotation.type());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isDelete() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RestOperationTypeEnum getRestOperationType() {
|
|
||||||
return RestOperationTypeEnum.ADD_TAGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,117 +0,0 @@
|
||||||
package ca.uhn.fhir.rest.server.method;
|
|
||||||
|
|
||||||
/*-
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Server Framework
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2018 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.lang.reflect.Modifier;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.model.api.TagList;
|
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
|
||||||
import ca.uhn.fhir.rest.annotation.TagListParam;
|
|
||||||
import ca.uhn.fhir.rest.api.*;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.param.ParameterUtil;
|
|
||||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
|
||||||
|
|
||||||
abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> {
|
|
||||||
|
|
||||||
private Class<? extends IBaseResource> myType;
|
|
||||||
private Integer myIdParamIndex;
|
|
||||||
private String myResourceName;
|
|
||||||
private Integer myTagListParamIndex;
|
|
||||||
|
|
||||||
public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, Class<? extends IBaseResource> theTypeFromMethodAnnotation) {
|
|
||||||
super(theMethod, theContext, theProvider);
|
|
||||||
|
|
||||||
if (theProvider instanceof IResourceProvider) {
|
|
||||||
myType = ((IResourceProvider) theProvider).getResourceType();
|
|
||||||
} else {
|
|
||||||
myType = theTypeFromMethodAnnotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Modifier.isInterface(myType.getModifiers())) {
|
|
||||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' does not specify a resource type, but has an @" + IdParam.class.getSimpleName()
|
|
||||||
+ " parameter. Please specity a resource type in the method annotation on this method");
|
|
||||||
}
|
|
||||||
|
|
||||||
myResourceName = theContext.getResourceDefinition(myType).getName();
|
|
||||||
|
|
||||||
myIdParamIndex = ParameterUtil.findIdParameterIndex(theMethod, getContext());
|
|
||||||
myTagListParamIndex = ParameterUtil.findTagListParameterIndex(theMethod);
|
|
||||||
|
|
||||||
if (myIdParamIndex == null) {
|
|
||||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' does not have an @" + IdParam.class.getSimpleName() + " parameter.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myTagListParamIndex == null) {
|
|
||||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' does not have a parameter of type " + TagList.class.getSimpleName() + ", or paramater is not annotated with the @"
|
|
||||||
+ TagListParam.class.getSimpleName() + " annotation");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getResourceName() {
|
|
||||||
return myResourceName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RestOperationTypeEnum getRestOperationType() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract boolean isDelete();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
|
|
||||||
if (theRequest.getRequestType() != RequestTypeEnum.POST) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!Constants.PARAM_TAGS.equals(theRequest.getOperation())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!myResourceName.equals(theRequest.getResourceName())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theRequest.getId() == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDelete()) {
|
|
||||||
if (Constants.PARAM_DELETE.equals(theRequest.getSecondaryOperation()) == false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (theRequest.getSecondaryOperation() != null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -494,10 +494,6 @@ public abstract class BaseMethodBinding<T> {
|
||||||
return new HistoryMethodBinding(theMethod, theContext, theProvider);
|
return new HistoryMethodBinding(theMethod, theContext, theProvider);
|
||||||
} else if (validate != null) {
|
} else if (validate != null) {
|
||||||
return new ValidateMethodBindingDstu2Plus(returnType, returnTypeFromRp, theMethod, theContext, theProvider, validate);
|
return new ValidateMethodBindingDstu2Plus(returnType, returnTypeFromRp, theMethod, theContext, theProvider, validate);
|
||||||
} else if (addTags != null) {
|
|
||||||
return new AddTagsMethodBinding(theMethod, theContext, theProvider, addTags);
|
|
||||||
} else if (deleteTags != null) {
|
|
||||||
return new DeleteTagsMethodBinding(theMethod, theContext, theProvider, deleteTags);
|
|
||||||
} else if (transaction != null) {
|
} else if (transaction != null) {
|
||||||
return new TransactionMethodBinding(theMethod, theContext, theProvider);
|
return new TransactionMethodBinding(theMethod, theContext, theProvider);
|
||||||
} else if (operation != null) {
|
} else if (operation != null) {
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package ca.uhn.fhir.rest.server.method;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* #%L
|
|
||||||
* HAPI FHIR - Server Framework
|
|
||||||
* %%
|
|
||||||
* Copyright (C) 2014 - 2018 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 ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.rest.annotation.DeleteTags;
|
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IRestfulServer;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|
||||||
|
|
||||||
public class DeleteTagsMethodBinding extends BaseAddOrDeleteTagsMethodBinding {
|
|
||||||
|
|
||||||
public DeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, DeleteTags theDeleteTags) {
|
|
||||||
super(theMethod, theContext, theProvider, theDeleteTags.type());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean isDelete() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RestOperationTypeEnum getRestOperationType() {
|
|
||||||
return RestOperationTypeEnum.DELETE_TAGS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@ import static org.hamcrest.Matchers.not;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -272,6 +273,29 @@ public class ServerMimetypeR4Test {
|
||||||
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
assertEquals(Constants.CT_FHIR_XML_NEW, status.getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #837
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testResponseContentTypes() throws IOException {
|
||||||
|
assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json"));
|
||||||
|
assertEquals("application/fhir+xml", readAndReturnContentType(null));
|
||||||
|
assertEquals("application/json+fhir", readAndReturnContentType("application/json+fhir"));
|
||||||
|
assertEquals("application/json+fhir", readAndReturnContentType("application/json"));
|
||||||
|
assertEquals("application/fhir+json", readAndReturnContentType("application/fhir+json,application/json;q=0.9"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readAndReturnContentType(String theAccept) throws IOException {
|
||||||
|
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||||
|
if (theAccept != null) {
|
||||||
|
httpGet.addHeader(Constants.HEADER_ACCEPT, theAccept);
|
||||||
|
}
|
||||||
|
HttpResponse status = ourClient.execute(httpGet);
|
||||||
|
String contentType = status.getEntity().getContentType().getValue();
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
contentType = contentType.replaceAll(";.*","");
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
package ca.uhn.fhir.rest.server.interceptor;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.api.AddProfileTagEnum;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import ca.uhn.fhir.util.PortUtil;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.http.HttpEntity;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.entity.ContentType;
|
||||||
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClientBuilder;
|
||||||
|
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class InterceptorThrowingExceptionR4Test {
|
||||||
|
|
||||||
|
private static final String ERR403 = "{\"resourceType\":\"OperationOutcome\",\"issue\":[{\"severity\":\"error\",\"code\":\"processing\",\"diagnostics\":\"Access denied by default policy (no applicable rules)\"}]}";
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(InterceptorThrowingExceptionR4Test.class);
|
||||||
|
private static CloseableHttpClient ourClient;
|
||||||
|
private static String ourConditionalCreateId;
|
||||||
|
private static FhirContext ourCtx = FhirContext.forR4();
|
||||||
|
private static boolean ourHitMethod;
|
||||||
|
private static int ourPort;
|
||||||
|
private static List<Resource> ourReturn;
|
||||||
|
private static Server ourServer;
|
||||||
|
private static RestfulServer ourServlet;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
ourCtx.setAddProfileTagWhenEncoding(AddProfileTagEnum.NEVER);
|
||||||
|
for (IServerInterceptor next : new ArrayList<>(ourServlet.getInterceptors())) {
|
||||||
|
ourServlet.unregisterInterceptor(next);
|
||||||
|
}
|
||||||
|
ourServlet.setTenantIdentificationStrategy(null);
|
||||||
|
ourReturn = null;
|
||||||
|
ourHitMethod = false;
|
||||||
|
ourConditionalCreateId = "1123";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Resource createPatient(Integer theId) {
|
||||||
|
Patient retVal = new Patient();
|
||||||
|
if (theId != null) {
|
||||||
|
retVal.setId(new IdType("Patient", (long) theId));
|
||||||
|
}
|
||||||
|
retVal.addName().setFamily("FAM");
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String extractResponseAndClose(HttpResponse status) throws IOException {
|
||||||
|
if (status.getEntity() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String responseContent;
|
||||||
|
responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||||
|
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||||
|
return responseContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFailureInProcessingCompletedNormally() throws Exception {
|
||||||
|
final List<Integer> hit = new ArrayList<>();
|
||||||
|
ourServlet.registerInterceptor(new InterceptorAdapter(){
|
||||||
|
@Override
|
||||||
|
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
|
||||||
|
hit.add(1);
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ourServlet.registerInterceptor(new InterceptorAdapter(){
|
||||||
|
@Override
|
||||||
|
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
|
||||||
|
hit.add(2);
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ourServlet.registerInterceptor(new InterceptorAdapter(){
|
||||||
|
@Override
|
||||||
|
public void processingCompletedNormally(ServletRequestDetails theRequestDetails) {
|
||||||
|
hit.add(3);
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
HttpGet httpGet;
|
||||||
|
HttpResponse status;
|
||||||
|
String response;
|
||||||
|
|
||||||
|
ourReturn = Collections.singletonList(createPatient(2));
|
||||||
|
ourHitMethod = false;
|
||||||
|
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||||
|
status = ourClient.execute(httpGet);
|
||||||
|
response = extractResponseAndClose(status);
|
||||||
|
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||||
|
assertThat(response, containsString("FAM"));
|
||||||
|
assertTrue(ourHitMethod);
|
||||||
|
ourLog.info("Hit: {}", hit);
|
||||||
|
assertThat(hit, contains(3,2,1));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() throws Exception {
|
||||||
|
ourServer.stop();
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void beforeClass() throws Exception {
|
||||||
|
|
||||||
|
ourPort = PortUtil.findFreePort();
|
||||||
|
try {
|
||||||
|
ourServer = new Server(ourPort);
|
||||||
|
} catch (Exception e) {
|
||||||
|
ourLog.error("FAILED", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
DummyPatientResourceProvider patProvider = new DummyPatientResourceProvider();
|
||||||
|
|
||||||
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
|
ourServlet = new RestfulServer(ourCtx);
|
||||||
|
ourServlet.setFhirContext(ourCtx);
|
||||||
|
ourServlet.setResourceProviders(patProvider);
|
||||||
|
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
||||||
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
|
ourServer.setHandler(proxyHandler);
|
||||||
|
ourServer.start();
|
||||||
|
|
||||||
|
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||||
|
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||||
|
builder.setConnectionManager(connectionManager);
|
||||||
|
ourClient = builder.build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Read(version = true)
|
||||||
|
public Patient read(@IdParam IdType theId) {
|
||||||
|
ourHitMethod = true;
|
||||||
|
return (Patient) ourReturn.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
33
pom.xml
33
pom.xml
|
@ -409,8 +409,9 @@
|
||||||
<!-- Dependency Versions -->
|
<!-- Dependency Versions -->
|
||||||
<derby_version>10.14.1.0</derby_version>
|
<derby_version>10.14.1.0</derby_version>
|
||||||
<jersey_version>2.25.1</jersey_version>
|
<jersey_version>2.25.1</jersey_version>
|
||||||
<jetty_version>9.4.6.v20170531</jetty_version>
|
<jetty_version>9.4.8.v20171121</jetty_version>
|
||||||
<hibernate_version>5.2.10.Final</hibernate_version>
|
<!--<hibernate_version>5.2.10.Final</hibernate_version>-->
|
||||||
|
<hibernate_version>5.2.12.Final</hibernate_version>
|
||||||
<hibernate_validator_version>5.4.1.Final</hibernate_validator_version>
|
<hibernate_validator_version>5.4.1.Final</hibernate_validator_version>
|
||||||
<!-- Update lucene version when you update hibernate-search version -->
|
<!-- Update lucene version when you update hibernate-search version -->
|
||||||
<hibernate_search_version>5.7.1.Final</hibernate_search_version>
|
<hibernate_search_version>5.7.1.Final</hibernate_search_version>
|
||||||
|
@ -419,9 +420,9 @@
|
||||||
<maven_license_plugin_version>1.8</maven_license_plugin_version>
|
<maven_license_plugin_version>1.8</maven_license_plugin_version>
|
||||||
<phloc_schematron_version>2.7.1</phloc_schematron_version>
|
<phloc_schematron_version>2.7.1</phloc_schematron_version>
|
||||||
<phloc_commons_version>4.4.11</phloc_commons_version>
|
<phloc_commons_version>4.4.11</phloc_commons_version>
|
||||||
<spring_version>5.0.0.RELEASE</spring_version>
|
<spring_version>5.0.3.RELEASE</spring_version>
|
||||||
<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
|
<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
|
||||||
<thymeleaf-version>3.0.7.RELEASE</thymeleaf-version>
|
<thymeleaf-version>3.0.9.RELEASE</thymeleaf-version>
|
||||||
|
|
||||||
<!-- We are aiming to still work on a very old version of SLF4j even though we depend on the newest, just to be nice to users of the API. This version is tested in the hapi-fhir-cobertura. -->
|
<!-- We are aiming to still work on a very old version of SLF4j even though we depend on the newest, just to be nice to users of the API. This version is tested in the hapi-fhir-cobertura. -->
|
||||||
<slf4j_target_version>1.6.0</slf4j_target_version>
|
<slf4j_target_version>1.6.0</slf4j_target_version>
|
||||||
|
@ -798,6 +799,21 @@
|
||||||
<artifactId>jetty-servlets</artifactId>
|
<artifactId>jetty-servlets</artifactId>
|
||||||
<version>${jetty_version}</version>
|
<version>${jetty_version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-io</artifactId>
|
||||||
|
<version>${jetty_version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-continuation</artifactId>
|
||||||
|
<version>${jetty_version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-security</artifactId>
|
||||||
|
<version>${jetty_version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-servlet</artifactId>
|
<artifactId>jetty-servlet</artifactId>
|
||||||
|
@ -818,6 +834,11 @@
|
||||||
<artifactId>jetty-webapp</artifactId>
|
<artifactId>jetty-webapp</artifactId>
|
||||||
<version>${jetty_version}</version>
|
<version>${jetty_version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-xml</artifactId>
|
||||||
|
<version>${jetty_version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||||
<artifactId>websocket-api</artifactId>
|
<artifactId>websocket-api</artifactId>
|
||||||
|
@ -1114,7 +1135,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-dependency-plugin</artifactId>
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
<version>2.10</version>
|
<version>3.0.2</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -1210,7 +1231,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.codehaus.mojo</groupId>
|
<groupId>org.codehaus.mojo</groupId>
|
||||||
<artifactId>versions-maven-plugin</artifactId>
|
<artifactId>versions-maven-plugin</artifactId>
|
||||||
<version>2.2</version>
|
<version>2.5</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
|
|
@ -8,6 +8,17 @@
|
||||||
<body>
|
<body>
|
||||||
<release version="3.3.0" date="TBD">
|
<release version="3.3.0" date="TBD">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
The version of a few dependencies have been bumped to the
|
||||||
|
latest versions (dependent HAPI modules listed in brackets):
|
||||||
|
<![CDATA[
|
||||||
|
<ul>
|
||||||
|
<li>Hibernate (JPA): 5.2.10.Final -> 5.2.12.Final</li>
|
||||||
|
<li>Spring (JPA): 5.0.0 -> 5.0.3</li>
|
||||||
|
<li>Thymeleaf (Web Tespage Overlay): 3.0.7.RELEASE -> 3.0.9.RELEASE</li>
|
||||||
|
</ul>
|
||||||
|
]]>
|
||||||
|
</action>
|
||||||
|
<action type="add">
|
||||||
This release corrects an inefficiency in the JPA Server, but requires a schema
|
This release corrects an inefficiency in the JPA Server, but requires a schema
|
||||||
change in order to update. Prior to this version of HAPI FHIR, a CLOB column
|
change in order to update. Prior to this version of HAPI FHIR, a CLOB column
|
||||||
containing the complete resource body was stored in two
|
containing the complete resource body was stored in two
|
||||||
|
@ -32,6 +43,17 @@
|
||||||
Fix an issue where the JPA server crashed while attempting to normalize string values
|
Fix an issue where the JPA server crashed while attempting to normalize string values
|
||||||
containing Korean text. Thanks to GitHub user @JoonggeonLee for reporting!
|
containing Korean text. Thanks to GitHub user @JoonggeonLee for reporting!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
An issue was solved where it was possible for server interceptors
|
||||||
|
to have both processingCompletedNormally and handleException called
|
||||||
|
if the stream.close() method threw an exception. Thanks to Carlos
|
||||||
|
Eduardo Lara Augusto for investigating!
|
||||||
|
</action>
|
||||||
|
<action type="remove" issue="831">
|
||||||
|
The <![CDATA[<code>@TagListParam</code>]]> annotation has been removed. This
|
||||||
|
annotation had no use after DSTU1 but never got deleted and was misleading. Thanks
|
||||||
|
to Angelo Kastroulis for reporting!
|
||||||
|
</action>
|
||||||
<action type="add">
|
<action type="add">
|
||||||
A new method overload has been added to IServerInterceptor:
|
A new method overload has been added to IServerInterceptor:
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
|
|
Loading…
Reference in New Issue