Work on conditional operations in JPA

This commit is contained in:
jamesagnew 2015-05-07 09:01:28 -04:00
parent 7585256037
commit a09c4438f2
7 changed files with 289 additions and 16 deletions

View File

@ -24,8 +24,10 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URL;
import java.text.Normalizer; import java.text.Normalizer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -636,7 +638,12 @@ public abstract class BaseFhirDao implements IDao {
SearchParameterMap paramMap = new SearchParameterMap(); SearchParameterMap paramMap = new SearchParameterMap();
List<NameValuePair> parameters; List<NameValuePair> parameters;
try { try {
parameters = URLEncodedUtils.parse(new URI(theMatchUrl), "UTF-8"); String matchUrl = theMatchUrl;
if (matchUrl.indexOf('?') == -1) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Error was: URL does not contain any parameters ('?' not detected)");
}
matchUrl = matchUrl.replace("|", "%7C");
parameters = URLEncodedUtils.parse(new URI(matchUrl), "UTF-8");
} catch (URISyntaxException e) { } catch (URISyntaxException e) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Error was: " + e.toString()); throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Error was: " + e.toString());
} }

View File

@ -200,7 +200,10 @@ public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
String url = extractTransactionUrlOrThrowException(nextEntry, verb); String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url); UrlParts parts = parseUrl(verb.getCode(), url);
if (parts.getResourceId() != null) { if (res.getId().hasIdPart() && isBlank(parts.getResourceId())) {
parts.setResourceId(res.getId().getIdPart());
}
if (isNotBlank(parts.getResourceId())) {
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId())); res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
outcome = resourceDao.update(res, null, false); outcome = resourceDao.update(res, null, false);
} else { } else {

View File

@ -446,6 +446,22 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea
} }
systems.add(null); systems.add(null);
codes.add(nextValue.getValueAsString()); codes.add(nextValue.getValueAsString());
} else if (nextObject instanceof CodingDt) {
CodingDt nextValue = (CodingDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
String nextSystem = nextValue.getSystemElement().getValueAsString();
String nextCode = nextValue.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
systems.add(nextSystem);
codes.add(nextCode);
}
if (!nextValue.getDisplayElement().isEmpty()) {
systems.add(null);
codes.add(nextValue.getDisplayElement().getValue());
}
} else if (nextObject instanceof CodeableConceptDt) { } else if (nextObject instanceof CodeableConceptDt) {
CodeableConceptDt nextCC = (CodeableConceptDt) nextObject; CodeableConceptDt nextCC = (CodeableConceptDt) nextObject;
if (!nextCC.getTextElement().isEmpty()) { if (!nextCC.getTextElement().isEmpty()) {

View File

@ -217,8 +217,8 @@ public class FhirResourceDaoDstu2Test {
} }
@Test @Test
public void testCreateWithIfNoneExist() { public void testCreateWithIfNoneExistBasic() {
String methodName = "testCreateWithIfNoneExist"; String methodName = "testCreateWithIfNoneExistBasic";
MethodOutcome results; MethodOutcome results;
Patient p = new Patient(); Patient p = new Patient();

View File

@ -4,7 +4,15 @@ import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
@ -13,6 +21,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.builder.CompareToBuilder;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpGet;
@ -31,6 +40,8 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.google.common.net.UrlEscapers;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
@ -89,6 +100,7 @@ public class ResourceProviderDstu2Test {
private static DaoConfig ourDaoConfig; private static DaoConfig ourDaoConfig;
private static CloseableHttpClient ourHttpClient; private static CloseableHttpClient ourHttpClient;
private static String ourServerBase; private static String ourServerBase;
private static int ourPort;
// private static JpaConformanceProvider ourConfProvider; // private static JpaConformanceProvider ourConfProvider;
@ -147,6 +159,7 @@ public class ResourceProviderDstu2Test {
String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt); String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt);
HttpPost post = new HttpPost(ourServerBase + "/Patient"); HttpPost post = new HttpPost(ourServerBase + "/Patient");
post.addHeader(Constants.HEADER_IF_NONE_EXIST, "Patient?name=" + methodName);
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post); CloseableHttpResponse response = ourHttpClient.execute(post);
IdDt id; IdDt id;
@ -166,7 +179,7 @@ public class ResourceProviderDstu2Test {
try { try {
assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue(); String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
assertEquals(id.getValue(), newIdString); assertEquals(id.getValue(), newIdString); // version should match for conditional create
} finally { } finally {
response.close(); response.close();
} }
@ -181,7 +194,7 @@ public class ResourceProviderDstu2Test {
pt.addName().addFamily(methodName); pt.addName().addFamily(methodName);
String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt); String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt);
HttpPost post = new HttpPost(ourServerBase + "/Patient"); HttpPost post = new HttpPost(ourServerBase + "/Patient?name=" + methodName);
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post); CloseableHttpResponse response = ourHttpClient.execute(post);
IdDt id; IdDt id;
@ -200,7 +213,7 @@ public class ResourceProviderDstu2Test {
try { try {
assertEquals(200, response.getStatusLine().getStatusCode()); assertEquals(200, response.getStatusLine().getStatusCode());
IdDt newId = new IdDt(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue()); IdDt newId = new IdDt(response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue());
assertEquals(id.toVersionless(), newId.toVersionless()); assertEquals(id.toVersionless(), newId.toVersionless()); // version shouldn't match for conditional update
assertNotEquals(id, newId); assertNotEquals(id, newId);
} finally { } finally {
response.close(); response.close();
@ -209,8 +222,8 @@ public class ResourceProviderDstu2Test {
} }
@Test @Test
public void testDeleteResourceConditional() throws IOException { public void testDeleteResourceConditional1() throws IOException {
String methodName = "testDeleteResourceConditional"; String methodName = "testDeleteResourceConditional1";
Patient pt = new Patient(); Patient pt = new Patient();
pt.addName().addFamily(methodName); pt.addName().addFamily(methodName);
@ -248,6 +261,67 @@ public class ResourceProviderDstu2Test {
} }
/**
* Based on email from Rene Spronk
*/
@Test
public void testDeleteResourceConditional2() throws IOException, Exception {
String methodName = "testDeleteResourceConditional2";
Patient pt = new Patient();
pt.addName().addFamily(methodName);
pt.addIdentifier().setSystem("http://ghh.org/patient").setValue("555-44-4444");
String resource = ourFhirCtx.newXmlParser().encodeResourceToString(pt);
HttpPost post = new HttpPost(ourServerBase + "/Patient");
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post);
IdDt id;
try {
assertEquals(201, response.getStatusLine().getStatusCode());
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
id = new IdDt(newIdString);
} finally {
response.close();
}
/*
* Try it with a raw socket call. The Apache client won't let us use the unescaped "|" in the URL
* but we want to make sure that works too..
*/
Socket sock = new Socket();
try {
sock.connect(new InetSocketAddress("localhost", ourPort));
sock.getOutputStream().write(("DELETE " + "/fhir/context/Patient?identifier=" + ("http://ghh.org/patient|555-44-4444")).getBytes("UTF-8"));
sock.getOutputStream().write("\n\n".getBytes("UTF-8"));
sock.getOutputStream().flush();
InputStream inputStream = sock.getInputStream();
byte[] buf = new byte[10000];
int count;
StringBuilder b = new StringBuilder();
while ((count = inputStream.read(buf)) > 0) {
b.append(new String(buf, 0, count, Charset.forName("UTF-8")));
}
String resp = b.toString();
ourLog.info("Resp: {}", resp);
} finally {
sock.close();
}
HttpGet read = new HttpGet(ourServerBase + "/Patient/" + id.getIdPart());
response = ourHttpClient.execute(read);
try {
ourLog.info(response.toString());
assertEquals(Constants.STATUS_HTTP_410_GONE, response.getStatusLine().getStatusCode());
} finally {
response.close();
}
}
/** /**
* Test for issue #60 * Test for issue #60
*/ */
@ -746,8 +820,7 @@ public class ResourceProviderDstu2Test {
p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01"); p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01");
IdDt p1Id = ourClient.create().resource(p1).execute().getId(); IdDt p1Id = ourClient.create().resource(p1).execute().getId();
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint() Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint().execute();
.execute();
assertEquals(1, actual.size()); assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart()); assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
@ -845,8 +918,7 @@ public class ResourceProviderDstu2Test {
assertThat(p1Id.getValue(), containsString("Patient/testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2/_history")); assertThat(p1Id.getValue(), containsString("Patient/testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2/_history"));
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2")) Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testUpdateWithClientSuppliedIdWhichDoesntExistRpDstu2")).encodedJson().prettyPrint().execute();
.encodedJson().prettyPrint().execute();
assertEquals(1, actual.size()); assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart()); assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
@ -862,13 +934,13 @@ public class ResourceProviderDstu2Test {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@BeforeClass @BeforeClass
public static void beforeClass() throws Exception { public static void beforeClass() throws Exception {
int port = RandomServerPortProvider.findFreePort(); ourPort = RandomServerPortProvider.findFreePort();
RestfulServer restServer = new RestfulServer(); RestfulServer restServer = new RestfulServer();
ourFhirCtx = FhirContext.forDstu2(); ourFhirCtx = FhirContext.forDstu2();
restServer.setFhirContext(ourFhirCtx); restServer.setFhirContext(ourFhirCtx);
ourServerBase = "http://localhost:" + port + "/fhir/context"; ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
ourAppCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu2.xml", "fhir-jpabase-spring-test-config.xml"); ourAppCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu2.xml", "fhir-jpabase-spring-test-config.xml");
@ -886,7 +958,7 @@ public class ResourceProviderDstu2Test {
restServer.setPagingProvider(new FifoMemoryPagingProvider(10)); restServer.setPagingProvider(new FifoMemoryPagingProvider(10));
ourServer = new Server(port); ourServer = new Server(ourPort);
ServletContextHandler proxyHandler = new ServletContextHandler(); ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/"); proxyHandler.setContextPath("/");

View File

@ -41,6 +41,14 @@ public class SystemProviderTest {
ourLog.info(response); ourLog.info(response);
} }
@Test
public void testTransactionFromBundle2() throws Exception {
InputStream bundleRes = SystemProviderTest.class.getResourceAsStream("/transaction_link_patient_eve_temp.xml");
String bundle = IOUtils.toString(bundleRes);
String response = ourClient.transaction().withBundle(bundle).prettyPrint().execute();
ourLog.info(response);
}
@AfterClass @AfterClass
public static void afterClass() throws Exception { public static void afterClass() throws Exception {

View File

@ -0,0 +1,167 @@
<Bundle xmlns="http://hl7.org/fhir">
<id value="ringholm1430996763590912"/>
<type value="transaction"/>
<entry>
<resource>
<Provenance>
<id value="ringholm1430996763591053"/>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">Authored on 15-Feb 2015 by GHH.</div>
</text>
<target>
<!-- unversioned, part of a transaction -->
<reference value="Patient/b555-44-4444"/>
</target>
<recorded value="2015-05-07T13:06:03+01:00"/>
<reason>
<text value="Patient validated demographics."/>
</reason>
<agent>
<role>
<system value="http://hl7.org/fhir/provenance-participant-role"/>
<code value="author"/>
</role>
<type>
<system value="http://hl7.org/fhir/provenance-participant-type"/>
<code value="patient"/>
</type>
<referenceReference>
<reference value="Patient/b555-44-4444"/>
<display value="Patient Everywoman"/>
</referenceReference>
<display value="Eve Everywoman"/>
</agent>
</Provenance>
</resource>
<transaction>
<method value="POST"/>
</transaction>
</entry>
<entry>
<resource>
<Patient>
<id value="b555-44-4444"/>
<extension url="http://ihe.net/ITI-78/Profile/pdqm#mothersMaidenName">
<valueHumanName>
<family value="Jones"/>
</valueHumanName>
</extension>
<identifier>
<use value="official"/>
<system value="http://ghh.org/patient"/>
<value value="555-44-4444"/>
</identifier>
<identifier>
<use value="official"/>
<system value="http://www.ohio.gov/dmv/driverslicence"/>
<value value="67-A4335"/>
<period>
<end value="2003-05-20"/>
</period>
</identifier>
<name>
<use value="official"/>
<family value="Everywoman"/>
<given value="Eve E."/>
</name>
<telecom>
<system value="phone"/>
<value value="(206)3345232"/>
<use value="home"/>
</telecom>
<telecom>
<system value="phone"/>
<value value="(206)752-121"/>
<use value="work"/>
</telecom>
<gender value="female"/>
<birthDate value="1962-03-20"/>
<address>
<line value="153 Fernwood Dr."/>
<city value="Statesville"/>
<state value="OH"/>
<postalCode value="35292"/>
</address>
<managingOrganization>
<reference value="Organization/GHH"/>
<display value="Good Health Hospital"/>
</managingOrganization>
<link>
<other>
<reference value="Patient/temp6789"/>
</other>
<type value="seealso"/>
</link>
<active value="true"/>
</Patient>
</resource>
<transaction>
<method value="PUT"/>
<url value="Patient/?identifier=http://ghh.org/patient%7C555-44-4444"/>
</transaction>
</entry>
<entry>
<resource>
<Patient>
<!-- Jane Doe registered in the emergency department -->
<id value="temp6789"/>
<identifier>
<use value="temp"/>
<system value="http://ghh.org/patient"/>
<value value="temp6789"/>
</identifier>
<name>
<use value="temp"/>
<family value="Doe 6789"/>
<given value="Jane"/>
</name>
<gender value="female"/>
<managingOrganization>
<reference value="Organization/GHH"/>
<display value="Good Health Hospital"/>
</managingOrganization>
<link>
<other>
<reference value="Patient/b555-44-4444"/>
</other>
<type value="replace"/>
</link>
<active value="true"/>
</Patient>
</resource>
<transaction>
<method value="PUT"/>
<url value="Patient/?identifier=http://ghh.org/patient%7Ctemp6789"/>
</transaction>
</entry>
<entry>
<resource>
<Organization>
<id value="GHH"/>
<identifier>
<!-- Identifier for the GHH hospital -->
<use value="official"/>
<system value="http://ghh.org/department"/>
<value value="GHH"/>
</identifier>
<name value="Good Health Hospital"/>
<type>
<!-- GHH is a Hospital -->
<coding>
<system value="http://snomed.info/sct"/>
<code value="22232009"/>
<display value="Hospital"/>
</coding>
</type>
<active value="true"/>
</Organization>
</resource>
<transaction>
<method value="POST"/>
<url value="Organization"/>
<ifNoneExist value="Organization/?identifier=http://ghh.org/department%7CGHH"/>
</transaction>
</entry>
</Bundle>