Returned resource objects from server methods should not be modified
while converting to a bundle
This commit is contained in:
parent
f632d119b4
commit
06a1e459d4
|
@ -1,75 +0,0 @@
|
|||
package ca.uhn.fhir.model.base.resource;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 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.util.List;
|
||||
|
||||
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
|
||||
import ca.uhn.fhir.model.api.BaseResource;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.IResourceBlock;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
|
||||
public abstract class BaseOperationOutcome extends BaseResource implements IResource {
|
||||
|
||||
public abstract BaseIssue addIssue();
|
||||
|
||||
public abstract List<? extends BaseIssue> getIssue();
|
||||
|
||||
public abstract BaseIssue getIssueFirstRep();
|
||||
|
||||
public static abstract class BaseIssue extends BaseIdentifiableElement implements IResourceBlock {
|
||||
<<<<<<< HEAD
|
||||
|
||||
public abstract CodeDt getSeverityElement();
|
||||
|
||||
=======
|
||||
|
||||
public abstract CodeDt getSeverityElement();
|
||||
|
||||
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
|
||||
public abstract StringDt getDetailsElement();
|
||||
|
||||
public abstract BaseCodingDt getType();
|
||||
|
||||
<<<<<<< HEAD
|
||||
public abstract BaseIssue addLocation( String theString);
|
||||
=======
|
||||
public abstract BaseIssue addLocation(String theString);
|
||||
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
|
||||
|
||||
public abstract BaseIssue setDetails(String theString);
|
||||
|
||||
public abstract StringDt getLocationFirstRep();
|
||||
<<<<<<< HEAD
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
=======
|
||||
|
||||
}
|
||||
|
||||
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
|
||||
}
|
|
@ -1009,8 +1009,7 @@ public class RestfulServer extends HttpServlet {
|
|||
}
|
||||
|
||||
if (theServer.getAddProfileTag() != AddProfileTagEnum.NEVER) {
|
||||
for (int i = 0; i < resourceList.size(); i++) {
|
||||
IResource nextRes = resourceList.get(i);
|
||||
for (IResource nextRes : resourceList) {
|
||||
RuntimeResourceDefinition def = theServer.getFhirContext().getResourceDefinition(nextRes);
|
||||
if (theServer.getAddProfileTag() == AddProfileTagEnum.ALWAYS || !def.isStandardProfile()) {
|
||||
addProfileToBundleEntry(theServer.getFhirContext(), nextRes);
|
||||
|
@ -1088,7 +1087,7 @@ public class RestfulServer extends HttpServlet {
|
|||
continue;
|
||||
}
|
||||
|
||||
IdDt id = nextRes.getId().toVersionless();
|
||||
IdDt id = nextRes.getId();
|
||||
if (id.hasResourceType() == false) {
|
||||
String resName = theContext.getResourceDefinition(nextRes).getName();
|
||||
id = id.withResourceType(resName);
|
||||
|
@ -1099,8 +1098,6 @@ public class RestfulServer extends HttpServlet {
|
|||
addedResourcesThisPass.add(nextRes);
|
||||
}
|
||||
|
||||
nextRef.setResource(null);
|
||||
nextRef.setReference(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,93 +43,33 @@ import ca.uhn.fhir.parser.DataFormatException;
|
|||
|
||||
public class FhirTerser {
|
||||
|
||||
private FhirContext myContext;
|
||||
|
||||
public FhirTerser(FhirContext theContext) {
|
||||
super();
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
private FhirContext myContext;
|
||||
|
||||
public BaseRuntimeChildDefinition getDefinition(Class<? extends IResource> theResourceType, String thePath) {
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
|
||||
|
||||
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
|
||||
|
||||
List<String> parts = Arrays.asList(thePath.split("\\."));
|
||||
List<String> subList = parts.subList(1, parts.size());
|
||||
if (subList.size() < 1) {
|
||||
throw new ConfigurationException("Invalid path: " + thePath);
|
||||
}
|
||||
return getDefinition(currentDef, subList);
|
||||
|
||||
}
|
||||
|
||||
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
|
||||
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
|
||||
|
||||
if (theSubList.size() == 1) {
|
||||
return nextDef;
|
||||
} else {
|
||||
BaseRuntimeElementCompositeDefinition<?> cmp = (BaseRuntimeElementCompositeDefinition<?>) nextDef.getChildByName(theSubList.get(0));
|
||||
return getDefinition(cmp, theSubList.subList(1, theSubList.size()));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Object> getValues(IResource theResource, String thePath) {
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
|
||||
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
|
||||
Object currentObj = theResource;
|
||||
|
||||
List<String> parts = Arrays.asList(thePath.split("\\."));
|
||||
List<String> subList = parts.subList(1, parts.size());
|
||||
if (subList.size() < 1) {
|
||||
throw new ConfigurationException("Invalid path: " + thePath);
|
||||
}
|
||||
return getValues(currentDef, currentObj, subList);
|
||||
|
||||
}
|
||||
|
||||
private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) {
|
||||
String name = theSubList.get(0);
|
||||
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
|
||||
List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj);
|
||||
List<Object> retVal = new ArrayList<Object>();
|
||||
|
||||
if (theSubList.size() == 1) {
|
||||
retVal.addAll(values);
|
||||
} else {
|
||||
for (IElement nextElement : values) {
|
||||
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
|
||||
List<?> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()));
|
||||
retVal.addAll(foundValues);
|
||||
private <T extends IElement> void addUndeclaredExtensions(IElement theElement, BaseRuntimeElementDefinition<?> theDefinition, BaseRuntimeChildDefinition theChildDefinition,
|
||||
IModelVisitor theCallback) {
|
||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement;
|
||||
for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) {
|
||||
theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt);
|
||||
addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit all elements in a given resource
|
||||
*
|
||||
* @param theResource The resource to visit
|
||||
* @param theVisitor The visitor
|
||||
*/
|
||||
public void visit(IResource theResource, IModelVisitor theVisitor) {
|
||||
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
|
||||
visit(theResource, null, def, theVisitor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing all child elements (including the resource itself) which are <b>non-empty</b> and are
|
||||
* either of the exact type specified, or are a subclass of that type.
|
||||
* Returns a list containing all child elements (including the resource itself) which are <b>non-empty</b> and are either of the exact type specified, or are a subclass of that type.
|
||||
* <p>
|
||||
* For example, specifying a type of {@link StringDt} would return all non-empty string instances within the
|
||||
* message. Specifying a type of {@link IResource} would return the resource itself, as well as any contained
|
||||
* resources.
|
||||
* For example, specifying a type of {@link StringDt} would return all non-empty string instances within the message. Specifying a type of {@link IResource} would return the resource itself, as
|
||||
* well as any contained resources.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not
|
||||
* decend into linked resources (e.g. {@link ResourceReferenceDt#getResource()})
|
||||
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not decend into linked resources (e.g.
|
||||
* {@link ResourceReferenceDt#getResource()})
|
||||
* </p>
|
||||
*
|
||||
* @param theResource
|
||||
|
@ -156,7 +96,8 @@ public class FhirTerser {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
|
||||
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition,
|
||||
ExtensionDt theNextExt) {
|
||||
if (theType.isAssignableFrom(theNextExt.getClass())) {
|
||||
retVal.add((T) theNextExt);
|
||||
}
|
||||
|
@ -168,25 +109,85 @@ public class FhirTerser {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
|
||||
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
|
||||
|
||||
if (theSubList.size() == 1) {
|
||||
return nextDef;
|
||||
} else {
|
||||
BaseRuntimeElementCompositeDefinition<?> cmp = (BaseRuntimeElementCompositeDefinition<?>) nextDef.getChildByName(theSubList.get(0));
|
||||
return getDefinition(cmp, theSubList.subList(1, theSubList.size()));
|
||||
}
|
||||
}
|
||||
|
||||
public BaseRuntimeChildDefinition getDefinition(Class<? extends IResource> theResourceType, String thePath) {
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
|
||||
|
||||
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
|
||||
|
||||
List<String> parts = Arrays.asList(thePath.split("\\."));
|
||||
List<String> subList = parts.subList(1, parts.size());
|
||||
if (subList.size() < 1) {
|
||||
throw new ConfigurationException("Invalid path: " + thePath);
|
||||
}
|
||||
return getDefinition(currentDef, subList);
|
||||
|
||||
}
|
||||
|
||||
private List<Object> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList) {
|
||||
String name = theSubList.get(0);
|
||||
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(name);
|
||||
List<? extends IElement> values = nextDef.getAccessor().getValues(theCurrentObj);
|
||||
List<Object> retVal = new ArrayList<Object>();
|
||||
|
||||
if (theSubList.size() == 1) {
|
||||
retVal.addAll(values);
|
||||
} else {
|
||||
for (IElement nextElement : values) {
|
||||
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
|
||||
List<?> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()));
|
||||
retVal.addAll(foundValues);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public List<Object> getValues(IResource theResource, String thePath) {
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
|
||||
BaseRuntimeElementCompositeDefinition<?> currentDef = def;
|
||||
Object currentObj = theResource;
|
||||
|
||||
List<String> parts = Arrays.asList(thePath.split("\\."));
|
||||
List<String> subList = parts.subList(1, parts.size());
|
||||
if (subList.size() < 1) {
|
||||
throw new ConfigurationException("Invalid path: " + thePath);
|
||||
}
|
||||
return getValues(currentDef, currentObj, subList);
|
||||
|
||||
}
|
||||
|
||||
private <T extends IElement> void visit(IElement theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
|
||||
theCallback.acceptElement(theElement, theChildDefinition, theDefinition);
|
||||
addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
|
||||
|
||||
// if (theElement.isEmpty()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (theElement.isEmpty()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
switch (theDefinition.getChildType()) {
|
||||
case PRIMITIVE_XHTML:
|
||||
case PRIMITIVE_DATATYPE:
|
||||
// These are primitive types
|
||||
break;
|
||||
case RESOURCE_REF:
|
||||
ResourceReferenceDt resRefDt = (ResourceReferenceDt)theElement;
|
||||
ResourceReferenceDt resRefDt = (ResourceReferenceDt) theElement;
|
||||
if (resRefDt.getReference().getValue() == null && resRefDt.getResource() != null) {
|
||||
IResource theResource = resRefDt.getResource();
|
||||
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
|
||||
visit(theResource, null, def, theCallback);
|
||||
if (theResource.getId() == null || theResource.getId().isEmpty() || theResource.getId().isLocal()) {
|
||||
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
|
||||
visit(theResource, null, def, theCallback);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case RESOURCE_BLOCK:
|
||||
|
@ -205,7 +206,7 @@ public class FhirTerser {
|
|||
}
|
||||
BaseRuntimeElementDefinition<?> childElementDef;
|
||||
childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
|
||||
|
||||
|
||||
if (childElementDef == null) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Found value of type[");
|
||||
|
@ -244,14 +245,17 @@ public class FhirTerser {
|
|||
}
|
||||
}
|
||||
|
||||
private <T extends IElement> void addUndeclaredExtensions(IElement theElement, BaseRuntimeElementDefinition<?> theDefinition, BaseRuntimeChildDefinition theChildDefinition, IModelVisitor theCallback) {
|
||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions containingElement = (ISupportsUndeclaredExtensions) theElement;
|
||||
for (ExtensionDt nextExt : containingElement.getUndeclaredExtensions()) {
|
||||
theCallback.acceptUndeclaredExtension(containingElement, theChildDefinition, theDefinition, nextExt);
|
||||
addUndeclaredExtensions(nextExt, theDefinition, theChildDefinition, theCallback);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Visit all elements in a given resource
|
||||
*
|
||||
* @param theResource
|
||||
* The resource to visit
|
||||
* @param theVisitor
|
||||
* The visitor
|
||||
*/
|
||||
public void visit(IResource theResource, IModelVisitor theVisitor) {
|
||||
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
|
||||
visit(theResource, null, def, theVisitor);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,14 +1,22 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.*;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
|
@ -22,33 +30,55 @@ import org.junit.AfterClass;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
|
||||
import ca.uhn.fhir.model.dstu.resource.Location;
|
||||
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class ReferenceParameterTest {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReferenceParameterTest.class);
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
ourCtx = servlet.getFhirContext();
|
||||
servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider(), new DummyLocationResourceProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
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();
|
||||
|
||||
ourCtx = servlet.getFhirContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithValue() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123");
|
||||
|
@ -66,6 +96,42 @@ public class ReferenceParameterTest {
|
|||
assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchReturnVersionedReferenceInResponse() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findPatientWithVersion");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
List<BundleEntry> entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries();
|
||||
assertEquals(2, entries.size());
|
||||
Patient p = (Patient) entries.get(0).getResource();
|
||||
|
||||
assertEquals(0, p.getContained().getContainedResources().size());
|
||||
assertEquals("22", p.getId().getIdPart());
|
||||
assertEquals("33", p.getId().getVersionIdPart());
|
||||
|
||||
assertEquals("44", p.getManagingOrganization().getReference().getIdPart());
|
||||
assertEquals("55", p.getManagingOrganization().getReference().getVersionIdPart());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadReturnVersionedReferenceInResponse() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/22");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, responseContent);
|
||||
|
||||
assertThat(status.getFirstHeader("Content-Location").getValue(), containsString("Patient/22/_history/33"));
|
||||
|
||||
assertEquals("44", p.getManagingOrganization().getReference().getIdPart());
|
||||
assertEquals("55", p.getManagingOrganization().getReference().getVersionIdPart());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithValueAndType() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123");
|
||||
|
@ -129,7 +195,7 @@ public class ReferenceParameterTest {
|
|||
assertThat(responseContent, containsString("value=\"thePartOfId po123 null\""));
|
||||
assertThat(responseContent, containsString("value=\"thePartOfName poname\""));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithMultipleParamsOfTheSameName4() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname");
|
||||
|
@ -160,7 +226,7 @@ public class ReferenceParameterTest {
|
|||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("value=\"theBarId Organization/po123 bar\""));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithMultipleParamsOfTheSameName7() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof:Organization=po123");
|
||||
|
@ -179,7 +245,6 @@ public class ReferenceParameterTest {
|
|||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithValueAndChain() throws Exception {
|
||||
{
|
||||
|
@ -198,8 +263,6 @@ public class ReferenceParameterTest {
|
|||
}
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReferenceParameterTest.class);
|
||||
|
||||
@Test
|
||||
public void testParamTypesInConformanceStatement() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata?_pretty=true");
|
||||
|
@ -222,35 +285,6 @@ public class ReferenceParameterTest {
|
|||
assertEquals(ResourceTypeEnum.ORGANIZATION, param.getTarget().get(0).getValueAsEnum());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
ourCtx = servlet.getFhirContext();
|
||||
servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider(), new DummyLocationResourceProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
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();
|
||||
|
||||
ourCtx = servlet.getFhirContext();
|
||||
}
|
||||
|
||||
public static class DummyOrganizationResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
|
@ -349,6 +383,34 @@ public class ReferenceParameterTest {
|
|||
*/
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Search(queryName="findPatientWithVersion")
|
||||
public List<Patient> findPatientWithVersion() {
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
||||
Patient p = createPatient();
|
||||
|
||||
retVal.add(p);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Read
|
||||
public Patient read(@IdParam IdDt theId) {
|
||||
return createPatient();
|
||||
}
|
||||
|
||||
private Patient createPatient() {
|
||||
Patient p = new Patient();
|
||||
p.setId("Patient/22/_history/33");
|
||||
p.addIdentifier("urn:foo", "findPatientWithVersion");
|
||||
|
||||
Observation org = new Observation();
|
||||
org.setId("Observation/44/_history/55");
|
||||
p.setManagingOrganization(new ResourceReferenceDt(org));
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
@Search
|
||||
public List<Patient> findPatient(@OptionalParam(name = Patient.SP_PROVIDER, targetTypes = { Organization.class }) ReferenceParam theParam) {
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
|
|
5
pom.xml
5
pom.xml
|
@ -109,6 +109,11 @@
|
|||
<id>petromykhailysyn</id>
|
||||
<name>Petro Mykhailyshyn</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>tahurac</id>
|
||||
<name>Tahura Chaudhry</name>
|
||||
<organization>University Health Network</organization>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</properties>
|
||||
<body>
|
||||
<release version="0.8" date="TBD">
|
||||
<action tyle="add">
|
||||
<action type="add">
|
||||
<![CDATA[<b>API CHANGE:</b>]]> The "FHIR structures" for DSTU1 (the classes which model the
|
||||
resources and composite datatypes) have been moved out of the core JAR into their
|
||||
own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast
|
||||
|
@ -39,7 +39,7 @@
|
|||
defined extension which was of a composite type. Thanks to Bill de Beaubien for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="44" dev="petromykhailysyn">
|
||||
Remove unnessecary IOException from narrative generator API. Thanks to
|
||||
Remove unnecessary IOException from narrative generator API. Thanks to
|
||||
Petro Mykhailysyn for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="48" dev="wdebeau1">
|
||||
|
@ -105,7 +105,8 @@
|
|||
<action type="add">
|
||||
When using Generic Client, if performing a
|
||||
<![CDATA[create]]> or <![CDATA[update]]> operation using a String as the resource body,
|
||||
the client will auto-detect the FHIR encoding style and send an appropriate Content-Type header.
|
||||
the client will auto-detect the FHIR encoding style and send an appropriate
|
||||
<![CDATA[Content-Type]]> header.
|
||||
</action>
|
||||
<action type="fix" issue="52">
|
||||
JPA module (and public HAPI-FHIR test server) were unable to process resource types
|
||||
|
@ -117,7 +118,7 @@
|
|||
Generic/Fluent Client "create" and "update" method requests were not setting a content type header
|
||||
</action>
|
||||
<action type="add" issue="53" dev="petromykhailysyn">
|
||||
DateDt left precision value as null in the constructor
|
||||
DateDt left precision value as <![CDATA[null]]> in the constructor
|
||||
<![CDATA[DateDt(Date)]]>.
|
||||
</action>
|
||||
<action type="fix">
|
||||
|
@ -126,6 +127,25 @@
|
|||
"[base url]/Patient/123" but if the RP returns ID "http://foo/Patient/123" the ID will be
|
||||
returned exactly as is. Thanks to Bill de Beaubien for the suggestion!
|
||||
</action>
|
||||
<action type="fix" issue="55">
|
||||
JPA module Transaction operation was not correctly replacing logical IDs
|
||||
beginning with "cid:" with server assigned IDs, as required by the
|
||||
specification.
|
||||
</action>
|
||||
<action type="fix" dev="tahurac">
|
||||
<![CDATA[FhirTerser]]> did not visit or find children in contained resources when
|
||||
searching a resource. This caused server implementations to not always return contained
|
||||
resources when they are included with a resource being returned.
|
||||
</action>
|
||||
<action type="add" dev="lmds">
|
||||
Add a method <![CDATA[String IResource#getResourceName()]]> which returns the name of the
|
||||
resource in question (e.g. "Patient", or "Observation"). This is intended as a
|
||||
convenience to users.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Do not strip version from resource references in resources returned
|
||||
from server search methods. Thanks to Bill de Beaubien for reporting!
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.7" date="2014-Oct-23">
|
||||
<action type="add" issue="30">
|
||||
|
@ -310,7 +330,7 @@
|
|||
update. This has no effect other than to switch between the HTTP 200 and HTTP 201 status codes on the
|
||||
response, but this may be useful in some circumstances.
|
||||
</action>
|
||||
<action type="fix">
|
||||
<action type="fix" dev="tahurac">
|
||||
Annotation client search methods with a specific resource type (e.g. List<Patient> search())
|
||||
won't return any resources that aren't of the correct type that are received in a response
|
||||
bundle (generally these are referenced resources, so they are populated in the reference fields instead).
|
||||
|
|
|
@ -97,7 +97,7 @@ patient.getManagingOrganization().setReference("Organization/124362");]]></sourc
|
|||
To do this, you can implement your server method to simply return
|
||||
<code>List<IResource></code> and then simply add your extra resources to
|
||||
the list. Another technique however, is to populate the reference as shown
|
||||
in the example above, but ensure that the referenced resource has an ID set.
|
||||
in the example below, but ensure that the referenced resource has an ID set.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
Loading…
Reference in New Issue