Only do one pass of validation during a JPA transaction

This commit is contained in:
jamesagnew 2015-11-29 16:48:57 -05:00
parent 9b0f2a3a9d
commit fcdf80c6a7
23 changed files with 476 additions and 20 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ nohup.out
*.orig
tmp.txt
*.hprof
tmp.txt
# Vagrant stuff.
.vagrant

View File

@ -78,9 +78,9 @@ public class ExampleDataUploader extends BaseCommand {
opt.setRequired(false);
options.addOption(opt);
opt = new Option("c", "cache", true, "Store a copy of the downloaded example pack on the local disk using a file of the given name. Use this file instead of fetching it from the internet if the file already exists.");
opt.setRequired(false);
options.addOption(opt);
// opt = new Option("c", "cache", true, "Store a copy of the downloaded example pack on the local disk using a file of the given name. Use this file instead of fetching it from the internet if the file already exists.");
// opt.setRequired(false);
// options.addOption(opt);
return options;
}

Binary file not shown.

View File

@ -1242,7 +1242,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
* This should be the very first thing..
*/
if (theResource != null) {
if (thePerformIndexing) {
validateResourceForStorage((T) theResource, theEntity);
}
String resourceType = myContext.getResourceDefinition(theResource).getName();
if (isNotBlank(theEntity.getResourceType()) && !theEntity.getResourceType().equals(resourceType)) {
throw new UnprocessableEntityException("Existing resource ID[" + theEntity.getIdDt().toUnqualifiedVersionless() + "] is of type[" + theEntity.getResourceType() + "] - Cannot update with [" + resourceType + "]");

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
@ -27,6 +27,14 @@ import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestDstu2Config;
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.jpa.entity.ForcedId;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
@ -14,6 +14,8 @@ import javax.servlet.http.HttpServletRequest;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.Media;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
@ -30,6 +30,8 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
@ -25,6 +25,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionFlaggedResourceDataDao;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.hamcrest.Matchers.contains;
@ -39,6 +39,10 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoDstu2;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.model.api.IQueryParameterType;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
@ -15,6 +15,7 @@ import org.junit.Before;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
@ -9,6 +9,8 @@ import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.rest.param.StringAndListParam;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.dao;
package ca.uhn.fhir.jpa.dao.dstu2;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyString;
@ -30,6 +30,7 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
@ -450,6 +451,7 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
}
}
@Test
public void testTransactionCreateWithDuplicateMatchUrl02() {
String methodName = "testTransactionCreateWithDuplicateMatchUrl02";
Bundle request = new Bundle();

View File

@ -29,13 +29,13 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestDstu21Config;
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoDstu2SearchNoFtTest;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
import ca.uhn.fhir.jpa.entity.ForcedId;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;

View File

@ -17,6 +17,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
@ -451,6 +452,7 @@ public class FhirSystemDaoDstu21Test extends BaseJpaDstu21SystemTest {
}
}
@Test
public void testTransactionCreateWithDuplicateMatchUrl02() {
String methodName = "testTransactionCreateWithDuplicateMatchUrl02";
Bundle request = new Bundle();
@ -472,6 +474,34 @@ public class FhirSystemDaoDstu21Test extends BaseJpaDstu21SystemTest {
}
}
@Test
public void testTransactionCreateWithPutUsingUrl() {
String methodName = "testTransactionCreateWithPutUsingUrl";
Bundle request = new Bundle();
request.setType(BundleTypeEnum.TRANSACTION);
Observation o = new Observation();
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl("Observation/a" + methodName);
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl("Patient/" + methodName);
mySystemDao.transaction(myRequestDetails, request);
myObservationDao.read(new IdDt("Observation/a" + methodName));
myPatientDao.read(new IdDt("Patient/" + methodName));
}
@Test
public void testTransactionCreateWithPutUsingUrl2() throws Exception {
String req = IOUtils.toString(FhirSystemDaoDstu21Test.class.getResourceAsStream("/bundle-dstu21.xml"));
Bundle request = myFhirCtx.newXmlParser().parseResource(Bundle.class, req);
mySystemDao.transaction(myRequestDetails, request);
}
@Test
public void testTransactionCreateWithInvalidMatchUrl() {
String methodName = "testTransactionCreateWithInvalidMatchUrl";

View File

@ -20,7 +20,7 @@ import org.springframework.web.context.support.AnnotationConfigWebApplicationCon
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import ca.uhn.fhir.jpa.dao.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.dao.dstu2.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;

View File

@ -29,7 +29,7 @@ import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.dao.dstu2.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.rp.dstu2.ObservationResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu2.OrganizationResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider;

View File

@ -0,0 +1,394 @@
<Bundle xmlns="http://hl7.org/fhir">
<entry>
<resource>
<QuestionnaireResponse xmlns="http://hl7.org/fhir">
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>
<b>Generated Narrative with Details</b>
</p>
<p>
<b>id</b>: gcs
</p>
<p>
<b>questionnaire</b>:
<a>Questionnaire/gcs</a>
</p>
<p>
<b>status</b>: completed
</p>
<p>
<b>subject</b>:
<a>Peter James Chalmers</a>
</p>
<p>
<b>authored</b>: Dec 11, 2014 4:44:16 AM
</p>
<p>
<b>source</b>:
<a>Practitioner/f007</a>
</p>
<blockquote>
<p>
<b>item</b>
</p>
<p>
<b>linkId</b>: 1.1
</p>
<h3>Answers</h3>
<table>
<tr>
<td>-</td>
<td>
<b>Value[x]</b>
</td>
</tr>
<tr>
<td>*</td>
<td>Confused (Details: LOINC code LA6560-2 = 'Confused', stated as 'Confused')</td>
</tr>
</table>
</blockquote>
<blockquote>
<p>
<b>item</b>
</p>
<p>
<b>linkId</b>: 1.2
</p>
<h3>Answers</h3>
<table>
<tr>
<td>-</td>
<td>
<b>Value[x]</b>
</td>
</tr>
<tr>
<td>*</td>
<td>Localizing pain (Details: LOINC code LA6566-9 = 'Localizing pain', stated as 'Localizing pain')</td>
</tr>
</table>
</blockquote>
<blockquote>
<p>
<b>item</b>
</p>
<p>
<b>linkId</b>: 1.3
</p>
<h3>Answers</h3>
<table>
<tr>
<td>-</td>
<td>
<b>Value[x]</b>
</td>
</tr>
<tr>
<td>*</td>
<td>Eyes open spontaneously (Details: LOINC code LA6556-0 = 'Eyes open spontaneously', stated as 'Eyes open spontaneously')</td>
</tr>
</table>
</blockquote>
</div>
</text>
<questionnaire>
<reference value="Questionnaire/Questionnairegcs"/>
</questionnaire>
<status value="completed"/>
<authored value="2014-12-11T04:44:16Z"/>
<item>
<linkId value="1.1"/>
<answer>
<valueCoding>
<extension url="http://hl7.org/fhir/StructureDefinition/iso21090-CO-value">
<valueDecimal value="4"/>
</extension>
<system value="http://loinc.org"/>
<code value="LA6560-2"/>
<display value="Confused"/>
</valueCoding>
</answer>
</item>
<item>
<linkId value="1.2"/>
<answer>
<valueCoding>
<extension url="http://hl7.org/fhir/StructureDefinition/iso21090-CO-value">
<valueDecimal value="5"/>
</extension>
<system value="http://loinc.org"/>
<code value="LA6566-9"/>
<display value="Localizing pain"/>
</valueCoding>
</answer>
</item>
<item>
<linkId value="1.3"/>
<answer>
<valueCoding>
<extension url="http://hl7.org/fhir/StructureDefinition/iso21090-CO-value">
<valueDecimal value="4"/>
</extension>
<system value="http://loinc.org"/>
<code value="LA6556-0"/>
<display value="Eyes open spontaneously"/>
</valueCoding>
</answer>
</item>
</QuestionnaireResponse>
</resource>
<request>
<method value="PUT"/>
<url value="QuestionnaireResponse/QuestionnaireResponsegcs"/>
</request>
</entry>
<entry>
<resource>
<Questionnaire xmlns="http://hl7.org/fhir">
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>
<b>Generated Narrative with Details</b>
</p>
<p>
<b>id</b>: gcs
</p>
<p>
<b>contained</b>: , ,
</p>
<p>
<b>status</b>: draft
</p>
<p>
<b>date</b>: Aug 3, 2015
</p>
<p>
<b>publisher</b>: FHIR Project team
</p>
<p>
<b>title</b>: Glasgow Coma Score
</p>
<p>
<b>concept</b>: Glasgow coma score total (Details: LOINC code 9269-2 = 'Glasgow coma score total', stated as 'null')
</p>
<p>
<b>subjectType</b>: Patient
</p>
<blockquote>
<p>
<b>item</b>
</p>
<p>
<b>linkId</b>: 1.1
</p>
<p>
<b>concept</b>: Glasgow coma score verbal (Details: LOINC code 9270-0 = 'Glasgow coma score verbal', stated as 'null')
</p>
<p>
<b>type</b>: choice
</p>
<p>
<b>options</b>: id: verbal; http://loinc.org/ValueSet/LL356-7; name: GCS Verbal Value Set; status: active; description: LOINC ANSWER LIST (LL356-7)
</p>
</blockquote>
<blockquote>
<p>
<b>item</b>
</p>
<p>
<b>linkId</b>: 1.2
</p>
<p>
<b>concept</b>: Glasgow coma score motor (Details: LOINC code 9268-4 = 'Glasgow coma score motor', stated as 'null')
</p>
<p>
<b>type</b>: choice
</p>
<p>
<b>options</b>: id: motor; http://loinc.org/ValueSet/LL357-5; name: GCS Motor Value Set; status: active; description: LOINC ANSWER LIST (LL357-5)
</p>
</blockquote>
<blockquote>
<p>
<b>item</b>
</p>
<p>
<b>linkId</b>: 1.3
</p>
<p>
<b>concept</b>: Glasgow coma score eye opening (Details: LOINC code 9267-6 = 'Glasgow coma score eye opening', stated as 'null')
</p>
<p>
<b>type</b>: choice
</p>
<p>
<b>options</b>: id: eye; http://loinc.org/ValueSet/LL355-9; name: GCS Eye Value Set; status: active; description: LOINC ANSWER LIST (LL355-9)
</p>
</blockquote>
</div>
</text>
<contained>
<ValueSet xmlns="http://hl7.org/fhir">
<id value="verbal"/>
<identifier>
<system value="http://loinc.org"/>
<value value="http://loinc.org/ValueSet/LL356-7"/>
</identifier>
<name value="GCS Verbal Value Set"/>
<status value="active"/>
<description value="LOINC ANSWER LIST (LL356-7)"/>
<compose>
<include>
<system value="http://loinc.org"/>
<concept>
<code value="LA6557-8"/>
<display value="No verbal response (>2yrs); no vocal response (&lt;=2yrs)"/>
</concept>
<concept>
<code value="LA6558-6"/>
<display value="Incomprehensible sounds"/>
</concept>
<concept>
<code value="LA6559-4"/>
<display value="Inappropriate words"/>
</concept>
<concept>
<code value="LA6560-2"/>
<display value="Confused"/>
</concept>
<concept>
<code value="LA6561-0"/>
<display value="Oriented"/>
</concept>
</include>
</compose>
</ValueSet>
</contained>
<contained>
<ValueSet xmlns="http://hl7.org/fhir">
<id value="motor"/>
<identifier>
<system value="http://loinc.org"/>
<value value="http://loinc.org/ValueSet/LL357-5"/>
</identifier>
<name value="GCS Motor Value Set"/>
<status value="active"/>
<description value="LOINC ANSWER LIST (LL357-5)"/>
<compose>
<include>
<system value="http://loinc.org"/>
<concept>
<code value="LA6562-8"/>
<display value="No motor response"/>
</concept>
<concept>
<code value="LA6563-6"/>
<display value="Extension to pain"/>
</concept>
<concept>
<code value="LA6564-4"/>
<display value="Flexion to pain"/>
</concept>
<concept>
<code value="LA6565-1"/>
<display value="Withdrawl from pain"/>
</concept>
<concept>
<code value="LA6566-9"/>
<display value="Localizing pain"/>
</concept>
<concept>
<code value="LA6567-7"/>
<display value="Obeys commands"/>
</concept>
</include>
</compose>
</ValueSet>
</contained>
<contained>
<ValueSet xmlns="http://hl7.org/fhir">
<id value="eye"/>
<identifier>
<system value="http://loinc.org"/>
<value value="http://loinc.org/ValueSet/LL355-9"/>
</identifier>
<name value="GCS Eye Value Set"/>
<status value="active"/>
<description value="LOINC ANSWER LIST (LL355-9)"/>
<compose>
<include>
<system value="http://loinc.org"/>
<concept>
<code value="LA6553-7"/>
<display value="No eye opening"/>
</concept>
<concept>
<code value="LA6554-5"/>
<display value="Eye opening to pain"/>
</concept>
<concept>
<code value="LA6555-2"/>
<display value="Eye opening to verbal command"/>
</concept>
<concept>
<code value="LA6556-0"/>
<display value="Eyes open spontaneously"/>
</concept>
</include>
</compose>
</ValueSet>
</contained>
<status value="draft"/>
<date value="2015-08-03"/>
<publisher value="FHIR Project team"/>
<title value="Glasgow Coma Score"/>
<concept>
<system value="http://loinc.org"/>
<code value="9269-2"/>
</concept>
<subjectType value="Patient"/>
<item>
<linkId value="1.1"/>
<concept>
<system value="http://loinc.org"/>
<code value="9270-0"/>
</concept>
<type value="choice"/>
<options>
<reference value="#verbal"/>
</options>
</item>
<item>
<linkId value="1.2"/>
<concept>
<system value="http://loinc.org"/>
<code value="9268-4"/>
</concept>
<type value="choice"/>
<options>
<reference value="#motor"/>
</options>
</item>
<item>
<linkId value="1.3"/>
<concept>
<system value="http://loinc.org"/>
<code value="9267-6"/>
</concept>
<type value="choice"/>
<options>
<reference value="#eye"/>
</options>
</item>
</Questionnaire>
</resource>
<request>
<method value="PUT"/>
<url value="Questionnaire/Questionnairegcs"/>
</request>
</entry>
</Bundle>

View File

@ -33,6 +33,13 @@
disabled using a RestfulServer configuration setting). A new client interceptor has been added
which compresses outgoing content from the client.
</action>
<action type="fix">
JPA server transaction attempted to validate resources twice each,
with one of these times being before anything had been committed to the
database. This meant that if a transaction contained both a Questionnaire
and a QuestionnaireResponse, it would fail because the QuestionnaireResponse
validator wouldn't be able to find the questionnaire. This is now corrected.
</action>
</release>
<release version="1.3" date="2015-11-14">
<action type="add">