Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2015-09-24 10:01:03 -04:00
commit 3c6299a157
93 changed files with 2992 additions and 928 deletions

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -18,22 +18,22 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -18,7 +18,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<!--
<exclusion>
@ -39,13 +39,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<optional>true</optional>
</dependency>
<dependency>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -34,7 +34,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>woodstox-core-asl</artifactId>
@ -49,7 +49,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>woodstox-core-asl</artifactId>
@ -60,7 +60,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>woodstox-core-asl</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -40,7 +40,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>woodstox-core-asl</artifactId>
@ -55,7 +55,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>woodstox-core-asl</artifactId>
@ -66,7 +66,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>woodstox-core-asl</artifactId>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.model.api;
import net.sourceforge.cobertura.CoverageIgnore;
/*
* #%L
* HAPI FHIR - Core Library
@ -31,6 +33,7 @@ package ca.uhn.fhir.model.api;
*
* @deprecated {@link Include} should be used instead
*/
@CoverageIgnore
@Deprecated
public class PathSpecification extends Include {

View File

@ -1014,7 +1014,7 @@ public class JsonParser extends BaseParser implements IParser {
if ("resourceType".equals(nextName)) {
continue;
} else if ("entry".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
JsonArray entries = grabJsonArray(theObject, nextName, "entry");
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "entry");
parseBundleChildren((JsonObject) jsonValue, theState);
@ -1023,7 +1023,7 @@ public class JsonParser extends BaseParser implements IParser {
continue;
} else if (myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
if ("link".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
JsonArray entries = grabJsonArray(theObject, nextName, "link");
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "link");
JsonObject linkObj = (JsonObject) jsonValue;
@ -1042,7 +1042,7 @@ public class JsonParser extends BaseParser implements IParser {
}
} else {
if ("link".equals(nextName)) {
JsonArray entries = theObject.getJsonArray(nextName);
JsonArray entries = grabJsonArray(theObject, nextName, "link");
for (JsonValue jsonValue : entries) {
theState.enteringNewElement(null, "link");
JsonObject linkObj = (JsonObject) jsonValue;
@ -1106,11 +1106,11 @@ public class JsonParser extends BaseParser implements IParser {
}
continue;
} else if ("extension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
JsonArray array = grabJsonArray(theObject, nextName, "extension");
parseExtension(theState, array, false);
continue;
} else if ("modifierExtension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
JsonArray array = grabJsonArray(theObject, nextName, "modifierExtension");
parseExtension(theState, array, true);
continue;
} else if (nextName.charAt(0) == '_') {
@ -1135,6 +1135,17 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private JsonArray grabJsonArray(JsonObject theObject, String nextName, String thePosition) {
JsonValue object = theObject.get(nextName);
if (object == null) {
return null;
}
if (object.getValueType() != ValueType.ARRAY) {
throw new DataFormatException("Syntax error parsing JSON FHIR structure: Expected ARRAY at element '" + thePosition + "', found '" + object.getValueType().name() + "'");
}
return (JsonArray) object;
}
private void parseChildren(ParserState<?> theState, String theName, JsonValue theJsonVal, JsonValue theAlternateVal, String theAlternateName) {
switch (theJsonVal.getValueType()) {
case ARRAY: {

View File

@ -24,8 +24,11 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.InstantDt;
@ -35,8 +38,8 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DateParam extends DateTimeDt implements IQueryParameterType, IQueryParameterOr<DateParam> {
private QuantityCompararatorEnum myComparator;
private BaseParam myBase=new BaseParam.ComposableBaseParam();
private QuantityCompararatorEnum myComparator;
/**
* Constructor
@ -55,17 +58,26 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, String theDate) {
public DateParam(QuantityCompararatorEnum theComparator, DateTimeDt theDate) {
myComparator = theComparator;
setValueAsString(theDate);
setValueAsString(theDate != null ? theDate.getValueAsString() : null);
}
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, DateTimeDt theDate) {
public DateParam(QuantityCompararatorEnum theComparator, long theDate) {
Validate.inclusiveBetween(1, Long.MAX_VALUE, theDate, "theDate must not be 0 or negative");
myComparator = theComparator;
setValueAsString(theDate != null ? theDate.getValueAsString() : null);
setValue(new Date(theDate));
}
/**
* Constructor
*/
public DateParam(QuantityCompararatorEnum theComparator, String theDate) {
myComparator = theComparator;
setValueAsString(theDate);
}
/**
@ -85,6 +97,11 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
return myComparator;
}
@Override
public Boolean getMissing() {
return myBase.getMissing();
}
@Override
public String getQueryParameterQualifier() {
if (myBase.getMissing()!=null) {
@ -93,6 +110,14 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
return null;
}
public DateTimeDt getValueAsDateTimeDt() {
return new DateTimeDt(getValueAsString());
}
public InstantDt getValueAsInstantDt() {
return new InstantDt(getValue());
}
@Override
public String getValueAsQueryToken() {
if (myBase.getMissing()!=null) {
@ -125,6 +150,17 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
myComparator = theComparator;
}
@Override
public void setMissing(Boolean theMissing) {
myBase.setMissing(theMissing);
}
@Override
public DateParam setValue(Date theValue) {
super.setValue(theValue, TemporalPrecisionEnum.MILLI);
return this;
}
@Override
public void setValueAsQueryToken(String theQualifier, String theValue) {
myBase.setValueAsQueryToken(theQualifier, theValue);
@ -191,22 +227,4 @@ public class DateParam extends DateTimeDt implements IQueryParameterType, IQuery
return b.toString();
}
public InstantDt getValueAsInstantDt() {
return new InstantDt(getValue());
}
public DateTimeDt getValueAsDateTimeDt() {
return new DateTimeDt(getValueAsString());
}
@Override
public Boolean getMissing() {
return myBase.getMissing();
}
@Override
public void setMissing(Boolean theMissing) {
myBase.setMissing(theMissing);
}
}

View File

@ -214,8 +214,16 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
* "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
*/
public void setRangeFromDatesInclusive(DateTimeDt theLowerBound, DateTimeDt theUpperBound) {
myLowerBound = theLowerBound != null ? new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
myUpperBound = theUpperBound != null ? new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
if (theLowerBound instanceof DateParam) {
myLowerBound = (DateParam) theLowerBound;
} else {
myLowerBound = theLowerBound != null ? new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, theLowerBound) : null;
}
if (theUpperBound instanceof DateParam) {
myUpperBound = (DateParam) theUpperBound;
} else {
myUpperBound = theUpperBound != null ? new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, theUpperBound) : null;
}
validateAndThrowDataFormatExceptionIfInvalid();
}
@ -304,8 +312,13 @@ public class DateRangeParam implements IQueryParameterAnd<DateParam> {
boolean haveLowerBound = haveLowerBound();
boolean haveUpperBound = haveUpperBound();
if (haveLowerBound && haveUpperBound) {
if (myLowerBound.getValue().after(myUpperBound.getValue())) {
throw new DataFormatException("Lower bound of " + myLowerBound.getValueAsString() + " is after upper bound of " + myUpperBound.getValueAsString());
if (myLowerBound.getValue().getTime() > myUpperBound.getValue().getTime()) {
StringBuilder b = new StringBuilder();
b.append("Lower bound of ");
b.append(myLowerBound.getValueAsString());
b.append(" is after upper bound of ");
b.append(myUpperBound.getValueAsString());
throw new DataFormatException(b.toString());
}
}

View File

@ -23,11 +23,13 @@ package ca.uhn.fhir.rest.param;
import java.util.Date;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/**
* @deprecated Use {@link DateParam} instead (this class is identical, but was renamed to be less confusing)
*/
@Deprecated
@CoverageIgnore
public class QualifiedDateParam extends DateParam {
/**
* Constructor

View File

@ -46,6 +46,7 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.IParameter;
import ca.uhn.fhir.rest.method.MethodUtil;
@ -145,12 +146,15 @@ public class ResourceParameter implements IParameter {
return charset;
}
public static IBaseResource loadResourceFromRequest(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding, Class<? extends IBaseResource> theResourceType) {
@SuppressWarnings("unchecked")
public static <T extends IBaseResource> T loadResourceFromRequest(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding, Class<T> theResourceType) {
FhirContext ctx = theRequest.getServer().getFhirContext();
final Charset charset = determineRequestCharset(theRequest);
Reader requestReader = createRequestReader(theRequest.getRawRequest(), charset);
RestOperationTypeEnum restOperationType = theMethodBinding != null ? theMethodBinding.getRestOperationType() : null;
EncodingEnum encoding = RestfulServerUtils.determineRequestEncodingNoDefault(theRequest);
if (encoding == null) {
String ctValue = theRequest.getServletRequest().getHeader(Constants.HEADER_CONTENT_TYPE);
@ -173,24 +177,24 @@ public class ResourceParameter implements IParameter {
}
encoding = MethodUtil.detectEncodingNoDefault(body);
if (encoding == null) {
String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "noContentTypeInRequest", theMethodBinding.getRestOperationType());
String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "noContentTypeInRequest", restOperationType);
throw new InvalidRequestException(msg);
} else {
requestReader = new InputStreamReader(new ByteArrayInputStream(theRequest.getRawRequest()), charset);
}
} else {
String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "invalidContentTypeInRequest", ctValue, theMethodBinding.getRestOperationType());
String msg = ctx.getLocalizer().getMessage(ResourceParameter.class, "invalidContentTypeInRequest", ctValue, restOperationType);
throw new InvalidRequestException(msg);
}
}
IParser parser = encoding.newParser(ctx);
IBaseResource retVal;
T retVal;
if (theResourceType != null) {
retVal = parser.parseResource(theResourceType, requestReader);
} else {
retVal = parser.parseResource(requestReader);
retVal = (T) parser.parseResource(requestReader);
}
if (theRequest.getId() != null && theRequest.getId().hasIdPart()) {

View File

@ -106,10 +106,11 @@ public interface IServerInterceptor {
* The incoming servlet request as provided by the servlet container
* @param theOperation
* The type of operation that the FHIR server has determined that the client is trying to invoke
* @param theRequestDetails
* An object which will be populated with any relevant details about the incoming request (this includes the HttpServletRequest)
* @param theProcessedRequest
* An object which will be populated with the details which were extracted from the raw request by the server,
* e.g. the FHIR operation type and the parsed resource body (if any).
*/
void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theRequestDetails);
void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest);
/**
* This method is called before any other processing takes place for each incoming request. It may be used to provide alternate handling for some requests, or to screen requests before they are

View File

@ -42,7 +42,8 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public class InterceptorAdapter implements IServerInterceptor {
@Override
public boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse) {
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
IOException {
return true;
}
@ -52,7 +53,12 @@ public class InterceptorAdapter implements IServerInterceptor {
}
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest) {
// nothing
}
@Override
public boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse) {
return true;
}
@ -62,12 +68,17 @@ public class InterceptorAdapter implements IServerInterceptor {
}
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
public boolean outgoingResponse(RequestDetails theRequestDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
return true;
}
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
public boolean outgoingResponse(RequestDetails theRequestDetails, IBaseResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
return true;
}
@Override
public boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException {
return true;
}
@ -75,16 +86,5 @@ public class InterceptorAdapter implements IServerInterceptor {
public BaseServerResponseException preProcessOutgoingException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest) throws ServletException {
return null;
}
@Override
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
IOException {
return true;
}
@Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theRequestDetails) {
// nothing
}
}

View File

@ -6,6 +6,9 @@ import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
/*
* #%L
* HAPI FHIR - Core Library
@ -158,5 +161,92 @@ public class UrlUtil {
throw new Error("UTF-8 not supported on this platform");
}
}
//@formatter:off
/**
* Parse a URL in one of the following forms:
* <ul>
* <li>[Resource Type]?[Search Params]
* <li>[Resource Type]/[Resource ID]
* <li>[Resource Type]/[Resource ID]/_history/[Version ID]
* </ul>
*/
//@formatter:on
public static UrlParts parseUrl(String theUrl) {
UrlParts retVal = new UrlParts();
int nextStart = 0;
boolean nextIsHistory = false;
for (int idx = 0; idx < theUrl.length(); idx++) {
char nextChar = theUrl.charAt(idx);
boolean atEnd = (idx + 1) == theUrl.length();
if (nextChar == '?' || nextChar == '/' || atEnd) {
int endIdx = atEnd ? idx + 1 : idx;
String nextSubstring = theUrl.substring(nextStart, endIdx);
if (retVal.getResourceType() == null) {
retVal.setResourceType(nextSubstring);
} else if (retVal.getResourceId() == null) {
retVal.setResourceId(nextSubstring);
} else if (nextIsHistory) {
retVal.setVersionId(nextSubstring);
} else {
if (nextSubstring.equals(Constants.URL_TOKEN_HISTORY)) {
nextIsHistory = true;
} else {
throw new InvalidRequestException("Invalid FHIR resource URL: " + theUrl);
}
}
if (nextChar == '?') {
if (theUrl.length() > idx + 1) {
retVal.setParams(theUrl.substring(idx + 1, theUrl.length()));
}
break;
}
nextStart = idx + 1;
}
}
return retVal;
}
public static class UrlParts {
private String myParams;
private String myResourceId;
private String myResourceType;
private String myVersionId;
public String getParams() {
return myParams;
}
public String getResourceId() {
return myResourceId;
}
public String getResourceType() {
return myResourceType;
}
public String getVersionId() {
return myVersionId;
}
public void setParams(String theParams) {
myParams = theParams;
}
public void setResourceId(String theResourceId) {
myResourceId = theResourceId;
}
public void setResourceType(String theResourceType) {
myResourceType = theResourceType;
}
public void setVersionId(String theVersionId) {
myVersionId = theVersionId;
}
}
}

View File

@ -11,7 +11,7 @@
<tr th:each="issue : ${resource.issue}">
<td th:text="${issue.severityElement.value}" style="font-weight: bold;"></td>
<td th:text="${issue.location}"></td>
<td><pre th:text="${issue.details}"/></td>
<td><pre th:text="${issue.diagnostics}"/></td>
</tr>
</table>
</div>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -22,33 +22,33 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-example</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<type>war</type>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
@ -143,7 +143,7 @@
<artifactItem>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-example</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<type>war</type>
<overWrite>true</overWrite>
<outputDirectory>target/classes</outputDirectory>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -19,32 +19,32 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -18,17 +18,17 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>

View File

@ -1,11 +1,10 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -31,7 +30,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
@ -42,22 +41,22 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
@ -93,18 +92,13 @@
<artifactId>jscience</artifactId>
</dependency>
<!-- FHIR RI is pulled in for UCUM support, but we don't want any of its
dependencies. -->
<!-- <dependency> <groupId>me.fhir</groupId> <artifactId>fhir-dstu1</artifactId>
<version>0.0.81.2489</version> <exclusions> <exclusion> <artifactId>Saxon-HE</artifactId>
<groupId>net.sf.saxon</groupId> </exclusion> <exclusion> <artifactId>commons-discovery</artifactId>
<groupId>commons-discovery</groupId> </exclusion> <exclusion> <artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId> </exclusion> <exclusion> <artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId> </exclusion> <exclusion> <artifactId>xpp3</artifactId>
<groupId>xpp3</groupId> </exclusion> <exclusion> <artifactId>junit</artifactId>
<groupId>junit</groupId> </exclusion> <exclusion> <artifactId>jdom</artifactId>
<groupId>org.jdom</groupId> </exclusion> <exclusion> <artifactId>gson</artifactId>
<groupId>com.google.code.gson</groupId> </exclusion> </exclusions> </dependency> -->
<!-- FHIR RI is pulled in for UCUM support, but we don't want any of its dependencies. -->
<!-- <dependency> <groupId>me.fhir</groupId> <artifactId>fhir-dstu1</artifactId> <version>0.0.81.2489</version> <exclusions> <exclusion> <artifactId>Saxon-HE</artifactId>
<groupId>net.sf.saxon</groupId> </exclusion> <exclusion> <artifactId>commons-discovery</artifactId> <groupId>commons-discovery</groupId> </exclusion> <exclusion>
<artifactId>commons-codec</artifactId> <groupId>commons-codec</groupId> </exclusion> <exclusion> <artifactId>commons-logging</artifactId> <groupId>commons-logging</groupId>
</exclusion> <exclusion> <artifactId>xpp3</artifactId> <groupId>xpp3</groupId> </exclusion> <exclusion> <artifactId>junit</artifactId> <groupId>junit</groupId> </exclusion>
<exclusion> <artifactId>jdom</artifactId> <groupId>org.jdom</groupId> </exclusion> <exclusion> <artifactId>gson</artifactId> <groupId>com.google.code.gson</groupId>
</exclusion> </exclusions> </dependency> -->
<!-- Test Database -->
@ -126,8 +120,7 @@
</dependency>
<!-- <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId>
<version>2.3.2</version> </dependency> -->
<!-- <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.3.2</version> </dependency> -->
<!-- Spring -->
<dependency>
@ -162,6 +155,10 @@
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
@ -226,7 +223,7 @@
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
@ -252,7 +249,7 @@
<artifactId>spring-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
@ -277,84 +274,14 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--
These tests all use a shared database, so it's easier if
they run in a predictable order
-->
<!-- These tests all use a shared database, so it's easier if they run in a predictable order -->
<runOrder>alphabetical</runOrder>
</configuration>
</plugin>
<plugin>
<groupId>de.juplo</groupId>
<artifactId>hibernate4-maven-plugin</artifactId>
<version>1.0.5</version>
<configuration>
<force>true</force>
<target>SCRIPT</target>
<skip>${skip-hib4}</skip>
</configuration>
<!--
This needs to be uncommented in order for this plugin to work with
Hibernate 4.3+ (as of hibernate4-maven-plugin version 1.0.5)
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate_version}</version>
</dependency>
</dependencies>
-->
<executions>
<execution>
<id>o10g</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.Oracle10gDialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_oracle_10g.sql</outputFile>
</configuration>
</execution>
<execution>
<id>derby</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.DerbyTenSevenDialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_derby.sql</outputFile>
</configuration>
</execution>
<execution>
<id>hsql</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.HSQLDialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_hsql.sql</outputFile>
</configuration>
</execution>
<execution>
<id>mysql5</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.MySQL5Dialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_mysql_5.sql</outputFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<executions>
<execution>
<id>build_dstu1</id>
@ -389,12 +316,12 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
@ -413,11 +340,10 @@
</build>
<reporting>
<plugins>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>${maven_jxr_plugin_version}</version>
</plugin>
</plugins>
</reporting>
@ -429,6 +355,70 @@
<skip-hib4>true</skip-hib4>
</properties>
</profile>
<profile>
<id>DIST</id>
<build>
<plugins>
<plugin>
<groupId>de.juplo</groupId>
<artifactId>hibernate4-maven-plugin</artifactId>
<configuration>
<force>true</force>
<target>SCRIPT</target>
<skip>${skip-hib4}</skip>
</configuration>
<!-- This needs to be uncommented in order for this plugin to work with Hibernate 4.3+ (as of hibernate4-maven-plugin version 1.0.5) <dependencies> <dependency>
<groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate_version}</version> </dependency> </dependencies> -->
<executions>
<execution>
<id>o10g</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.Oracle10gDialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_oracle_10g.sql</outputFile>
</configuration>
</execution>
<execution>
<id>derby</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.DerbyTenSevenDialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_derby.sql</outputFile>
</configuration>
</execution>
<execution>
<id>hsql</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.HSQLDialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_hsql.sql</outputFile>
</configuration>
</execution>
<execution>
<id>mysql5</id>
<goals>
<goal>export</goal>
</goals>
<phase>test</phase>
<configuration>
<hibernateDialect>org.hibernate.dialect.MySQL5Dialect</hibernateDialect>
<outputFile>${project.build.directory}/schema_mysql_5.sql</outputFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -166,8 +166,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return InstantDt.withCurrentTime();
}
protected List<ResourceLink> extractResourceLinks(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceLink> retVal = new ArrayList<ResourceLink>();
protected Set<ResourceLink> extractResourceLinks(ResourceTable theEntity, IResource theResource) {
Set<ResourceLink> retVal = new HashSet<ResourceLink>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -185,73 +185,76 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
multiType = true;
}
for (Object nextObject : extractValues(nextPathsUnsplit, theResource)) {
if (nextObject == null) {
continue;
}
ResourceLink nextEntity;
if (nextObject instanceof BaseResourceReferenceDt) {
BaseResourceReferenceDt nextValue = (BaseResourceReferenceDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if (nextValue.getReference().isEmpty() || nextValue.getReference().getValue().startsWith("#")) {
// This is a blank or contained resource reference
String[] nextPathsSplit = nextPathsUnsplit.split("\\|");
for (String nextPath : nextPathsSplit) {
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null) {
continue;
}
String typeString = nextValue.getReference().getResourceType();
if (isBlank(typeString)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReference().getValue());
}
RuntimeResourceDefinition resourceDefinition;
try {
resourceDefinition = getContext().getResourceDefinition(typeString);
} catch (DataFormatException e) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Resource type is unknown or not supported on this server - " + nextValue.getReference().getValue());
}
ResourceLink nextEntity;
if (nextObject instanceof BaseResourceReferenceDt) {
BaseResourceReferenceDt nextValue = (BaseResourceReferenceDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if (nextValue.getReference().isEmpty() || nextValue.getReference().getValue().startsWith("#")) {
// This is a blank or contained resource reference
continue;
}
Class<? extends IBaseResource> type = resourceDefinition.getImplementingClass();
String id = nextValue.getReference().getIdPart();
if (StringUtils.isBlank(id)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource ID - " + nextValue.getReference().getValue());
}
String typeString = nextValue.getReference().getResourceType();
if (isBlank(typeString)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource type - " + nextValue.getReference().getValue());
}
RuntimeResourceDefinition resourceDefinition;
try {
resourceDefinition = getContext().getResourceDefinition(typeString);
} catch (DataFormatException e) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Resource type is unknown or not supported on this server - " + nextValue.getReference().getValue());
}
IFhirResourceDao<?> dao = getDao(type);
if (dao == null) {
StringBuilder b = new StringBuilder();
b.append("This server (version ");
b.append(myContext.getVersion().getVersion());
b.append(") is not able to handle resources of type[");
b.append(nextValue.getReference().getResourceType());
b.append("] - Valid resource types for this server: ");
b.append(myResourceTypeToDao.keySet().toString());
Class<? extends IBaseResource> type = resourceDefinition.getImplementingClass();
String id = nextValue.getReference().getIdPart();
if (StringUtils.isBlank(id)) {
throw new InvalidRequestException("Invalid resource reference found at path[" + nextPathsUnsplit + "] - Does not contain resource ID - " + nextValue.getReference().getValue());
}
throw new InvalidRequestException(b.toString());
}
Long valueOf;
try {
valueOf = translateForcedIdToPid(nextValue.getReference());
} catch (ResourceNotFoundException e) {
String resName = getContext().getResourceDefinition(type).getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf);
if (target == null) {
String resName = getContext().getResourceDefinition(type).getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
nextEntity = new ResourceLink(nextPathsUnsplit, theEntity, target);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
IFhirResourceDao<?> dao = getDao(type);
if (dao == null) {
StringBuilder b = new StringBuilder();
b.append("This server (version ");
b.append(myContext.getVersion().getVersion());
b.append(") is not able to handle resources of type[");
b.append(nextValue.getReference().getResourceType());
b.append("] - Valid resource types for this server: ");
b.append(myResourceTypeToDao.keySet().toString());
throw new InvalidRequestException(b.toString());
}
Long valueOf;
try {
valueOf = translateForcedIdToPid(nextValue.getReference());
} catch (ResourceNotFoundException e) {
String resName = getContext().getResourceDefinition(type).getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf);
if (target == null) {
String resName = getContext().getResourceDefinition(type).getName();
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
}
nextEntity = new ResourceLink(nextPath, theEntity, target);
} else {
continue;
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
if (nextEntity != null) {
retVal.add(nextEntity);
}
}
if (nextEntity != null) {
retVal.add(nextEntity);
}
}
}
@ -261,46 +264,43 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return retVal;
}
protected List<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
protected Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamDates(theEntity, theResource);
}
protected List<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
protected Set<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamNumber(theEntity, theResource);
}
protected List<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
protected Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamUri(theEntity, theResource);
}
protected List<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
protected Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamCoords(theEntity, theResource);
}
protected List<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
protected Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamQuantity(theEntity, theResource);
}
protected List<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
protected Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamStrings(theEntity, theResource);
}
protected List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
protected Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamTokens(theEntity, theResource);
}
private List<Object> extractValues(String thePaths, IResource theResource) {
private List<Object> extractValues(String thePath, IResource theResource) {
List<Object> values = new ArrayList<Object>();
String[] nextPathsSplit = thePaths.split("\\|");
FhirTerser t = getContext().newTerser();
for (String nextPath : nextPathsSplit) {
String nextPathTrimmed = nextPath.trim();
try {
values.addAll(t.getValues(theResource, nextPathTrimmed));
} catch (Exception e) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
ourLog.warn("Failed to index values from path[{}] in resource type[{}]: ", new Object[] { nextPathTrimmed, def.getName(), e.toString() });
}
String nextPathTrimmed = thePath.trim();
try {
values.addAll(t.getValues(theResource, nextPathTrimmed));
} catch (Exception e) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
ourLog.warn("Failed to index values from path[{}] in resource type[{}]: ", new Object[] { nextPathTrimmed, def.getName(), e.toString() });
}
return values;
}
@ -520,7 +520,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
throw e;
}
IResource resource = (IResource) toResource(type.getImplementingClass(), next);
IResource resource = (IResource) toResource(type.getImplementingClass(), next, true);
retVal.add(resource);
}
return retVal;
@ -558,12 +558,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
protected void populateResourceIntoEntity(IResource theResource, ResourceTable theEntity) {
if (theEntity.getPublished().isEmpty()) {
theEntity.setPublished(new Date());
}
theEntity.setUpdated(new Date());
theEntity.setResourceType(toResourceName(theResource));
List<BaseResourceReferenceDt> refs = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, BaseResourceReferenceDt.class);
@ -936,13 +930,13 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return retVal;
}
protected IBaseResource toResource(BaseHasResource theEntity) {
protected IBaseResource toResource(BaseHasResource theEntity, boolean theForHistoryOperation) {
RuntimeResourceDefinition type = myContext.getResourceDefinition(theEntity.getResourceType());
return toResource(type.getImplementingClass(), theEntity);
return toResource(type.getImplementingClass(), theEntity, theForHistoryOperation);
}
@SuppressWarnings("unchecked")
protected <R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity) {
protected <R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation) {
String resourceText = null;
switch (theEntity.getEncoding()) {
case JSON:
@ -983,14 +977,29 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
res = (IResource) myContext.getResourceDefinition(theResourceType).newInstance();
retVal = (R) res;
ResourceMetadataKeyEnum.DELETED_AT.put(res, new InstantDt(theEntity.getDeleted()));
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.DELETE);
if (theForHistoryOperation) {
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.DELETE);
}
} else if (theForHistoryOperation) {
/*
* If the create and update times match, this was when the resource was created
* so we should mark it as a POST. Otherwise, it's a PUT.
*/
Date published = theEntity.getPublished().getValue();
Date updated = theEntity.getUpdated().getValue();
if (published.equals(updated)) {
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.POST);
} else {
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put(res, BundleEntryTransactionMethodEnum.PUT);
}
}
res.setId(theEntity.getIdDt());
ResourceMetadataKeyEnum.VERSION.put(res, Long.toString(theEntity.getVersion()));
ResourceMetadataKeyEnum.PUBLISHED.put(res, theEntity.getPublished());
ResourceMetadataKeyEnum.UPDATED.put(res, theEntity.getUpdated());
IDao.RESOURCE_PID.put(res, theEntity.getId());
if (theEntity.getTitle() != null) {
ResourceMetadataKeyEnum.TITLE.put(res, theEntity.getTitle());
@ -1063,25 +1072,28 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
}
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull) {
return updateEntity(theResource, entity, theUpdateHistory, theDeletedTimestampOrNull, true, true);
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, Date theUpdateTime) {
return updateEntity(theResource, entity, theUpdateHistory, theDeletedTimestampOrNull, true, true, theUpdateTime);
}
@SuppressWarnings("unchecked")
protected ResourceTable updateEntity(final IResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion) {
if (theEntity.getPublished() == null) {
theEntity.setPublished(new Date());
}
protected ResourceTable updateEntity(final IResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion, Date theUpdateTime) {
/*
* This should be the very first thing..
*/
if (theResource != null) {
validateResourceForStorage((T) theResource);
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 + "]");
}
}
if (theEntity.getPublished() == null) {
theEntity.setPublished(theUpdateTime);
}
if (theUpdateHistory) {
final ResourceHistoryTable historyEntry = theEntity.toHistory();
myEntityManager.persist(historyEntry);
@ -1109,25 +1121,25 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
Collection<ResourceIndexedSearchParamCoords> paramsCoords = new ArrayList<ResourceIndexedSearchParamCoords>(theEntity.getParamsCoords());
Collection<ResourceLink> resourceLinks = new ArrayList<ResourceLink>(theEntity.getResourceLinks());
List<ResourceIndexedSearchParamString> stringParams = null;
List<ResourceIndexedSearchParamToken> tokenParams = null;
List<ResourceIndexedSearchParamNumber> numberParams = null;
List<ResourceIndexedSearchParamQuantity> quantityParams = null;
List<ResourceIndexedSearchParamDate> dateParams = null;
List<ResourceIndexedSearchParamUri> uriParams = null;
List<ResourceIndexedSearchParamCoords> coordsParams = null;
List<ResourceLink> links = null;
Set<ResourceIndexedSearchParamString> stringParams = null;
Set<ResourceIndexedSearchParamToken> tokenParams = null;
Set<ResourceIndexedSearchParamNumber> numberParams = null;
Set<ResourceIndexedSearchParamQuantity> quantityParams = null;
Set<ResourceIndexedSearchParamDate> dateParams = null;
Set<ResourceIndexedSearchParamUri> uriParams = null;
Set<ResourceIndexedSearchParamCoords> coordsParams = null;
Set<ResourceLink> links = null;
if (theDeletedTimestampOrNull != null) {
stringParams = Collections.emptyList();
tokenParams = Collections.emptyList();
numberParams = Collections.emptyList();
quantityParams = Collections.emptyList();
dateParams = Collections.emptyList();
uriParams = Collections.emptyList();
coordsParams = Collections.emptyList();
links = Collections.emptyList();
stringParams = Collections.emptySet();
tokenParams = Collections.emptySet();
numberParams = Collections.emptySet();
quantityParams = Collections.emptySet();
dateParams = Collections.emptySet();
uriParams = Collections.emptySet();
coordsParams = Collections.emptySet();
links = Collections.emptySet();
theEntity.setDeleted(theDeletedTimestampOrNull);
theEntity.setUpdated(theDeletedTimestampOrNull);
@ -1147,7 +1159,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
// ourLog.info("Indexing resource: {}", entity.getId());
ourLog.trace("Storing string indexes: {}", stringParams);
tokenParams = new ArrayList<ResourceIndexedSearchParamToken>();
tokenParams = new HashSet<ResourceIndexedSearchParamToken>();
for (BaseResourceIndexedSearchParam next : extractSearchParamTokens(theEntity, theResource)) {
if (next instanceof ResourceIndexedSearchParamToken) {
tokenParams.add((ResourceIndexedSearchParamToken) next);
@ -1159,7 +1171,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
links = extractResourceLinks(theEntity, theResource);
populateResourceIntoEntity(theResource, theEntity);
theEntity.setUpdated(new Date());
theEntity.setUpdated(theUpdateTime);
theEntity.setLanguage(theResource.getLanguage().getValue());
theEntity.setParamsString(stringParams);
theEntity.setParamsStringPopulated(stringParams.isEmpty() == false);
@ -1178,11 +1190,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
theEntity.setResourceLinks(links);
theEntity.setHasLinks(links.isEmpty() == false);
theEntity.setIndexStatus(INDEX_STATUS_INDEXED);
} else {
populateResourceIntoEntity(theResource, theEntity);
theEntity.setUpdated(new Date());
theEntity.setUpdated(theUpdateTime);
theEntity.setLanguage(theResource.getLanguage().getValue());
theEntity.setIndexStatus(null);
@ -1197,8 +1209,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
myEntityManager.persist(theEntity.getForcedId());
}
postPersist(theEntity, (T) theResource);
} else {
theEntity = myEntityManager.merge(theEntity);
postUpdate(theEntity, (T) theResource);
}
if (thePerformIndexing) {
@ -1289,6 +1305,30 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
return theEntity;
}
/**
* Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the
* first time.
*
* @param theEntity
* The resource
* @param theResource The resource being persisted
*/
protected void postUpdate(ResourceTable theEntity, T theResource) {
// nothing
}
/**
* Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the
* first time.
*
* @param theEntity
* The resource
* @param theResource The resource being persisted
*/
protected void postPersist(ResourceTable theEntity, T theResource) {
// nothing
}
/**
* This method is invoked immediately before storing a new resource, or an update to an existing resource to allow
* the DAO to ensure that it is valid for persistence. By default, checks for the "subsetted" tag and rejects
@ -1296,8 +1336,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
*
* @param theResource
* The resource that is about to be persisted
* @param theEntityToSave TODO
*/
protected void validateResourceForStorage(T theResource) {
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
IResource res = (IResource) theResource;
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(res);
if (tagList != null) {

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.INDEX_NOT_FOUND;
/*
* #%L
* HAPI FHIR JPA Server
@ -143,7 +142,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class);
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
private EntityManager myEntityManager;
protected EntityManager myEntityManager;
@Autowired
private PlatformTransactionManager myPlatformTransactionManager;
@ -246,9 +245,10 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
HashSet<Long> found = new HashSet<Long>(q.getResultList());
if (!theExistingPids.isEmpty()) {
theExistingPids.retainAll(found);
return theExistingPids;
} else {
return found;
}
return found;
}
// private Set<Long> addPredicateComposite(String theParamName, Set<Long> thePids, List<? extends
@ -256,49 +256,54 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
// }
private Set<Long> addPredicateLanguage(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList) {
Set<Long> retVal = thePids;
if (theList == null || theList.isEmpty()) {
return thePids;
}
if (theList.size() > 1) {
throw new InvalidRequestException("Language parameter can not have more than one AND value, found " + theList.size());
return retVal;
}
for (List<? extends IQueryParameterType> nextList : theList) {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceTable> from = cq.from(ResourceTable.class);
cq.select(from.get("myId").as(Long.class));
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
Root<ResourceTable> from = cq.from(ResourceTable.class);
cq.select(from.get("myId").as(Long.class));
Set<String> values = new HashSet<String>();
for (IQueryParameterType next : theList.get(0)) {
if (next instanceof StringParam) {
String nextValue = ((StringParam) next).getValue();
if (isBlank(nextValue)) {
continue;
Set<String> values = new HashSet<String>();
for (IQueryParameterType next : nextList) {
if (next instanceof StringParam) {
String nextValue = ((StringParam) next).getValue();
if (isBlank(nextValue)) {
continue;
}
values.add(nextValue);
} else {
throw new InternalErrorException("Lanugage parameter must be of type " + StringParam.class.getCanonicalName() + " - Got " + next.getClass().getCanonicalName());
}
values.add(nextValue);
}
if (values.isEmpty()) {
return retVal;
}
Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
Predicate langPredicate = from.get("myLanguage").as(String.class).in(values);
Predicate masterCodePredicate = builder.and(typePredicate, langPredicate);
Predicate notDeletedPredicate = builder.isNull(from.get("myDeleted"));
if (retVal.size() > 0) {
Predicate inPids = (from.get("myId").in(retVal));
cq.where(builder.and(masterCodePredicate, inPids, notDeletedPredicate));
} else {
throw new InternalErrorException("Lanugage parameter must be of type " + StringParam.class.getCanonicalName() + " - Got " + next.getClass().getCanonicalName());
cq.where(builder.and(masterCodePredicate, notDeletedPredicate));
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
retVal = new HashSet<Long>(q.getResultList());
if (retVal.isEmpty()) {
return retVal;
}
}
if (values.isEmpty()) {
return thePids;
}
Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
Predicate langPredicate = from.get("myLanguage").as(String.class).in(values);
Predicate masterCodePredicate = builder.and(typePredicate, langPredicate);
Predicate notDeletedPredicate = builder.isNull(from.get("myDeleted"));
if (thePids.size() > 0) {
Predicate inPids = (from.get("myId").in(thePids));
cq.where(builder.and(masterCodePredicate, inPids, notDeletedPredicate));
} else {
cq.where(builder.and(masterCodePredicate, notDeletedPredicate));
}
TypedQuery<Long> q = myEntityManager.createQuery(cq);
return new HashSet<Long>(q.getResultList());
return retVal;
}
private boolean addPredicateMissingFalseIfPresent(CriteriaBuilder theBuilder, String theParamName, Root<? extends BaseResourceIndexedSearchParam> from, List<Predicate> codePredicates, IQueryParameterType nextOr) {
@ -1005,7 +1010,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
}
}
return doCreate(theResource, theIfNoneExist, thePerformIndexing);
return doCreate(theResource, theIfNoneExist, thePerformIndexing, new Date());
}
private Predicate createCompositeParamPart(CriteriaBuilder builder, Root<ResourceTable> from, RuntimeSearchParam left, IQueryParameterType leftValue) {
@ -1269,7 +1274,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, theId.getResourceType());
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
ResourceTable savedEntity = updateEntity(null, entity, true, new Date());
Date updateTime = new Date();
ResourceTable savedEntity = updateEntity(null, entity, true, updateTime, updateTime);
notifyWriteCompleted();
@ -1299,14 +1305,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
// Perform delete
ResourceTable savedEntity = updateEntity(null, entity, true, new Date());
Date updateTime = new Date();
ResourceTable savedEntity = updateEntity(null, entity, true, updateTime, updateTime);
notifyWriteCompleted();
ourLog.info("Processed delete on {} in {}ms", theUrl, w.getMillisAndRestart());
return toMethodOutcome(savedEntity, null);
}
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing) {
private DaoMethodOutcome doCreate(T theResource, String theIfNoneExist, boolean thePerformIndexing, Date theUpdateTime) {
StopWatch w = new StopWatch();
preProcessResourceForStorage(theResource);
@ -1347,7 +1354,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
ActionRequestDetails requestDetails = new ActionRequestDetails(theResource.getId(), toResourceName(theResource), theResource);
notifyInterceptors(RestOperationTypeEnum.CREATE, requestDetails);
updateEntity(theResource, entity, false, null, thePerformIndexing, true);
updateEntity(theResource, entity, false, null, thePerformIndexing, true, theUpdateTime);
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(true);
@ -1420,7 +1427,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
try {
BaseHasResource entity = readEntity(theId.toVersionless(), false);
validateResourceType(entity);
currentTmp = toResource(myResourceType, entity);
currentTmp = toResource(myResourceType, entity, true);
if (ResourceMetadataKeyEnum.UPDATED.get(currentTmp).after(end.getValue())) {
currentTmp = null;
}
@ -1497,7 +1504,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
if (retVal.size() == maxResults) {
break;
}
retVal.add(toResource(myResourceType, next));
retVal.add(toResource(myResourceType, next, true));
}
return retVal;
@ -1528,7 +1535,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return retVal;
}
private void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids) {
private void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation) {
if (theIncludePids.isEmpty()) {
return;
}
@ -1547,7 +1554,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
for (ResourceTable next : q.getResultList()) {
Class<? extends IBaseResource> resourceType = getContext().getResourceDefinition(next.getResourceType()).getImplementingClass();
IResource resource = (IResource) toResource(resourceType, next);
IResource resource = (IResource) toResource(resourceType, next, theForHistoryOperation);
Integer index = position.get(next.getId());
if (index == null) {
ourLog.warn("Got back unexpected resource PID {}", next.getId());
@ -1828,7 +1835,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
BaseHasResource entity = readEntity(theId);
validateResourceType(entity);
T retVal = toResource(myResourceType, entity);
T retVal = toResource(myResourceType, entity, false);
InstantDt deleted = ResourceMetadataKeyEnum.DELETED_AT.get(retVal);
if (deleted != null && !deleted.isEmpty()) {
@ -2066,7 +2073,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
// Execute the query and make sure we return distinct results
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
loadResourcesByPid(pidsSubList, retVal, revIncludedPids);
loadResourcesByPid(pidsSubList, retVal, revIncludedPids, false);
return retVal;
}
@ -2126,42 +2133,41 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
if (nextParamEntry.getValue().isEmpty()) {
continue;
} else if (nextParamEntry.getValue().size() > 1) {
throw new InvalidRequestException("AND queries not supported for _id (Multiple instances of this param found)");
} else {
Set<Long> joinPids = new HashSet<Long>();
List<? extends IQueryParameterType> nextValue = nextParamEntry.getValue().get(0);
if (nextValue == null || nextValue.size() == 0) {
continue;
} else {
for (IQueryParameterType next : nextValue) {
String value = next.getValueAsQueryToken();
IIdType valueId = new IdDt(value);
for (List<? extends IQueryParameterType> nextValue : nextParamEntry.getValue()) {
Set<Long> joinPids = new HashSet<Long>();
if (nextValue == null || nextValue.size() == 0) {
continue;
} else {
for (IQueryParameterType next : nextValue) {
String value = next.getValueAsQueryToken();
IIdType valueId = new IdDt(value);
try {
BaseHasResource entity = readEntity(valueId);
if (entity.getDeleted() != null) {
continue;
try {
BaseHasResource entity = readEntity(valueId);
if (entity.getDeleted() != null) {
continue;
}
joinPids.add(entity.getId());
} catch (ResourceNotFoundException e) {
// This isn't an error, just means no result found
}
joinPids.add(entity.getId());
} catch (ResourceNotFoundException e) {
// This isn't an error, just means no result found
}
if (joinPids.isEmpty()) {
return new HashSet<Long>();
}
}
if (joinPids.isEmpty()) {
pids = addPredicateId(pids, joinPids);
if (pids.isEmpty()) {
return new HashSet<Long>();
}
}
pids = addPredicateId(pids, joinPids);
if (pids.isEmpty()) {
return new HashSet<Long>();
}
if (pids.isEmpty()) {
pids.addAll(joinPids);
} else {
pids.retainAll(joinPids);
if (pids.isEmpty()) {
pids.addAll(joinPids);
} else {
pids.retainAll(joinPids);
}
}
}
@ -2382,7 +2388,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
if (resourceId.isIdPartValidLong()) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "failedToCreateWithClientAssignedNumericId", theResource.getId().getIdPart()));
}
return doCreate(theResource, null, thePerformIndexing);
return doCreate(theResource, null, thePerformIndexing, new Date());
}
}
@ -2399,7 +2405,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
// Perform update
ResourceTable savedEntity = updateEntity(theResource, entity, true, null, thePerformIndexing, true);
ResourceTable savedEntity = updateEntity(theResource, entity, true, null, thePerformIndexing, true, new Date());
notifyWriteCompleted();

View File

@ -101,7 +101,7 @@ public abstract class BaseHapiFhirSystemDao<T> extends BaseHapiFhirDao<IBaseReso
for (ResourceTable resourceTable : resources) {
final IBaseResource resource;
try {
resource = toResource(resourceTable);
resource = toResource(resourceTable, false);
} catch (DataFormatException e) {
ourLog.warn("Failure parsing resource: {}", e.toString());
throw new UnprocessableEntityException(Long.toString(resourceTable.getId()));

View File

@ -35,6 +35,8 @@ public class DaoConfig {
private int myIncludeLimit = 2000;
private List<IServerInterceptor> myInterceptors;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private boolean mySubscriptionEnabled;
private long mySubscriptionPollDelay = 1000;
/**
* See {@link #setIncludeLimit(int)}
@ -64,6 +66,17 @@ public class DaoConfig {
return myResourceEncoding;
}
public long getSubscriptionPollDelay() {
return mySubscriptionPollDelay;
}
/**
* See {@link #setSubscriptionEnabled(boolean)}
*/
public boolean isSubscriptionEnabled() {
return mySubscriptionEnabled;
}
public void setHardSearchLimit(int theHardSearchLimit) {
myHardSearchLimit = theHardSearchLimit;
}
@ -90,12 +103,11 @@ public class DaoConfig {
* ID).
* </p>
*/
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
myInterceptors = theInterceptors;
}
public void setResourceEncoding(ResourceEncodingEnum theResourceEncoding) {
myResourceEncoding = theResourceEncoding;
public void setInterceptors(IServerInterceptor... theInterceptor) {
setInterceptors(new ArrayList<IServerInterceptor>());
if (theInterceptor != null && theInterceptor.length != 0) {
getInterceptors().addAll(Arrays.asList(theInterceptor));
}
}
/**
@ -107,12 +119,27 @@ public class DaoConfig {
* ID).
* </p>
*/
public void setInterceptors(IServerInterceptor... theInterceptor) {
if (theInterceptor == null || theInterceptor.length==0){
setInterceptors(new ArrayList<IServerInterceptor>());
} else {
setInterceptors(Arrays.asList(theInterceptor));
}
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
myInterceptors = theInterceptors;
}
public void setResourceEncoding(ResourceEncodingEnum theResourceEncoding) {
myResourceEncoding = theResourceEncoding;
}
/**
* Does this server support subscription? If set to true, the server
* will enable the subscription monitoring mode, which adds a bit of
* overhead. Note that if this is enabled, you must also include
* Spring task scanning to your XML config for the scheduled tasks
* used by the subscription module.
*/
public void setSubscriptionEnabled(boolean theSubscriptionEnabled) {
mySubscriptionEnabled = theSubscriptionEnabled;
}
public void setSubscriptionPollDelay(long theSubscriptionPollDelay) {
mySubscriptionPollDelay = theSubscriptionPollDelay;
}
}

View File

@ -27,6 +27,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
@ -58,8 +59,8 @@ public class FhirResourceDaoQuestionnaireResponseDstu2 extends FhirResourceDaoDs
}
@Override
protected void validateResourceForStorage(QuestionnaireResponse theResource) {
super.validateResourceForStorage(theResource);
protected void validateResourceForStorage(QuestionnaireResponse theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
if (!myValidateResponses) {
return;
}

View File

@ -0,0 +1,183 @@
package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import org.apache.commons.lang3.time.DateUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionFlaggedResourceDataDao;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subscription>implements IFhirResourceDaoSubscription<Subscription> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSubscriptionDstu2.class);
@Autowired
private ISubscriptionFlaggedResourceDataDao mySubscriptionFlaggedResourceDataDao;
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
SubscriptionTable subscriptionEntity = new SubscriptionTable();
subscriptionEntity.setSubscriptionResource(theEntity);
subscriptionEntity.setNextCheck(theEntity.getPublished().getValue());
subscriptionEntity.setMostRecentMatch(theEntity.getPublished().getValue());
subscriptionEntity.setStatus(theSubscription.getStatusElement().getValueAsEnum());
myEntityManager.persist(subscriptionEntity);
}
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void pollForNewUndeliveredResources() {
if (getConfig().isSubscriptionEnabled() == false) {
return;
}
ourLog.trace("Beginning pollForNewUndeliveredResources()");
// SubscriptionCandidateResource
TypedQuery<SubscriptionTable> q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_NEXT_CHECK", SubscriptionTable.class);
q.setParameter("next_check", new Date());
q.setParameter("status", SubscriptionStatusEnum.ACTIVE);
List<SubscriptionTable> subscriptions = q.getResultList();
for (SubscriptionTable nextSubscriptionTable : subscriptions) {
pollForNewUndeliveredResources(nextSubscriptionTable);
}
}
private void pollForNewUndeliveredResources(SubscriptionTable theSubscriptionTable) {
Subscription subscription = toResource(Subscription.class, theSubscriptionTable.getSubscriptionResource(), false);
RuntimeResourceDefinition resourceDef = validateCriteriaAndReturnResourceDefinition(subscription);
SearchParameterMap criteriaUrl = translateMatchUrl(subscription.getCriteria(), resourceDef);
criteriaUrl = new SearchParameterMap();//TODO:remove
long start = theSubscriptionTable.getMostRecentMatch().getTime();
long end = System.currentTimeMillis() - getConfig().getSubscriptionPollDelay();
if (end <= start) {
ourLog.trace("Skipping search for subscription");
return;
}
ourLog.info("Subscription search from {} to {}", start, end);
DateRangeParam range = new DateRangeParam();
range.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN, start));
range.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN, end));
criteriaUrl.setLastUpdated(range);
IFhirResourceDao<? extends IBaseResource> dao = getDao(resourceDef.getImplementingClass());
IBundleProvider results = dao.search(criteriaUrl);
if (results.size() == 0) {
return;
}
ourLog.info("Found {} new results for Subscription {}", results.size(), subscription.getId().getIdPart());
List<SubscriptionFlaggedResource> flags = new ArrayList<SubscriptionFlaggedResource>();
for (IBaseResource next : results.getResources(0, results.size())) {
SubscriptionFlaggedResource nextFlag = new SubscriptionFlaggedResource();
// nextFlag.setResource();
}
}
@Override
protected void postPersist(ResourceTable theEntity, Subscription theSubscription) {
super.postPersist(theEntity, theSubscription);
createSubscriptionTable(theEntity, theSubscription);
}
@Override
protected ResourceTable updateEntity(IResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion, Date theUpdateTime) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
Subscription resource = (Subscription) theResource;
Long resourceId = theEntity.getId();
if (theDeletedTimestampOrNull != null) {
Query q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_DELETE");
q.setParameter("res_id", resourceId);
q.executeUpdate();
} else {
Query q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_SET_STATUS");
q.setParameter("res_id", resourceId);
q.setParameter("status", resource.getStatusElement().getValueAsEnum());
if (q.executeUpdate() > 0) {
ourLog.info("Updated subscription status for subscription {} to {}", resourceId, resource.getStatusElement().getValueAsEnum());
} else {
createSubscriptionTable(retVal, resource);
}
}
return retVal;
}
@Override
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
if (dao == null) {
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resDef);
}
if (theResource.getChannel().getType() == null) {
throw new UnprocessableEntityException("Subscription.channel.type must be populated on this server");
}
SubscriptionStatusEnum status = theResource.getStatusElement().getValueAsEnum();
if (status == null) {
throw new UnprocessableEntityException("Subscription.status must be populated on this server");
}
}
private RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
String query = theResource.getCriteria();
if (isBlank(query)) {
throw new UnprocessableEntityException("Subscription.criteria must be populated");
}
int sep = query.indexOf('?');
if (sep <= 1) {
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
}
String resType = query.substring(0, sep);
if (resType.contains("/")) {
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
}
RuntimeResourceDefinition resDef;
try {
resDef = getContext().getResourceDefinition(resType);
} catch (DataFormatException e) {
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resType);
}
return resDef;
}
}

View File

@ -60,7 +60,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>
if (sourceEntity == null) {
throw new ResourceNotFoundException(theId);
}
ValueSet source = (ValueSet) toResource(sourceEntity);
ValueSet source = (ValueSet) toResource(sourceEntity, false);
/*
* Add composed concepts

View File

@ -104,6 +104,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>> {
OperationOutcome oo = new OperationOutcome();
retVal.add(oo);
Date updateTime = new Date();
for (int resourceIdx = 0; resourceIdx < theResources.size(); resourceIdx++) {
IResource nextResource = theResources.get(resourceIdx);
@ -160,6 +161,8 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>> {
if (entity == null) {
nextResouceOperationOut = BundleEntryTransactionMethodEnum.POST;
entity = toEntity(nextResource);
entity.setUpdated(updateTime);
entity.setPublished(updateTime);
if (nextId.isEmpty() == false && "cid:".equals(nextId.getBaseUrl())) {
ourLog.debug("Resource in transaction has ID[{}], will replace with server assigned ID", nextId.getIdPart());
} else if (nextResouceOperationIn == BundleEntryTransactionMethodEnum.POST) {
@ -170,7 +173,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>> {
if (candidateMatches.size() == 1) {
ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
BaseHasResource existingEntity = loadFirstEntityFromCandidateMatches(candidateMatches);
IResource existing = (IResource) toResource(existingEntity);
IResource existing = (IResource) toResource(existingEntity, false);
persistedResources.add(null);
retVal.add(existing);
continue;
@ -262,11 +265,11 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>> {
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(resource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
if (deletedInstantOrNull == null && ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(resource) == BundleEntryTransactionMethodEnum.DELETE) {
deletedTimestampOrNull = new Date();
deletedTimestampOrNull = updateTime;
ResourceMetadataKeyEnum.DELETED_AT.put(resource, new InstantDt(deletedTimestampOrNull));
}
updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull);
updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull, updateTime);
}
long delay = System.currentTimeMillis() - start;

View File

@ -19,7 +19,9 @@ package ca.uhn.fhir.jpa.dao;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.Date;
import java.util.HashMap;
@ -64,6 +66,8 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.util.UrlUtil.UrlParts;
public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class);
@ -92,10 +96,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
resp.addEntry().setResource(ooResp);
/*
* For batch, we handle each entry as a mini-transaction in its own
* database transaction so that if one fails, it doesn't prevent others
* For batch, we handle each entry as a mini-transaction in its own database transaction so that if one fails, it
* doesn't prevent others
*/
for (final Entry nextRequestEntry : theRequest.getEntry()) {
TransactionCallback<Bundle> callback = new TransactionCallback<Bundle>() {
@ -118,13 +122,13 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
Entry subResponseEntry = nextResponseBundle.getEntry().get(0);
resp.addEntry(subResponseEntry);
/*
* If the individual entry didn't have a resource in its response, bring the
* sub-transaction's OperationOutcome across so the client can see it
* If the individual entry didn't have a resource in its response, bring the sub-transaction's
* OperationOutcome across so the client can see it
*/
if (subResponseEntry.getResource() == null) {
subResponseEntry.setResource(nextResponseBundle.getEntry().get(0).getResource());
}
} catch (BaseServerResponseException e) {
caughtEx = e;
} catch (Throwable t) {
@ -167,75 +171,6 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
return retVal;
}
private UrlParts parseUrl(String theAction, String theUrl) {
UrlParts retVal = new UrlParts();
//@formatter:off
/*
* We assume that the URL passed in is in one of the following forms:
* [Resource Type]?[Search Params]
* [Resource Type]/[Resource ID]
* [Resource Type]/[Resource ID]/_history/[Version ID]
*/
//@formatter:on
int nextStart = 0;
boolean nextIsHistory = false;
for (int idx = 0; idx < theUrl.length(); idx++) {
char nextChar = theUrl.charAt(idx);
boolean atEnd = (idx + 1) == theUrl.length();
if (nextChar == '?' || nextChar == '/' || atEnd) {
int endIdx = atEnd ? idx + 1 : idx;
String nextSubstring = theUrl.substring(nextStart, endIdx);
if (retVal.getResourceType() == null) {
retVal.setResourceType(nextSubstring);
} else if (retVal.getResourceId() == null) {
retVal.setResourceId(nextSubstring);
} else if (nextIsHistory) {
retVal.setVersionId(nextSubstring);
} else {
if (nextSubstring.equals(Constants.URL_TOKEN_HISTORY)) {
nextIsHistory = true;
} else {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
}
if (nextChar == '?') {
if (theUrl.length() > idx + 1) {
retVal.setParams(theUrl.substring(idx + 1, theUrl.length()));
}
break;
}
nextStart = idx + 1;
}
}
RuntimeResourceDefinition resType;
try {
resType = getContext().getResourceDefinition(retVal.getResourceType());
} catch (DataFormatException e) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
IFhirResourceDao<? extends IBaseResource> dao = null;
if (resType != null) {
dao = getDao(resType.getImplementingClass());
}
if (dao == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
retVal.setDao(dao);
if (retVal.getResourceId() == null && retVal.getParams() == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
return retVal;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Bundle transaction(Bundle theRequest) {
@ -265,6 +200,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
ourLog.info("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
long start = System.currentTimeMillis();
Date updateTime = new Date();
Set<IdDt> allIds = new LinkedHashSet<IdDt>();
Map<IdDt, IdDt> idSubstitutions = new HashMap<IdDt, IdDt>();
@ -275,11 +211,11 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
// TODO: process verbs in the correct order
for (int i = 0; i < theRequest.getEntry().size(); i++) {
if (i % 100 == 0) {
ourLog.info("Processed {} entries out of {}", i, theRequest.getEntry().size());
}
Entry nextEntry = theRequest.getEntry().get(i);
IResource res = nextEntry.getResource();
IdDt nextResourceId = null;
@ -330,11 +266,12 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
// DELETE
Entry newEntry = response.addEntry();
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url);
UrlParts parts = UrlUtil.parseUrl(url);
ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.getCode(), url);
if (parts.getResourceId() != null) {
parts.getDao().delete(new IdDt(parts.getResourceType(), parts.getResourceId()));
dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()));
} else {
parts.getDao().deleteByUrl(parts.getResourceType() + '?' + parts.getParams());
dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams());
}
newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_204_NO_CONTENT));
@ -350,7 +287,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url);
UrlParts parts = UrlUtil.parseUrl(url);
if (isNotBlank(parts.getResourceId())) {
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
outcome = resourceDao.update(res, null, false);
@ -365,10 +302,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
case GET: {
// SEARCH/READ/VREAD
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url);
UrlParts parts = UrlUtil.parseUrl(url);
@SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = parts.getDao();
IFhirResourceDao dao = toDao(parts, verb.getCode(), url);
String ifNoneMatch = nextEntry.getRequest().getIfNoneMatch();
if (isNotBlank(ifNoneMatch)) {
@ -382,9 +319,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
if (isNotBlank(ifNoneMatch)) {
throw new InvalidRequestException("Unable to perform vread on '" + url + "' with ifNoneMatch also set. Do not include a version in the URL to perform a conditional read.");
}
found = (IResource) resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId(), parts.getVersionId()));
found = (IResource) dao.read(new IdDt(parts.getResourceType(), parts.getResourceId(), parts.getVersionId()));
} else {
found = (IResource) resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId()));
found = (IResource) dao.read(new IdDt(parts.getResourceType(), parts.getResourceId()));
if (isNotBlank(ifNoneMatch) && ifNoneMatch.equals(found.getId().getVersionIdPart())) {
notChanged = true;
}
@ -402,9 +339,9 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
resp.setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED));
}
} else if (parts.getParams() != null) {
RuntimeResourceDefinition def = getContext().getResourceDefinition(parts.getDao().getResourceType());
RuntimeResourceDefinition def = getContext().getResourceDefinition(dao.getResourceType());
SearchParameterMap params = translateMatchUrl(url, def);
IBundleProvider bundle = parts.getDao().search(params);
IBundleProvider bundle = dao.search(params);
Bundle searchBundle = new Bundle();
searchBundle.setTotal(bundle.size());
@ -453,7 +390,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false);
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false, updateTime);
}
myEntityManager.flush();
@ -468,8 +405,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
IFhirResourceDao<?> resourceDao = getDao(nextEntry.getResource().getClass());
Set<Long> val = resourceDao.processMatchUrl(matchUrl);
if (val.size() > 1) {
throw new InvalidRequestException(
"Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
throw new InvalidRequestException("Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
}
}
}
@ -488,13 +424,38 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
long delay = System.currentTimeMillis() - start;
ourLog.info(theActionName + " completed in {}ms", new Object[] { delay });
notifyWriteCompleted();
response.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
return response;
}
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
RuntimeResourceDefinition resType;
try {
resType = getContext().getResourceDefinition(theParts.getResourceType());
} catch (DataFormatException e) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
throw new InvalidRequestException(msg);
}
IFhirResourceDao<? extends IBaseResource> dao = null;
if (resType != null) {
dao = getDao(resType.getImplementingClass());
}
if (dao == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
throw new InvalidRequestException(msg);
}
if (theParts.getResourceId() == null && theParts.getParams() == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
throw new InvalidRequestException(msg);
}
return dao;
}
private IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IResource> theClass) {
IFhirResourceDao<? extends IResource> retVal = getDao(theClass);
if (retVal == null) {
@ -503,15 +464,15 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
return retVal;
}
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome,
Entry newEntry, String theResourceType, IResource theRes) {
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome, Entry newEntry, String theResourceType, IResource theRes) {
IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless();
IdDt resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless();
if (newId.equals(resourceId) == false) {
idSubstitutions.put(resourceId, newId);
if (isPlaceholder(resourceId)) {
/*
* The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified kind too just to be lenient.
* The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified
* kind too just to be lenient.
*/
idSubstitutions.put(new IdDt(theResourceType + '/' + resourceId.getValue()), newId);
}
@ -538,52 +499,4 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
}
private static class UrlParts {
private IFhirResourceDao<? extends IBaseResource> myDao;
private String myParams;
private String myResourceId;
private String myResourceType;
private String myVersionId;
public IFhirResourceDao<? extends IBaseResource> getDao() {
return myDao;
}
public String getParams() {
return myParams;
}
public String getResourceId() {
return myResourceId;
}
public String getResourceType() {
return myResourceType;
}
public String getVersionId() {
return myVersionId;
}
public void setDao(IFhirResourceDao<? extends IBaseResource> theDao) {
myDao = theDao;
}
public void setParams(String theParams) {
myParams = theParams;
}
public void setResourceId(String theResourceId) {
myResourceId = theResourceId;
}
public void setResourceType(String theResourceType) {
myResourceType = theResourceType;
}
public void setVersionId(String theVersionId) {
myVersionId = theVersionId;
}
}
}

View File

@ -1,5 +1,8 @@
package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
/*
* #%L
* HAPI FHIR JPA Server
@ -22,6 +25,21 @@ package ca.uhn.fhir.jpa.dao;
public interface IDao {
void registerDaoListener(IDaoListener theListener);
public static final ResourceMetadataKeyEnum<Long> RESOURCE_PID = new ResourceMetadataKeyEnum<Long>("RESOURCE_PID") {
private static final long serialVersionUID = 1L;
@Override
public Long get(IResource theResource) {
return (Long) theResource.getResourceMetadata().get(RESOURCE_PID);
}
@Override
public void put(IResource theResource, Long theObject) {
theResource.getResourceMetadata().put(RESOURCE_PID, theObject);
}
};
void registerDaoListener(IDaoListener theListener);
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 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 org.hl7.fhir.instance.model.api.IBaseResource;
public interface IFhirResourceDaoSubscription<T extends IBaseResource> extends IFhirResourceDao<T> {
void pollForNewUndeliveredResources();
}

View File

@ -1,27 +1,6 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 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.ArrayList;
import java.util.List;
import java.util.Set;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
@ -35,18 +14,18 @@ import ca.uhn.fhir.model.api.IResource;
interface ISearchParamExtractor {
public abstract List<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource);
public abstract Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource);
public abstract List<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource);
public abstract Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource);
public abstract ArrayList<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource);
public abstract Set<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource);
public abstract List<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource);
public abstract Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource);
public abstract List<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource);
public abstract Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource);
public abstract List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource);
public abstract Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource);
public abstract List<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource);
public abstract Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource);
}

View File

@ -75,13 +75,13 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
public List<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
return Collections.emptyList();
public Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
return Collections.emptySet();
}
@Override
public List<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamDate> retVal = new ArrayList<ResourceIndexedSearchParamDate>();
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -135,8 +135,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
public ArrayList<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamNumber> retVal = new ArrayList<ResourceIndexedSearchParamNumber>();
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -230,8 +230,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
public List<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamQuantity> retVal = new ArrayList<ResourceIndexedSearchParamQuantity>();
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -278,8 +278,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
public List<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamString> retVal = new ArrayList<ResourceIndexedSearchParamString>();
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -364,8 +364,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
public List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
ArrayList<BaseResourceIndexedSearchParam> retVal = new ArrayList<BaseResourceIndexedSearchParam>();
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
HashSet<BaseResourceIndexedSearchParam> retVal = new HashSet<BaseResourceIndexedSearchParam>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -472,8 +472,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
public List<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
return Collections.emptyList();
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
return Collections.emptySet();
}
}

View File

@ -84,7 +84,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
super(theContext);
}
private void addSearchTerm(ResourceTable theEntity, ArrayList<ResourceIndexedSearchParamString> retVal, String resourceName, String searchTerm) {
private void addSearchTerm(ResourceTable theEntity, Set<ResourceIndexedSearchParamString> retVal, String resourceName, String searchTerm) {
if (isBlank(searchTerm)) {
return;
}
@ -97,7 +97,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
retVal.add(nextEntity);
}
private void addStringParam(ResourceTable theEntity, ArrayList<BaseResourceIndexedSearchParam> retVal, RuntimeSearchParam nextSpDef, String value) {
private void addStringParam(ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> retVal, RuntimeSearchParam nextSpDef, String value) {
if (value.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
value = value.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
}
@ -107,9 +107,9 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
}
@Override
public List<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
public Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
// TODO: implement
return Collections.emptyList();
return Collections.emptySet();
}
/*
@ -118,8 +118,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamDate> retVal = new ArrayList<ResourceIndexedSearchParamDate>();
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -178,8 +178,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public ArrayList<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamNumber> retVal = new ArrayList<ResourceIndexedSearchParamNumber>();
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -272,8 +272,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamQuantity> retVal = new ArrayList<ResourceIndexedSearchParamQuantity>();
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -326,8 +326,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamString> retVal = new ArrayList<ResourceIndexedSearchParamString>();
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -407,8 +407,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IResource)
*/
@Override
public List<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
ArrayList<BaseResourceIndexedSearchParam> retVal = new ArrayList<BaseResourceIndexedSearchParam>();
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
HashSet<BaseResourceIndexedSearchParam> retVal = new HashSet<BaseResourceIndexedSearchParam>();
String useSystem = null;
if (theResource instanceof ValueSet) {
@ -556,8 +556,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
}
@Override
public List<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
ArrayList<ResourceIndexedSearchParamUri> retVal = new ArrayList<ResourceIndexedSearchParamUri>();
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamUri> retVal = new HashSet<ResourceIndexedSearchParamUri>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@ -608,13 +608,13 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity,
ArrayList<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
}
}
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, ArrayList<BaseResourceIndexedSearchParam> theListToPopulate,
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate,
RuntimeSearchParam theParameterDef, CodingDt nextCoding) {
if (nextCoding != null && !nextCoding.isEmpty()) {

View File

@ -21,8 +21,8 @@ package ca.uhn.fhir.jpa.dao;
*/
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;
@ -36,7 +36,7 @@ import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
public class SearchParameterMap extends HashMap<String, List<List<? extends IQueryParameterType>>> {
public class SearchParameterMap extends LinkedHashMap<String, List<List<? extends IQueryParameterType>>> {
private static final long serialVersionUID = 1L;

View File

@ -0,0 +1,9 @@
package ca.uhn.fhir.jpa.dao.data;
import org.springframework.data.repository.CrudRepository;
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
public interface ISubscriptionFlaggedResourceDataDao extends CrudRepository<SubscriptionFlaggedResource, Long> {
}

View File

@ -98,7 +98,11 @@ public abstract class BaseHasResource {
public abstract IdDt getIdDt();
public InstantDt getPublished() {
return new InstantDt(myPublished);
if (myPublished != null) {
return new InstantDt(myPublished);
} else {
return null;
}
}
public byte[] getResource() {

View File

@ -24,6 +24,11 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
//@formatter:off
@Entity
@Table(name = "HFJ_SPIDX_COORDS" /* , indexes = { @Index(name = "IDX_SP_TOKEN", columnList = "SP_SYSTEM,SP_VALUE") } */)
@ -52,20 +57,59 @@ public class ResourceIndexedSearchParamCoords extends BaseResourceIndexedSearchP
setLongitude(theLongitude);
}
public double getLatitude() {
return myLatitude;
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamCoords)) {
return false;
}
ResourceIndexedSearchParamCoords obj = (ResourceIndexedSearchParamCoords) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getLatitude(), obj.getLatitude());
b.append(getLongitude(), obj.getLongitude());
return b.isEquals();
}
public void setLatitude(double theLatitude) {
myLatitude = theLatitude;
public double getLatitude() {
return myLatitude;
}
public double getLongitude() {
return myLongitude;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getLatitude());
b.append(getLongitude());
return b.toHashCode();
}
public void setLatitude(double theLatitude) {
myLatitude = theLatitude;
}
public void setLongitude(double theLongitude) {
myLongitude = theLongitude;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
b.append("lat", getLatitude());
b.append("lon", getLongitude());
return b.build();
}
}

View File

@ -28,6 +28,11 @@ import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
//@formatter:off
@Entity
@Table(name = "HFJ_SPIDX_DATE" /*, indexes= {@Index(name="IDX_SP_DATE", columnList= "SP_VALUE_LOW,SP_VALUE_HIGH")}*/)
@ -47,18 +52,34 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
@Temporal(TemporalType.TIMESTAMP)
public Date myValueLow;
public ResourceIndexedSearchParamDate() {
}
public ResourceIndexedSearchParamDate(String theName, Date theLow, Date theHigh) {
setParamName(theName);
setValueLow(theLow);
setValueHigh(theHigh);
}
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamDate)) {
return false;
}
ResourceIndexedSearchParamDate obj = (ResourceIndexedSearchParamDate) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getValueHigh(), obj.getValueHigh());
b.append(getValueLow(), obj.getValueLow());
return b.isEquals();
}
public Date getValueHigh() {
return myValueHigh;
@ -68,6 +89,16 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
return myValueLow;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getValueHigh());
b.append(getValueLow());
return b.toHashCode();
}
public void setValueHigh(Date theValueHigh) {
myValueHigh = theValueHigh;
}
@ -76,6 +107,13 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
myValueLow = theValueLow;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
b.append("valueLow", getValueLow());
b.append("valueHigh", getValueHigh());
return b.build();
}
}

View File

@ -26,6 +26,11 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
//@formatter:off
@Entity
@Table(name = "HFJ_SPIDX_NUMBER" /*, indexes= {@Index(name="IDX_SP_NUMBER", columnList="SP_VALUE")}*/ )
@ -39,21 +44,57 @@ public class ResourceIndexedSearchParamNumber extends BaseResourceIndexedSearchP
@Column(name = "SP_VALUE", nullable = true)
public BigDecimal myValue;
public ResourceIndexedSearchParamNumber() {
}
public ResourceIndexedSearchParamNumber(String theParamName, BigDecimal theValue) {
setParamName(theParamName);
setValue(theValue);
}
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamNumber)) {
return false;
}
ResourceIndexedSearchParamNumber obj = (ResourceIndexedSearchParamNumber) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getValue(), obj.getValue());
return b.isEquals();
}
public BigDecimal getValue() {
return myValue;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getValue());
return b.toHashCode();
}
public void setValue(BigDecimal theValue) {
myValue = theValue;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
b.append("value", getValue());
return b.build();
}
}

View File

@ -26,6 +26,11 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
//@formatter:off
@Entity
@Table(name = "HFJ_SPIDX_QUANTITY" /*, indexes= {@Index(name="IDX_SP_NUMBER", columnList="SP_VALUE")}*/ )
@ -47,9 +52,9 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
public BigDecimal myValue;
public ResourceIndexedSearchParamQuantity() {
//nothing
// nothing
}
public ResourceIndexedSearchParamQuantity(String theParamName, BigDecimal theValue, String theSystem, String theUnits) {
setParamName(theParamName);
setSystem(theSystem);
@ -57,6 +62,27 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
setUnits(theUnits);
}
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamQuantity)) {
return false;
}
ResourceIndexedSearchParamQuantity obj = (ResourceIndexedSearchParamQuantity) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getSystem(), obj.getSystem());
b.append(getUnits(), obj.getUnits());
b.append(getValue(), obj.getValue());
return b.isEquals();
}
public String getSystem() {
return mySystem;
}
@ -69,6 +95,16 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
return myValue;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getSystem());
b.append(getUnits());
b.append(getValue());
return b.toHashCode();
}
public void setSystem(String theSystem) {
mySystem = theSystem;
@ -82,4 +118,15 @@ public class ResourceIndexedSearchParamQuantity extends BaseResourceIndexedSearc
myValue = theValue;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
b.append("system", getSystem());
b.append("units", getUnits());
b.append("value", getValue());
return b.build();
}
}

View File

@ -25,25 +25,26 @@ import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@Entity
@Table(name = "HFJ_SPIDX_STRING"/*, indexes= {@Index(name="IDX_SP_STRING", columnList="SP_VALUE_NORMALIZED")}*/)
@org.hibernate.annotations.Table(appliesTo="HFJ_SPIDX_STRING",indexes= {
@org.hibernate.annotations.Index(name="IDX_SP_STRING", columnNames= {"RES_TYPE", "SP_NAME", "SP_VALUE_NORMALIZED"})})
@Table(name = "HFJ_SPIDX_STRING"/* , indexes= {@Index(name="IDX_SP_STRING", columnList="SP_VALUE_NORMALIZED")} */)
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_STRING", indexes = { @org.hibernate.annotations.Index(name = "IDX_SP_STRING", columnNames = { "RES_TYPE", "SP_NAME", "SP_VALUE_NORMALIZED" }) })
public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchParam {
public static final int MAX_LENGTH = 100;
private static final long serialVersionUID = 1L;
@Column(name = "SP_VALUE_EXACT", length = 100, nullable = true)
public String myValueExact;
@Column(name = "SP_VALUE_NORMALIZED", length = MAX_LENGTH, nullable = true)
public String myValueNormalized;
@Column(name="SP_VALUE_EXACT",length=100,nullable=true)
public String myValueExact;
public ResourceIndexedSearchParamString() {
}
@ -53,21 +54,42 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
setValueExact(theValueExact);
}
public String getValueNormalized() {
return myValueNormalized;
}
public void setValueNormalized(String theValueNormalized) {
if (StringUtils.defaultString(theValueNormalized).length() > MAX_LENGTH) {
throw new IllegalArgumentException("Value is too long: " + theValueNormalized.length());
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
myValueNormalized = theValueNormalized;
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamString)) {
return false;
}
ResourceIndexedSearchParamString obj = (ResourceIndexedSearchParamString) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getValueExact(), obj.getValueExact());
return b.isEquals();
}
public String getValueExact() {
return myValueExact;
}
public String getValueNormalized() {
return myValueNormalized;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getValueExact());
return b.toHashCode();
}
public void setValueExact(String theValueExact) {
if (StringUtils.defaultString(theValueExact).length() > MAX_LENGTH) {
throw new IllegalArgumentException("Value is too long: " + theValueExact.length());
@ -75,6 +97,13 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
myValueExact = theValueExact;
}
public void setValueNormalized(String theValueNormalized) {
if (StringUtils.defaultString(theValueNormalized).length() > MAX_LENGTH) {
throw new IllegalArgumentException("Value is too long: " + theValueNormalized.length());
}
myValueNormalized = theValueNormalized;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
@ -83,5 +112,4 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
b.append("value", getValueNormalized());
return b.build();
}
}

View File

@ -25,13 +25,15 @@ import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@Entity
@Table(name = "HFJ_SPIDX_TOKEN" /* , indexes = { @Index(name = "IDX_SP_TOKEN", columnList = "SP_SYSTEM,SP_VALUE") } */)
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_TOKEN", indexes = {
@org.hibernate.annotations.Index(name = "IDX_SP_TOKEN", columnNames = { "RES_TYPE", "SP_NAME", "SP_SYSTEM", "SP_VALUE" }),
@org.hibernate.annotations.Index(name = "IDX_SP_TOKEN_UNQUAL", columnNames = { "RES_TYPE", "SP_NAME", "SP_VALUE" })
})
@org.hibernate.annotations.Table(appliesTo = "HFJ_SPIDX_TOKEN", indexes = { @org.hibernate.annotations.Index(name = "IDX_SP_TOKEN", columnNames = { "RES_TYPE", "SP_NAME", "SP_SYSTEM", "SP_VALUE" }),
@org.hibernate.annotations.Index(name = "IDX_SP_TOKEN_UNQUAL", columnNames = { "RES_TYPE", "SP_NAME", "SP_VALUE" }) })
public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchParam {
public static final int MAX_LENGTH = 100;
@ -53,6 +55,26 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
setValue(theValue);
}
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamToken)) {
return false;
}
ResourceIndexedSearchParamToken obj = (ResourceIndexedSearchParamToken) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getSystem(), obj.getSystem());
b.append(getValue(), obj.getValue());
return b.isEquals();
}
public String getSystem() {
return mySystem;
}
@ -61,6 +83,16 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
return myValue;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getSystem());
b.append(getValue());
return b.toHashCode();
}
public void setSystem(String theSystem) {
mySystem = StringUtils.defaultIfBlank(theSystem, null);
}
@ -69,4 +101,13 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
myValue = StringUtils.defaultIfBlank(theValue, null);
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("paramName", getParamName());
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
b.append("system", getSystem());
b.append("value", getValue());
return b.build();
}
}

View File

@ -25,6 +25,8 @@ import javax.persistence.Entity;
import javax.persistence.Table;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
//@formatter:off
@ -51,10 +53,38 @@ public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchPara
setUri(theUri);
}
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceIndexedSearchParamUri)) {
return false;
}
ResourceIndexedSearchParamUri obj = (ResourceIndexedSearchParamUri) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(getParamName(), obj.getParamName());
b.append(getResource(), obj.getResource());
b.append(getUri(), obj.getUri());
return b.isEquals();
}
public String getUri() {
return myUri;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(getParamName());
b.append(getResource());
b.append(getUri());
return b.toHashCode();
}
public void setUri(String theUri) {
myUri = StringUtils.defaultIfBlank(theUri, null);
}

View File

@ -32,11 +32,12 @@ import javax.persistence.ManyToOne;
import javax.persistence.Table;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
@Entity
@Table(name = "HFJ_RES_LINK"/*, indexes= {@Index(name="IDX_RL_TPATHRES", columnList= "SRC_PATH,TARGET_RESOURCE_ID")}*/)
@org.hibernate.annotations.Table(appliesTo="HFJ_RES_LINK",indexes= {
@org.hibernate.annotations.Index(name="IDX_RL_TPATHRES", columnNames= {"SRC_PATH", "TARGET_RESOURCE_ID"})})
@Table(name = "HFJ_RES_LINK"/* , indexes= {@Index(name="IDX_RL_TPATHRES", columnList= "SRC_PATH,TARGET_RESOURCE_ID")} */)
@org.hibernate.annotations.Table(appliesTo = "HFJ_RES_LINK", indexes = { @org.hibernate.annotations.Index(name = "IDX_RL_TPATHRES", columnNames = { "SRC_PATH", "TARGET_RESOURCE_ID" }) })
public class ResourceLink implements Serializable {
private static final long serialVersionUID = 1L;
@ -50,33 +51,21 @@ public class ResourceLink implements Serializable {
private String mySourcePath;
@ManyToOne(optional = false)
@JoinColumn(name = "SRC_RESOURCE_ID", referencedColumnName="RES_ID", nullable=false)
@JoinColumn(name = "SRC_RESOURCE_ID", referencedColumnName = "RES_ID", nullable = false)
private ResourceTable mySourceResource;
@Column(name = "SRC_RESOURCE_ID", insertable = false, updatable = false, nullable=false)
@Column(name = "SRC_RESOURCE_ID", insertable = false, updatable = false, nullable = false)
private Long mySourceResourcePid;
@ManyToOne(optional = false)
@JoinColumn(name = "TARGET_RESOURCE_ID", referencedColumnName="RES_ID", nullable=false)
@JoinColumn(name = "TARGET_RESOURCE_ID", referencedColumnName = "RES_ID", nullable = false)
private ResourceTable myTargetResource;
@Column(name = "TARGET_RESOURCE_ID", insertable = false, updatable = false,nullable=false)
@Column(name = "TARGET_RESOURCE_ID", insertable = false, updatable = false, nullable = false)
private Long myTargetResourcePid;
public ResourceLink() {
//nothing
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("ResourceLink[");
b.append("path=").append(mySourcePath);
b.append(", src=").append(mySourceResource.getId());
b.append(", target=").append(myTargetResource.getId());
b.append("]");
return b.toString();
// nothing
}
public ResourceLink(String theSourcePath, ResourceTable theSourceResource, ResourceTable theTargetResource) {
@ -86,6 +75,25 @@ public class ResourceLink implements Serializable {
myTargetResource = theTargetResource;
}
@Override
public boolean equals(Object theObj) {
if (this == theObj) {
return true;
}
if (theObj == null) {
return false;
}
if (!(theObj instanceof ResourceLink)) {
return false;
}
ResourceLink obj = (ResourceLink) theObj;
EqualsBuilder b = new EqualsBuilder();
b.append(mySourcePath, obj.mySourcePath);
b.append(mySourceResource, obj.mySourceResource);
b.append(myTargetResource, obj.myTargetResource);
return b.isEquals();
}
public String getSourcePath() {
return mySourcePath;
}
@ -106,6 +114,15 @@ public class ResourceLink implements Serializable {
return myTargetResourcePid;
}
@Override
public int hashCode() {
HashCodeBuilder b = new HashCodeBuilder();
b.append(mySourcePath);
b.append(mySourceResource);
b.append(myTargetResource);
return b.toHashCode();
}
public void setSourcePath(String theSourcePath) {
mySourcePath = theSourcePath;
}
@ -114,17 +131,21 @@ public class ResourceLink implements Serializable {
mySourceResource = theSourceResource;
}
public void setSourceResourcePid(Long theSourceResourcePid) {
mySourceResourcePid = theSourceResourcePid;
}
public void setTargetResource(ResourceTable theTargetResource) {
Validate.notNull(theTargetResource);
myTargetResource = theTargetResource;
}
public void setTargetResourcePid(Long theTargetResourcePid) {
myTargetResourcePid = theTargetResourcePid;
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("ResourceLink[");
b.append("path=").append(mySourcePath);
b.append(", src=").append(mySourceResource.getId());
b.append(", target=").append(myTargetResource.getId());
b.append("]");
return b.toString();
}
}

View File

@ -19,14 +19,12 @@ package ca.uhn.fhir.jpa.entity;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.persistence.CascadeType;
@ -329,7 +327,7 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myParamsDatePopulated = theParamsDatePopulated;
}
public void setParamsNumber(List<ResourceIndexedSearchParamNumber> theNumberParams) {
public void setParamsNumber(Collection<ResourceIndexedSearchParamNumber> theNumberParams) {
if (!isParamsNumberPopulated() && theNumberParams.isEmpty()) {
return;
}
@ -396,7 +394,7 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myProfile = theProfile;
}
public void setResourceLinks(List<ResourceLink> theLinks) {
public void setResourceLinks(Collection<ResourceLink> theLinks) {
if (!isHasLinks() && theLinks.isEmpty()) {
return;
}

View File

@ -0,0 +1,47 @@
package ca.uhn.fhir.jpa.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
@Entity
@Table(name = "HFJ_SUBSCRIPTION_FLAG_RES")
public class SubscriptionFlaggedResource {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "SEQ_SUBSCRIPTION_FLAG_ID", sequenceName = "SEQ_SUBSCRIPTION_FLAG_ID")
@Column(name = "PID", insertable = false, updatable = false)
private Long myId;
@ManyToOne
@JoinColumn(name="RES_ID")
private ResourceTable myResource;
@ManyToOne()
@JoinColumn(name="SUBSCRIPTION_ID")
private SubscriptionTable mySubscription;
public ResourceTable getResource() {
return myResource;
}
public SubscriptionTable getSubscription() {
return mySubscription;
}
public void setResource(ResourceTable theResource) {
myResource = theResource;
}
public void setSubscription(SubscriptionTable theSubscription) {
mySubscription = theSubscription;
}
}

View File

@ -0,0 +1,117 @@
package ca.uhn.fhir.jpa.entity;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
//@formatter:off
@Entity
@Table(name = "HFJ_SUBSCRIPTION", uniqueConstraints= {
@UniqueConstraint(name="IDX_SUBS_RESID", columnNames= { "RES_ID" }),
@UniqueConstraint(name="IDX_SUBS_NEXTCHECK", columnNames= { "SUBSCRIPTION_STATUS", "NEXT_CHECK" })
})
@NamedQueries({
@NamedQuery(name="Q_HFJ_SUBSCRIPTION_SET_STATUS", query="UPDATE SubscriptionTable t SET t.myStatus = :status WHERE t.myResId = :res_id"),
@NamedQuery(name="Q_HFJ_SUBSCRIPTION_NEXT_CHECK", query="SELECT t FROM SubscriptionTable t WHERE t.myStatus = :status AND t.myNextCheck <= :next_check"),
@NamedQuery(name="Q_HFJ_SUBSCRIPTION_GET_BY_RES", query="SELECT t FROM SubscriptionTable t WHERE t.myResId = :res_id"),
@NamedQuery(name="Q_HFJ_SUBSCRIPTION_DELETE", query="DELETE FROM SubscriptionTable t WHERE t.myResId = :res_id"),
})
//@formatter:on
public class SubscriptionTable {
@Column(name = "CHECK_INTERVAL", nullable = false)
private long myCheckInterval;
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
@SequenceGenerator(name = "SEQ_SUBSCRIPTION_ID", sequenceName = "SEQ_SUBSCRIPTION_ID")
@Column(name = "PID", insertable = false, updatable = false)
private Long myId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "NEXT_CHECK", nullable = false)
private Date myNextCheck;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "MOST_RECENT_MATCH", nullable = false)
private Date myMostRecentMatch;
@Column(name = "RES_ID", insertable = false, updatable = false)
private Long myResId;
@Column(name = "SUBSCRIPTION_STATUS", nullable = false, length = 20)
@Enumerated(EnumType.STRING)
private SubscriptionStatusEnum myStatus;
@OneToOne()
@JoinColumn(name = "RES_ID", insertable = true, updatable = false, referencedColumnName = "RES_ID", foreignKey = @ForeignKey(name = "FK_SUBSCRIPTION_RESOURCE_ID") )
private ResourceTable mySubscriptionResource;
@OneToMany(orphanRemoval=true, mappedBy="mySubscription")
private Collection<SubscriptionFlaggedResource> myFlaggedResources;
public long getCheckInterval() {
return myCheckInterval;
}
public Long getId() {
return myId;
}
public Date getNextCheck() {
return myNextCheck;
}
public SubscriptionStatusEnum getStatus() {
return myStatus;
}
public ResourceTable getSubscriptionResource() {
return mySubscriptionResource;
}
public void setCheckInterval(long theCheckInterval) {
myCheckInterval = theCheckInterval;
}
public void setNextCheck(Date theNextCheck) {
myNextCheck = theNextCheck;
}
public void setStatus(SubscriptionStatusEnum theStatus) {
myStatus = theStatus;
}
public void setSubscriptionResource(ResourceTable theSubscriptionResource) {
mySubscriptionResource = theSubscriptionResource;
}
public Date getMostRecentMatch() {
return myMostRecentMatch;
}
public void setMostRecentMatch(Date theMostRecentMatch) {
myMostRecentMatch = theMostRecentMatch;
}
}

View File

@ -24,16 +24,9 @@ import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome.Issue;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.IParserErrorHandler;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
@ -46,16 +39,13 @@ import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResourceProvider<T> {
public static final String OPERATION_NAME_META = "$meta";
public static final String OPERATION_NAME_META_DELETE = "$meta-delete";
public static final String OPERATION_NAME_META_ADD = "$meta-add";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaResourceProviderDstu2.class);
public JpaResourceProviderDstu2() {
// nothing
@ -123,6 +113,9 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
})
//@formatter:on
public Parameters metaAdd(@IdParam IdDt theId, @OperationParam(name = "meta") MetaDt theMeta) {
if (theMeta == null) {
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
}
Parameters parameters = new Parameters();
MetaDt metaAddOperation = getDao().metaAddOperation(theId, theMeta);
parameters.addParameter().setName("return").setValue(metaAddOperation);
@ -135,6 +128,9 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
})
//@formatter:on
public Parameters metaDelete(@IdParam IdDt theId, @OperationParam(name = "meta") MetaDt theMeta) {
if (theMeta == null) {
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
}
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(getDao().metaDeleteOperation(theId, theMeta));
return parameters;
@ -150,10 +146,6 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
theResource.setId(theId);
return getDao().update(theResource);
}
} catch (ResourceNotFoundException e) {
ourLog.info("Can't update resource with ID[" + theId.getValue() + "] because it doesn't exist, going to create it instead");
theResource.setId(theId);
return getDao().create(theResource);
} finally {
endRequest(theRequest);
}

View File

@ -0,0 +1,16 @@
package ca.uhn.fhir.jpa.util;
import org.hibernate.dialect.DerbyTenSevenDialect;
/**
* As of Hibernate 5.0.1, DerbyTenSevenDialect doesn't seem to work when updating
* the schema, as it tries to create a duplicate schema
*/
public class HapiDerbyTenSevenDialect extends DerbyTenSevenDialect {
@Override
public String getQuerySequencesString() {
return "select SEQUENCENAME from sys.syssequences";
}
}

View File

@ -0,0 +1,103 @@
package ca.uhn.fhir.jpa.util;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoSubscriptionDstu2;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import net.sourceforge.cobertura.CoverageIgnore;
/**
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
* {@link SubscriptionStatusEnum#REQUESTED} state and prevents clients from changing the status.
*/
public class SubscriptionsRequireManualActivationInterceptor extends InterceptorAdapter {
public static final ResourceMetadataKeyEnum<Object> ALLOW_STATUS_CHANGE = new ResourceMetadataKeyEnum<Object>(FhirResourceDaoSubscriptionDstu2.class.getName() + "_ALLOW_STATUS_CHANGE") {
private static final long serialVersionUID = 1;
@CoverageIgnore
@Override
public Object get(IResource theResource) {
throw new UnsupportedOperationException();
}
@CoverageIgnore
@Override
public void put(IResource theResource, Object theObject) {
throw new UnsupportedOperationException();
}
};
@Autowired
@Qualifier("mySubscriptionDaoDstu2")
private IFhirResourceDao<Subscription> myDao;
@Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest) {
switch (theOperation) {
case CREATE:
case UPDATE:
if (theProcessedRequest.getResourceType().equals("Subscription")) {
verifyStatusOk(theProcessedRequest);
}
default:
break;
}
}
public void setDao(IFhirResourceDao<Subscription> theDao) {
myDao = theDao;
}
private void verifyStatusOk(ActionRequestDetails theRequestDetails) {
Subscription subscription = (Subscription) theRequestDetails.getResource();
;
SubscriptionStatusEnum newStatus = subscription.getStatusElement().getValueAsEnum();
if (newStatus == SubscriptionStatusEnum.REQUESTED || newStatus == SubscriptionStatusEnum.OFF) {
return;
}
IIdType requestId = theRequestDetails.getId();
if (requestId != null && requestId.hasIdPart()) {
Subscription existing;
try {
existing = myDao.read(requestId);
SubscriptionStatusEnum existingStatus = existing.getStatusElement().getValueAsEnum();
if (existingStatus != newStatus) {
throw new UnprocessableEntityException("Subscription.status can not be changed from " + describeStatus(existingStatus) + " to " + describeStatus(newStatus));
}
} catch (ResourceNotFoundException e) {
if (newStatus != SubscriptionStatusEnum.REQUESTED) {
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatusEnum.REQUESTED.getCode() + "' on a newly created subscription");
}
}
} else {
if (newStatus != SubscriptionStatusEnum.REQUESTED) {
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatusEnum.REQUESTED.getCode() + "' on a newly created subscription");
}
}
}
private String describeStatus(SubscriptionStatusEnum existingStatus) {
String existingStatusString;
if (existingStatus != null) {
existingStatusString = '\'' + existingStatus.getCode() + '\'';
} else {
existingStatusString = "null";
}
return existingStatusString;
}
}

View File

@ -35,7 +35,7 @@
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" /> -->
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
</bean>
</property>
</bean>

View File

@ -12,13 +12,11 @@ import javax.persistence.PersistenceContext;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
@ -39,12 +37,17 @@ import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.ResourceTag;
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.ConceptMap;
import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Encounter;
import ca.uhn.fhir.model.dstu2.resource.Immunization;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Organization;
@ -53,6 +56,8 @@ import ca.uhn.fhir.model.dstu2.resource.Practitioner;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
import ca.uhn.fhir.model.dstu2.resource.StructureDefinition;
import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.resource.Substance;
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.method.MethodUtil;
@ -63,16 +68,21 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
@ContextConfiguration(locations={
"classpath:hapi-fhir-server-resourceproviders-dstu2.xml",
"classpath:fhir-jpabase-spring-test-config.xml"})
@TransactionConfiguration(defaultRollback=false)
//@formatter:on
public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@Autowired
@Qualifier("myConceptMapDaoDstu2")
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
@Autowired
protected DaoConfig myDaoConfig;
@Autowired
@Qualifier("myDeviceDaoDstu2")
protected IFhirResourceDao<Device> myDeviceDao;
@Autowired
@Qualifier("myDiagnosticOrderDaoDstu2")
protected IFhirResourceDao<DiagnosticOrder> myDiagnosticOrderDao;
@Autowired
@Qualifier("myDiagnosticReportDaoDstu2")
protected IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
@Autowired
@ -82,6 +92,9 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
protected EntityManager myEntityManager;
@Autowired
protected FhirContext myFhirCtx;
@Autowired
@Qualifier("myImmunizationDaoDstu2")
protected IFhirResourceDao<Immunization> myImmunizationDao;
protected IServerInterceptor myInterceptor;
@Autowired
@Qualifier("myLocationDaoDstu2")
@ -111,6 +124,12 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@Qualifier("myStructureDefinitionDaoDstu2")
protected IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
@Autowired
@Qualifier("mySubscriptionDaoDstu2")
protected IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
@Autowired
@Qualifier("mySubstanceDaoDstu2")
protected IFhirResourceDao<Substance> mySubstanceDao;
@Autowired
@Qualifier("mySystemDaoDstu2")
protected IFhirSystemDao<Bundle> mySystemDao;
@Autowired
@ -145,6 +164,13 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
return newJsonParser.parseResource(type, string);
}
public TransactionTemplate newTxTemplate() {
TransactionTemplate retVal = new TransactionTemplate(myTxManager);
retVal.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
retVal.afterPropertiesSet();
return retVal;
}
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
@ -159,6 +185,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d").executeUpdate();
@ -174,6 +201,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
entityManager.createQuery("DELETE from " + SubscriptionTable.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceHistoryTag.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceTag.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + TagDefinition.class.getSimpleName() + " d").executeUpdate();

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsInRelativeOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.not;
@ -24,7 +25,13 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
@ -38,19 +45,25 @@ import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.ConceptMap;
import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Encounter;
import ca.uhn.fhir.model.dstu2.resource.Immunization;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
import ca.uhn.fhir.model.dstu2.resource.Substance;
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
import ca.uhn.fhir.model.dstu2.valueset.ContactPointSystemEnum;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.param.CompositeParam;
import ca.uhn.fhir.rest.param.DateParam;
@ -58,6 +71,8 @@ import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
@ -70,6 +85,163 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
public class FhirResourceDaoDstu2SearchTest extends BaseJpaDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2SearchTest.class);
@Test
public void testIndexNoDuplicatesString() {
Patient p = new Patient();
p.addAddress().addLine("123 Fake Street");
p.addAddress().addLine("123 Fake Street");
p.addAddress().addLine("123 Fake Street");
p.addAddress().addLine("456 Fake Street");
p.addAddress().addLine("456 Fake Street");
p.addAddress().addLine("456 Fake Street");
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamString> type = ResourceIndexedSearchParamString.class;
List<ResourceIndexedSearchParamString> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myPatientDao.search(Patient.SP_ADDRESS, new StringParam("123 Fake Street")));
assertThat(actual, contains(id));
}
@Test
public void testIndexNoDuplicatesDate() {
DiagnosticOrder order = new DiagnosticOrder();
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-11T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-11T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-11T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-12T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-12T11:12:12Z"));
order.addItem().addEvent().setDateTime(new DateTimeDt("2011-12-12T11:12:12Z"));
IIdType id = myDiagnosticOrderDao.create(order).getId().toUnqualifiedVersionless();
List<IIdType> actual = toUnqualifiedVersionlessIds(myDiagnosticOrderDao.search(DiagnosticOrder.SP_ITEM_DATE, new DateParam("2011-12-12T11:12:12Z")));
assertThat(actual, contains(id));
Class<ResourceIndexedSearchParamDate> type = ResourceIndexedSearchParamDate.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
}
@Test
public void testIndexNoDuplicatesNumber() {
Immunization res = new Immunization();
res.addVaccinationProtocol().setDoseSequence(1);
res.addVaccinationProtocol().setDoseSequence(1);
res.addVaccinationProtocol().setDoseSequence(1);
res.addVaccinationProtocol().setDoseSequence(2);
res.addVaccinationProtocol().setDoseSequence(2);
res.addVaccinationProtocol().setDoseSequence(2);
IIdType id = myImmunizationDao.create(res).getId().toUnqualifiedVersionless();
List<IIdType> actual = toUnqualifiedVersionlessIds(myImmunizationDao.search(Immunization.SP_DOSE_SEQUENCE, new NumberParam("1")));
assertThat(actual, contains(id));
Class<ResourceIndexedSearchParamNumber> type = ResourceIndexedSearchParamNumber.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
}
@Test
public void testIndexNoDuplicatesUri() {
ConceptMap res = new ConceptMap();
res.addElement().addTarget().addDependsOn().setElement("http://foo");
res.addElement().addTarget().addDependsOn().setElement("http://foo");
res.addElement().addTarget().addDependsOn().setElement("http://bar");
res.addElement().addTarget().addDependsOn().setElement("http://bar");
IIdType id = myConceptMapDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myConceptMapDao.search(ConceptMap.SP_DEPENDSON, new UriParam("http://foo")));
assertThat(actual, contains(id));
}
@Test
public void testIndexNoDuplicatesQuantity() {
Substance res = new Substance();
res.addInstance().getQuantity().setSystem("http://foo").setCode("UNIT").setValue(123);
res.addInstance().getQuantity().setSystem("http://foo").setCode("UNIT").setValue(123);
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
res.addInstance().getQuantity().setSystem("http://foo2").setCode("UNIT2").setValue(1232);
IIdType id = mySubstanceDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamQuantity> type = ResourceIndexedSearchParamQuantity.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(mySubstanceDao.search(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT")));
assertThat(actual, contains(id));
}
@Test
public void testIndexNoDuplicatesToken() {
Patient res = new Patient();
res.addIdentifier().setSystem("http://foo1").setValue("123");
res.addIdentifier().setSystem("http://foo1").setValue("123");
res.addIdentifier().setSystem("http://foo2").setValue("1234");
res.addIdentifier().setSystem("http://foo2").setValue("1234");
IIdType id = myPatientDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceIndexedSearchParamToken> type = ResourceIndexedSearchParamToken.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("http://foo1", "123")));
assertThat(actual, contains(id));
}
@Test
public void testIndexNoDuplicatesReference() {
Practitioner pract =new Practitioner();
pract.setId("Practitioner/somepract");
pract.getName().addFamily("SOME PRACT");
myPractitionerDao.update(pract);
Practitioner pract2 =new Practitioner();
pract2.setId("Practitioner/somepract2");
pract2.getName().addFamily("SOME PRACT2");
myPractitionerDao.update(pract2);
DiagnosticOrder res = new DiagnosticOrder();
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract"));
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract"));
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract2"));
res.addEvent().setActor(new ResourceReferenceDt("Practitioner/somepract2"));
IIdType id = myDiagnosticOrderDao.create(res).getId().toUnqualifiedVersionless();
Class<ResourceLink> type = ResourceLink.class;
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
ourLog.info(toStringMultiline(results));
assertEquals(2, results.size());
List<IIdType> actual = toUnqualifiedVersionlessIds(myDiagnosticOrderDao.search(DiagnosticOrder.SP_ACTOR, new ReferenceParam("Practitioner/somepract")));
assertThat(actual, contains(id));
}
private String toStringMultiline(List<?> theResults) {
StringBuilder b = new StringBuilder();
for (Object next : theResults) {
b.append('\n');
b.append(" * ").append(next.toString());
}
return b.toString();
}
@Test
public void testSearchAll() {
{
@ -130,6 +302,151 @@ public class FhirResourceDaoDstu2SearchTest extends BaseJpaDstu2Test {
}
/**
* #222
*/
@Test
public void testSearchForDeleted() {
{
Patient patient = new Patient();
patient.setId("TEST");
patient.setLanguage(new CodeDt("TEST"));
patient.addName().addFamily("TEST");
patient.addIdentifier().setSystem("TEST").setValue("TEST");
myPatientDao.update(patient);
}
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
params.put("_id", new StringDt("TEST"));
assertEquals(1, toList(myPatientDao.search(params)).size());
params.put("_language", new StringParam("TEST"));
assertEquals(1, toList(myPatientDao.search(params)).size());
params.put(Patient.SP_IDENTIFIER, new TokenParam("TEST", "TEST"));
assertEquals(1, toList(myPatientDao.search(params)).size());
params.put(Patient.SP_NAME, new StringParam("TEST"));
assertEquals(1, toList(myPatientDao.search(params)).size());
myPatientDao.delete(new IdDt("Patient/TEST"));
params = new HashMap<String, IQueryParameterType>();
params.put("_id", new StringDt("TEST"));
assertEquals(0, toList(myPatientDao.search(params)).size());
params.put("_language", new StringParam("TEST"));
assertEquals(0, toList(myPatientDao.search(params)).size());
params.put(Patient.SP_IDENTIFIER, new TokenParam("TEST", "TEST"));
assertEquals(0, toList(myPatientDao.search(params)).size());
params.put(Patient.SP_NAME, new StringParam("TEST"));
assertEquals(0, toList(myPatientDao.search(params)).size());
}
@Test
public void testSearchByIdParamWrongType() {
IIdType id1;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Organization patient = new Organization();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id2 = myOrganizationDao.create(patient).getId().toUnqualifiedVersionless();
}
SearchParameterMap params = new SearchParameterMap();
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id2.getIdPart())));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
@Test
public void testSearchByIdParamOr() {
IIdType id1;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
SearchParameterMap params = new SearchParameterMap();
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id2.getIdPart())));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1, id2));
params = new SearchParameterMap();
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id1.getIdPart())));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
params = new SearchParameterMap();
params.add("_id", new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam("999999999999")));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
@Test
public void testSearchByIdParamAnd() {
IIdType id1;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
SearchParameterMap params;
StringAndListParam param;
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam(id1.getIdPart())).addOr(new StringParam(id2.getIdPart())));
param.addAnd(new StringOrListParam().addOr(new StringParam(id1.getIdPart())));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam(id2.getIdPart())));
param.addAnd(new StringOrListParam().addOr(new StringParam(id1.getIdPart())));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam(id2.getIdPart())));
param.addAnd(new StringOrListParam().addOr(new StringParam("9999999999999")));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
params = new SearchParameterMap();
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("9999999999999")));
param.addAnd(new StringOrListParam().addOr(new StringParam(id2.getIdPart())));
params.add("_id", param);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
}
@Test
public void testSearchCompositeParam() {
Observation o1 = new Observation();
@ -201,7 +518,6 @@ public class FhirResourceDaoDstu2SearchTest extends BaseJpaDstu2Test {
assertEquals(0, retrieved.size());
}
}
@Test
public void testSearchLanguageParam() {
IIdType id1;
@ -240,9 +556,155 @@ public class FhirResourceDaoDstu2SearchTest extends BaseJpaDstu2Test {
List<Patient> patients = toList(myPatientDao.search(params));
assertEquals(0, patients.size());
}
}
@Test
public void testSearchLanguageParamAndOr() {
IIdType id1;
{
Patient patient = new Patient();
patient.getLanguage().setValue("en_CA");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("testSearchLanguageParam").addGiven("Joe");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Patient patient = new Patient();
patient.getLanguage().setValue("en_US");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("testSearchLanguageParam").addGiven("John");
id2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
{
SearchParameterMap params = new SearchParameterMap();
params.add(Patient.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("en_US")));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1, id2));
}
{
SearchParameterMap params = new SearchParameterMap();
params.add(Patient.SP_RES_LANGUAGE, new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
SearchParameterMap params = new SearchParameterMap();
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")));
params.add(Patient.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
SearchParameterMap params = new SearchParameterMap();
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ")));
params.add(Patient.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
}
{
SearchParameterMap params = new SearchParameterMap();
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("ZZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
params.add(Patient.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), empty());
}
{
SearchParameterMap params = new SearchParameterMap();
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null)));
params.add(Patient.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
SearchParameterMap params = new SearchParameterMap();
params.add("_id", new StringParam(id1.getIdPart()));
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null)));
params.add(Patient.SP_RES_LANGUAGE, and);
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
{
SearchParameterMap params = new SearchParameterMap();
StringAndListParam and = new StringAndListParam();
and.addAnd(new StringOrListParam().addOr(new StringParam("en_CA")).addOr(new StringParam("ZZZZ")));
and.addAnd(new StringOrListParam().addOr(new StringParam("")).addOr(new StringParam(null)));
params.add(Patient.SP_RES_LANGUAGE, and);
params.add("_id", new StringParam(id1.getIdPart()));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(params)), containsInAnyOrder(id1));
}
}
@Test
public void testSearchLastUpdatedParamWithComparator() throws InterruptedException {
String methodName = "testSearchLastUpdatedParamWithComparator";
IIdType id0;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id0 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
int sleep = 100;
long start = System.currentTimeMillis();
Thread.sleep(sleep);
DateTimeDt beforeAny = new DateTimeDt(new Date(), TemporalPrecisionEnum.MILLI);
IIdType id1a;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1a = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id1b;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1b = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
ourLog.info("Res 1: {}", ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id0)).getValueAsString());
ourLog.info("Res 2: {}", ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id1a)).getValueAsString());
InstantDt id1bpublished = ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id1b));
ourLog.info("Res 3: {}", id1bpublished.getValueAsString());
Thread.sleep(sleep);
long end = System.currentTimeMillis();
SearchParameterMap map;
Date startDate = new Date(start);
Date endDate = new Date(end);
DateTimeDt startDateTime = new DateTimeDt(startDate, TemporalPrecisionEnum.MILLI);
DateTimeDt endDateTime = new DateTimeDt(endDate, TemporalPrecisionEnum.MILLI);
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(startDateTime, endDateTime));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, startDateTime), new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN, startDateTime), new DateParam(QuantityCompararatorEnum.LESSTHAN, endDateTime)));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a, id1b));
map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam(new DateParam(QuantityCompararatorEnum.GREATERTHAN, startDateTime.getValue()), new DateParam(QuantityCompararatorEnum.LESSTHAN, id1bpublished.getValue())));
ourLog.info("Searching: {}", map.getLastUpdated());
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a));
}
@Test
public void testSearchLastUpdatedParam() throws InterruptedException {
String methodName = "testSearchLastUpdatedParam";

View File

@ -0,0 +1,174 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Set;
import javax.persistence.TypedQuery;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Before;
import org.junit.Test;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.valueset.ObservationStatusEnum;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class FhirResourceDaoDstu2SubscriptionTest extends BaseJpaDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2SubscriptionTest.class);
@Test
public void testCreateSubscriptionInvalidCriteria() {
Subscription subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("http://foo.com/Observation?AAA=BBB");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("ObservationZZZZ?a=b");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.criteria contains invalid/unsupported resource type: ObservationZZZZ"));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation?identifier=123");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.channel.type must be populated on this server"));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation?identifier=123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
assertTrue(mySubscriptionDao.create(subs).getId().hasIdPart());
}
@Before
public void beforeEnableSubscription() {
myDaoConfig.setSubscriptionEnabled(true);
}
@Test
public void testSubscriptionResourcesAppear() throws Exception {
myDaoConfig.setSubscriptionPollDelay(0);
String methodName = "testSubscriptionResourcesAppear";
Patient p = new Patient();
p.addName().addFamily(methodName);
IIdType pId = myPatientDao.create(p).getId().toUnqualifiedVersionless();
Observation obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
IIdType beforeId = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Subscription subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
Thread.sleep(100);
ourLog.info("Before: {}", System.currentTimeMillis());
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
IIdType afterId1 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
IIdType afterId2 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Thread.sleep(100);
ourLog.info("After: {}", System.currentTimeMillis());
mySubscriptionDao.pollForNewUndeliveredResources();
}
@Test
public void testCreateSubscription() {
Subscription subs = new Subscription();
subs.setCriteria("Observation?subject=Patient/123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
TypedQuery<SubscriptionTable> q = myEntityManager.createQuery("SELECT t from SubscriptionTable t WHERE t.mySubscriptionResource.myId = :id", SubscriptionTable.class);
q.setParameter("id", id.getIdPartAsLong());
final SubscriptionTable table = q.getSingleResult();
assertNotNull(table);
assertNotNull(table.getNextCheck());
assertEquals(table.getNextCheck(), table.getSubscriptionResource().getPublished().getValue());
assertEquals(SubscriptionStatusEnum.REQUESTED, myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
mySubscriptionDao.update(subs);
assertEquals(SubscriptionStatusEnum.ACTIVE, myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.ACTIVE, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
mySubscriptionDao.delete(id);
assertNull(myEntityManager.find(SubscriptionTable.class, table.getId()));
/*
* Re-create again
*/
subs = new Subscription();
subs.setCriteria("Observation?subject=Patient/123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setId(id);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
mySubscriptionDao.update(subs);
assertEquals(SubscriptionStatusEnum.REQUESTED, myEntityManager.createQuery("SELECT t FROM SubscriptionTable t WHERE t.myResId = " + id.getIdPart(), SubscriptionTable.class).getSingleResult().getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
}
}

View File

@ -77,6 +77,7 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortOrderEnum;
@ -966,8 +967,13 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals(id.withVersion("1"), entries.get(2).getIdElement());
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(0)));
assertEquals(BundleEntryTransactionMethodEnum.PUT, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(0)));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(1)));
assertEquals(BundleEntryTransactionMethodEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(1)));
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get((IResource) entries.get(2)));
assertEquals(BundleEntryTransactionMethodEnum.POST, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) entries.get(2)));
}
@Test

View File

@ -0,0 +1,126 @@
package ca.uhn.fhir.jpa.provider;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
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.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import ca.uhn.fhir.jpa.dao.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
public abstract class BaseResourceProviderDstu2Test extends BaseJpaDstu2Test {
protected static IGenericClient ourClient;
protected static CloseableHttpClient ourHttpClient;
protected static int ourPort;
private static Server ourServer;
protected static String ourServerBase;
public BaseResourceProviderDstu2Test() {
super();
}
protected List<IdDt> toIdListUnqualifiedVersionless(Bundle found) {
List<IdDt> list = new ArrayList<IdDt>();
for (BundleEntry next : found.getEntries()) {
list.add(next.getResource().getId().toUnqualifiedVersionless());
}
return list;
}
protected List<String> toNameList(Bundle resp) {
List<String> names = new ArrayList<String>();
for (BundleEntry next : resp.getEntries()) {
Patient nextPt = (Patient) next.getResource();
String nextStr = nextPt.getNameFirstRep().getGivenAsSingleString() + " " + nextPt.getNameFirstRep().getFamilyAsSingleString();
if (isNotBlank(nextStr)) {
names.add(nextStr);
}
}
return names;
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
ourHttpClient.close();
ourServer = null;
ourHttpClient = null;
}
@After
public void after() {
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Before
public void before() throws Exception {
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
if (ourServer == null) {
ourPort = RandomServerPortProvider.findFreePort();
RestfulServer restServer = new RestfulServer(myFhirCtx);
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
restServer.setResourceProviders((List)myResourceProviders);
restServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
restServer.setPlainProviders(mySystemProvider);
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(restServer, mySystemDao);
confProvider.setImplementationDescription("THIS IS THE DESC");
restServer.setServerConformanceProvider(confProvider);
restServer.setPagingProvider(new FifoMemoryPagingProvider(10));
Server server = new Server(ourPort);
ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/");
ServletHolder servletHolder = new ServletHolder();
servletHolder.setServlet(restServer);
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
server.setHandler(proxyHandler);
server.start();
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor(true));
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourHttpClient = builder.build();
ourServer = server;
}
}
}

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.provider;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsInRelativeOrder;
@ -29,7 +28,6 @@ import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@ -41,23 +39,11 @@ import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
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.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.jpa.dao.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
@ -95,27 +81,18 @@ import ca.uhn.fhir.model.primitive.UnsignedIntDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class ResourceProviderDstu2Test extends BaseJpaDstu2Test {
public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
private static IGenericClient ourClient;
private static CloseableHttpClient ourHttpClient;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderDstu2Test.class);
private static int ourPort;
private static Server ourServer;
private static String ourServerBase;
// private static JpaConformanceProvider ourConfProvider;
@ -151,6 +128,33 @@ public class ResourceProviderDstu2Test extends BaseJpaDstu2Test {
// }
// }
@Test
public void testSearchByIdOr() {
IIdType id1;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
IIdType id2;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
id2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
//@formatter:off
Bundle found = ourClient
.search()
.forResource(Patient.class)
.where(Patient.RES_ID.matches().values(id1.getIdPart(), id2.getIdPart()))
.and(Patient.RES_ID.matches().value(id1.getIdPart()))
.execute();
//@formatter:on
assertThat(toIdListUnqualifiedVersionless(found), containsInAnyOrder(id1));
}
@Test
public void testBundleCreate() throws Exception {
IGenericClient client = ourClient;
@ -202,6 +206,19 @@ public class ResourceProviderDstu2Test extends BaseJpaDstu2Test {
}
@Test
public void testCreateWithForcedId() throws IOException {
String methodName = "testCreateWithForcedId";
Patient p = new Patient();
p.addName().addFamily(methodName);
p.setId(methodName);
IIdType optId = ourClient.update().resource(p).execute().getId();
assertEquals(methodName, optId.getIdPart());
assertEquals("1", optId.getVersionIdPart());
}
@Test
public void testCreateQuestionnaireResponseWithValidation() throws IOException {
ValueSet options = new ValueSet();
@ -730,6 +747,50 @@ public class ResourceProviderDstu2Test extends BaseJpaDstu2Test {
}
}
@Test
public void testMetaOperationWithNoMetaParameter() throws Exception {
Patient p = new Patient();
p.addName().addFamily("testMetaAddInvalid");
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
//@formatter:off
String input = "<Parameters>\n" +
" <meta>\n" +
" <tag>\n" +
" <system value=\"http://example.org/codes/tags\"/>\n" +
" <code value=\"record-lost\"/>\n" +
" <display value=\"Patient File Lost\"/>\n" +
" </tag>\n" +
" </meta>\n" +
"</Parameters>";
//@formatter:on
HttpPost post = new HttpPost(ourServerBase + "/Patient/" + id.getIdPart() + "/$meta-add");
post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
CloseableHttpResponse response = ourHttpClient.execute(post);
try {
String output = IOUtils.toString(response.getEntity().getContent());
ourLog.info(output);
assertEquals(400, response.getStatusLine().getStatusCode());
assertThat(output, containsString("Input contains no parameter with name 'meta'"));
} finally {
response.close();
}
post = new HttpPost(ourServerBase + "/Patient/" + id.getIdPart() + "/$meta-delete");
post.setEntity(new StringEntity(input, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
response = ourHttpClient.execute(post);
try {
String output = IOUtils.toString(response.getEntity().getContent());
ourLog.info(output);
assertEquals(400, response.getStatusLine().getStatusCode());
assertThat(output, containsString("Input contains no parameter with name 'meta'"));
} finally {
response.close();
}
}
@Test
public void testMetaOperations() throws Exception {
String methodName = "testMetaOperations";
@ -1635,84 +1696,4 @@ public class ResourceProviderDstu2Test extends BaseJpaDstu2Test {
}
private List<IdDt> toIdListUnqualifiedVersionless(Bundle found) {
List<IdDt> list = new ArrayList<IdDt>();
for (BundleEntry next : found.getEntries()) {
list.add(next.getResource().getId().toUnqualifiedVersionless());
}
return list;
}
private List<String> toNameList(Bundle resp) {
List<String> names = new ArrayList<String>();
for (BundleEntry next : resp.getEntries()) {
Patient nextPt = (Patient) next.getResource();
String nextStr = nextPt.getNameFirstRep().getGivenAsSingleString() + " " + nextPt.getNameFirstRep().getFamilyAsSingleString();
if (isNotBlank(nextStr)) {
names.add(nextStr);
}
}
return names;
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
ourHttpClient.close();
}
@After
public void after() {
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@Before
public void before() throws Exception {
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
if (ourServer == null) {
ourPort = RandomServerPortProvider.findFreePort();
RestfulServer restServer = new RestfulServer(myFhirCtx);
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
restServer.setResourceProviders((List)myResourceProviders);
restServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
restServer.setPlainProviders(mySystemProvider);
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(restServer, mySystemDao);
confProvider.setImplementationDescription("THIS IS THE DESC");
restServer.setServerConformanceProvider(confProvider);
restServer.setPagingProvider(new FifoMemoryPagingProvider(10));
Server server = new Server(ourPort);
ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/");
ServletHolder servletHolder = new ServletHolder();
servletHolder.setServlet(restServer);
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
server.setHandler(proxyHandler);
server.start();
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor(true));
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourHttpClient = builder.build();
ourServer = server;
}
}
}

View File

@ -0,0 +1,101 @@
package ca.uhn.fhir.jpa.provider;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor;
import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class SubscriptionsRequireManualActivationInterceptorTest extends BaseResourceProviderDstu2Test {
@Test
public void testCreateInvalidNoStatus() {
Subscription subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?identifier=123");
try {
ourClient.create().resource(subs).execute();
fail();
} catch (UnprocessableEntityException e) {
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status must be 'requested' on a newly created subscription", e.getMessage());
}
subs.setId("ABC");
try {
ourClient.update().resource(subs).execute();
fail();
} catch (UnprocessableEntityException e) {
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status must be 'requested' on a newly created subscription", e.getMessage());
}
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
ourClient.update().resource(subs).execute();
}
@Test
public void testCreateInvalidWrongStatus() {
Subscription subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
subs.setCriteria("Observation?identifier=123");
try {
ourClient.create().resource(subs).execute();
fail();
} catch (UnprocessableEntityException e) {
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status must be 'requested' on a newly created subscription", e.getMessage());
}
subs.setId("ABC");
try {
ourClient.update().resource(subs).execute();
fail();
} catch (UnprocessableEntityException e) {
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status must be 'requested' on a newly created subscription", e.getMessage());
}
}
@Test
public void testUpdateFails() {
Subscription subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation?identifier=123");
IIdType id = ourClient.create().resource(subs).execute().getId().toUnqualifiedVersionless();
subs.setId(id);
try {
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
ourClient.update().resource(subs).execute();
fail();
} catch (UnprocessableEntityException e) {
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status can not be changed from 'requested' to 'active'", e.getMessage());
}
try {
subs.setStatus((SubscriptionStatusEnum) null);
ourClient.update().resource(subs).execute();
fail();
} catch (UnprocessableEntityException e) {
assertEquals("HTTP 422 Unprocessable Entity: Subscription.status can not be changed from 'requested' to null", e.getMessage());
}
subs.setStatus(SubscriptionStatusEnum.OFF);
}
@Override
public void beforeCreateInterceptor() {
super.beforeCreateInterceptor();
SubscriptionsRequireManualActivationInterceptor interceptor = new SubscriptionsRequireManualActivationInterceptor();
interceptor.setDao(mySubscriptionDao);
myDaoConfig.getInterceptors().add(interceptor);
}
}

View File

@ -21,16 +21,13 @@
<class>ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords</class>
<class>ca.uhn.fhir.jpa.entity.ResourceLink</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTag</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionTable</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource</class>
<class>ca.uhn.fhir.jpa.entity.TagDefinition</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.connection.password" value="" />
<property name="hibernate.jdbc.batch_size" value="0" />
<property name="hibernate.cache.use_minimal_puts" value="false" />
<property name="hibernate.cache.use_query_cache" value="false" />

View File

@ -33,7 +33,7 @@
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" /> -->
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
</bean>
</property>
</bean>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -31,33 +31,33 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- At least one "structures" JAR must also be included -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- This dependency includes the JPA server itself, which is packaged separately from the rest of HAPI FHIR -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<type>war</type>
<scope>provided</scope>
</dependency>

View File

@ -20,6 +20,8 @@
<class>ca.uhn.fhir.jpa.entity.ResourceLink</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTable</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTag</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionTable</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource</class>
<class>ca.uhn.fhir.jpa.entity.TagDefinition</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>

View File

@ -21,7 +21,7 @@
and other properties supported by BasicDataSource.
-->
<bean id="myPersistenceDataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="url" value="jdbc:derby:directory:jpaserver_derby_files;create=true" />
<property name="url" value="jdbc:derby:directory:target/jpaserver_derby_files;create=true" />
<property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver"></property>
<property name="username" value=""/>
<property name="password" value=""/>
@ -40,7 +40,7 @@
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
</bean>
</property>
</bean>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -18,27 +18,27 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<type>war</type>
<scope>provided</scope>
</dependency>
@ -52,13 +52,6 @@
<artifactId>phloc-commons</artifactId>
</dependency>
<!--dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test</artifactId>
<version>0.9-SNAPSHOT</version>
<scope>test</scope>
</dependency-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>

View File

@ -20,11 +20,13 @@
<class>ca.uhn.fhir.jpa.entity.ResourceLink</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTable</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTag</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionTable</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource</class>
<class>ca.uhn.fhir.jpa.entity.TagDefinition</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="hibernate.dialect" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.jdbc.batch_size" value="20" />
<property name="hibernate.cache.use_minimal_puts" value="true" />

View File

@ -44,7 +44,7 @@
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" />-->
<!-- <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> -->
</bean>

View File

@ -31,7 +31,7 @@
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" /> -->
<!-- <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> -->
</bean>

View File

@ -18,6 +18,7 @@
<util:list id="myServerInterceptors">
<ref bean="myLoggingInterceptor"/>
<ref bean="mySubscriptionSecurityInterceptor"/>
</util:list>
<!--
@ -42,6 +43,8 @@
<bean id="dbServer" class="ca.uhn.fhirtest.DerbyNetworkServer">
</bean>
<bean id="mySubscriptionSecurityInterceptor" class="ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor"/>
<!--
Do some fancy logging to create a nice access log that has details

View File

@ -42,7 +42,7 @@
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
</bean>
</property>
</bean>

View File

@ -16,12 +16,14 @@
<class>ca.uhn.fhir.jpa.entity.ResourceLink</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTable</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTag</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionTable</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="hibernate.dialect" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.connection.password" value="" />

View File

@ -1,31 +1,76 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2-SNAPSHOT</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-osgi-core</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<url>http://jamesagnew.github.io/hapi-fhir/</url>
<name>HAPI FHIR - OSGi Bundle</name>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2-SNAPSHOT</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.3-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Export-Package>ca.uhn.fhir</Export-Package>
<Export-Package>org.hl7.fhir</Export-Package>
<Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
<Embed-Dependency>*;scope=!provided|test</Embed-Dependency>
<Embed-Directory>lib</Embed-Directory>
<Embed-Transitive>true</Embed-Transitive>
<_removeheaders>Built-By</_removeheaders>
<!-- <Private-Package>org.foo.myproject.*</Private-Package> <Bundle-Activator>org.foo.myproject.impl1.Activator</Bundle-Activator> -->
</instructions>
</configuration>
<executions>
<execution>
<goals>
<goal>bundle</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -17,7 +17,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
@ -136,7 +136,7 @@
<plugin>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<executions>
<execution>
<goals>

View File

@ -10,12 +10,16 @@ import java.util.List;
import org.junit.Test;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DateRangeParamTest {
private static SimpleDateFormat ourFmt;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DateRangeParamTest.class);
static {
ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS");
@ -25,6 +29,31 @@ public class DateRangeParamTest {
return new DateRangeParam(new DateParam(theString));
}
@Test
public void testRange() {
InstantDt start = new InstantDt("2015-09-23T07:43:34.811-04:00");
InstantDt end = new InstantDt("2015-09-23T07:43:34.899-04:00");
DateParam lowerBound = new DateParam(QuantityCompararatorEnum.GREATERTHAN, start.getValue());
DateParam upperBound = new DateParam(QuantityCompararatorEnum.LESSTHAN, end.getValue());
assertEquals(QuantityCompararatorEnum.GREATERTHAN, lowerBound.getComparator());
assertEquals(QuantityCompararatorEnum.LESSTHAN, upperBound.getComparator());
/*
* When DateParam (which extends DateTimeDt) gets passed in, make sure we preserve the
* comparators..
*/
DateRangeParam param = new DateRangeParam(lowerBound, upperBound);
ourLog.info(param.toString());
assertEquals(QuantityCompararatorEnum.GREATERTHAN, param.getLowerBound().getComparator());
assertEquals(QuantityCompararatorEnum.LESSTHAN, param.getUpperBound().getComparator());
param = new DateRangeParam(new DateTimeDt(lowerBound.getValue()), new DateTimeDt(upperBound.getValue()));
ourLog.info(param.toString());
assertEquals(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, param.getLowerBound().getComparator());
assertEquals(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, param.getUpperBound().getComparator());
}
@Test
public void testAddAnd() {
assertEquals(1, new DateAndListParam().addAnd(new DateOrListParam()).getValuesAsQueryTokens().size());

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -17,13 +17,13 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<scope>test</scope>
</dependency>
@ -144,7 +144,7 @@
<plugin>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<executions>
<execution>
<id>generate</id>

View File

@ -28,6 +28,7 @@ import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Binary;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Medication;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
@ -474,17 +475,6 @@ public class JsonParserDstu2Test {
assertThat(ourCtx.newJsonParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
}
@Test
public void testParseAndEncodeBundleResourceWithComments() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-transaction2.json"));
ourCtx.newJsonParser().parseBundle(content);
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
// TODO: preserve comments
}
@Test
public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-example.json"));
@ -527,7 +517,7 @@ public class JsonParserDstu2Test {
assertEquals(exp, act);
}
/**
* Test for #146
*/
@ -641,6 +631,17 @@ public class JsonParserDstu2Test {
}
@Test
public void testParseAndEncodeBundleResourceWithComments() throws Exception {
String content = IOUtils.toString(JsonParserDstu2Test.class.getResourceAsStream("/bundle-transaction2.json"));
ourCtx.newJsonParser().parseBundle(content);
ca.uhn.fhir.model.dstu2.resource.Bundle parsed = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, content);
// TODO: preserve comments
}
@Test
public void testParseAndEncodeBundleWithDeletedEntry() {
@ -856,7 +857,7 @@ public class JsonParserDstu2Test {
assertEquals(exp, act);
}
@Test
public void testParsePatientInBundle() {
@ -917,6 +918,17 @@ public class JsonParserDstu2Test {
}
}
@Test
public void testParseWithWrongTypeObjectShouldBeArray() throws Exception {
String input = IOUtils.toString(getClass().getResourceAsStream("/invalid_metadata.json"));
try {
ourCtx.newJsonParser().parseResource(Conformance.class, input);
fail();
} catch (DataFormatException e) {
assertEquals("Syntax error parsing JSON FHIR structure: Expected ARRAY at element 'modifierExtension', found 'OBJECT'", e.getMessage());
}
}
/**
* See #144 and #146
*/

View File

@ -51,11 +51,13 @@ public class SearchDstu2Test {
private static Server ourServer;
private static String ourLastMethod;
private static DateAndListParam ourLastDateAndList;
private static ReferenceParam ourLastRef;
@Before
public void before() {
ourLastMethod = null;
ourLastDateAndList = null;
ourLastRef = null;
}
@Test
@ -68,6 +70,59 @@ public class SearchDstu2Test {
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchReferenceParams01() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchNoList&ref=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals(null, ourLastRef.getResourceType());
}
@Test
public void testSearchReferenceParams02() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchNoList&ref=Patient/123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals("Patient", ourLastRef.getResourceType());
}
@Test
public void testSearchReferenceParams03() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchNoList&ref:Patient=Patient/123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals("Patient", ourLastRef.getResourceType());
}
@Test
public void testSearchReferenceParams04() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchNoList&ref:Patient=123");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertEquals("123", ourLastRef.getIdPart());
assertEquals("Patient", ourLastRef.getResourceType());
}
@Test
public void testSearchDateAndList() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?searchDateAndList=2001,2002&searchDateAndList=2003,2004");
@ -220,7 +275,17 @@ public class SearchDstu2Test {
return Collections.emptyList();
}
//@formatter:on
//@formatter:off
@Search(queryName="searchNoList")
public List<Patient> searchNoList(
@RequiredParam(name = "ref") ReferenceParam theParam) {
ourLastMethod = "searchNoList";
ourLastRef = theParam;
return Collections.emptyList();
}
//@formatter:on
//@formatter:off
@Search()
public List<Patient> searchDateAndList(

View File

@ -0,0 +1,65 @@
{
"resourceType": "Conformance",
"meta": {
"versionId": "0.0.1"
},
"status": "draft",
"experimental": true,
"date": "2015-09-23T12:00:00Z",
"fhirVersion": "DSTU 2 0.5.0",
"acceptUnknown": false,
"format": [
"json"
],
"rest": [
{
"mode": "server",
"documentation": "Information about the system's restful capabilities that apply across all applications, such as security",
"security": {
"cors": false,
"service": [
{
"coding": [
{
"system": "http://hl7.org/fhir/restful-security-service",
"code": "OAuth"
}
]
}
],
"description": "General description of how security works",
"certificate": [
{
"type": "json"
}
],
"modifierExtension": {
"url": "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"
},
"extension": {
"url": "http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris"
}
},
"resource": [
{
"type": "Patient",
"profile": {
"reference": "http://hl7.org/fhir/StructureDefinition/patient-daf-dafpatient"
},
"interaction": [
{
"code": "read"
},
{
"code": "update"
},
{
"code": "search-type"
}
],
"versioning": "no-version"
}
]
}
]
}

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
@ -18,12 +18,12 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -27,22 +27,22 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!--<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
@ -66,13 +66,6 @@
<scope>provided</scope>
</dependency>
<!-- <dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-test</artifactId>
<version>0.9-SNAPSHOT</version>
<scope>test</scope>
</dependency>-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
@ -111,12 +104,10 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring_version}</version>
<exclusions>
<exclusion>
<artifactId>xml-apis</artifactId>
@ -127,53 +118,44 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@ -21,13 +21,15 @@
<class>ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords</class>
<class>ca.uhn.fhir.jpa.entity.ResourceLink</class>
<class>ca.uhn.fhir.jpa.entity.ResourceTag</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionTable</class>
<class>ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource</class>
<class>ca.uhn.fhir.jpa.entity.TagDefinition</class>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="hibernate.connection.url" value="jdbc:hsqldb:mem:unit-testing-jpa" />
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver" />
<property name="hibernate.dialect" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="hibernate.dialect" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.connection.username" value="sa" />
<property name="hibernate.connection.password" value="" />

View File

@ -38,7 +38,7 @@
<property name="showSql" value="false" />
<property name="generateDdl" value="true" />
<!-- <property name="databasePlatform" value="org.hibernate.dialect.HSQLDialect" /> -->
<property name="databasePlatform" value="org.hibernate.dialect.DerbyTenSevenDialect" />
<property name="databasePlatform" value="ca.uhn.fhir.jpa.util.HapiDerbyTenSevenDialect" />
</bean>
</property>
</bean>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -19,7 +19,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!--
Because Tinder is a part of the HAPI FHIR build process (it generates

View File

@ -44,11 +44,11 @@ public class ${className}ResourceProvider extends
@Description(shortDefinition="The resource identity")
@OptionalParam(name="_id")
StringParam theId,
StringAndListParam theId,
@Description(shortDefinition="The resource language")
@OptionalParam(name="_language")
StringParam theResourceLanguage,
StringAndListParam theResourceLanguage,
@Description(shortDefinition="Search for resources which have the given tag")
@OptionalParam(name=ca.uhn.fhir.rest.server.Constants.PARAM_TAG)

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
default-autowire="no" default-lazy-init="false"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
@ -8,6 +9,7 @@
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
"
>
@ -21,6 +23,12 @@
</bean>
#if ( ${versionCapitalized} == 'Dstu2' )
<jpa:repositories base-package="ca.uhn.fhir.jpa.dao.data" />
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
<bean id="myJpaValidationSupport${versionCapitalized}" class="ca.uhn.fhir.jpa.dao.JpaValidationSupport${versionCapitalized}"/>
#end
@ -33,7 +41,7 @@
#foreach ( $res in $resources )
<bean id="my${res.name}Dao${versionCapitalized}"
## Some resource types have customized DAOs for resource specific functionality
#if ( ${versionCapitalized} == 'Dstu2' && ( ${res.name} == 'Bundle' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'ValueSet'))
#if ( ${versionCapitalized} == 'Dstu2' && ( ${res.name} == 'Bundle' || ${res.name} == 'Subscription' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'ValueSet'))
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${res.name}${versionCapitalized}">
#else
class="ca.uhn.fhir.jpa.dao.FhirResourceDao${versionCapitalized}">

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -17,12 +17,12 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
@ -45,7 +45,7 @@
<plugin>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<executions>
<execution>
<id>custom-structs</id>
@ -104,7 +104,7 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>

45
pom.xml
View File

@ -11,7 +11,7 @@
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<url>http://jamesagnew.github.io/hapi-fhir/</url>
@ -214,15 +214,13 @@
<derby_version>10.11.1.1</derby_version>
<!-- Note on Hibernate versions: Hibernate 4.3+ uses JPA 2.1, which is too new for a number of platforms including JBoss EAP 6.x and Glassfish 3.0. Upgrade this
version with caution! Also note that if you change this, you may get a failure in hibernate4-maven-plugin. See the note in hapi-fhir-jpaserver-base/pom.xml's configuration
for that plugin... <hibernate_version>4.3.7.Final</hibernate_version> -->
<hibernate_version>4.2.17.Final</hibernate_version>
<hibernate_validator_version>5.1.0.Final</hibernate_validator_version>
for that plugin... -->
<hibernate_version>5.0.1.Final</hibernate_version>
<hibernate_validator_version>5.2.1.Final</hibernate_validator_version>
<jetty_version>9.2.6.v20141205</jetty_version>
<maven_build_helper_plugin_version>1.9.1</maven_build_helper_plugin_version>
<maven_assembly_plugin_version>2.5.3</maven_assembly_plugin_version>
<maven_failsafe_plugin_version>2.18.1</maven_failsafe_plugin_version>
<maven_gpg_plugin_version>1.6</maven_gpg_plugin_version>
<maven_jxr_plugin_version>2.5</maven_jxr_plugin_version>
<maven_license_plugin_version>1.8</maven_license_plugin_version>
<maven_project_info_plugin_version>2.8</maven_project_info_plugin_version>
<maven_surefire_plugin_version>2.18.1</maven_surefire_plugin_version>
@ -231,7 +229,7 @@
<mitreid-connect-version>1.1.8</mitreid-connect-version>
<phloc_schematron_version>2.7.1</phloc_schematron_version>
<phloc_commons_version>4.3.6</phloc_commons_version>
<spring_version>4.1.5.RELEASE</spring_version>
<spring_version>4.2.1.RELEASE</spring_version>
<thymeleaf-version>2.1.4.RELEASE</thymeleaf-version>
<ebay_cors_filter_version>1.0.1</ebay_cors_filter_version>
<xmlunit_version>1.6</xmlunit_version>
@ -505,6 +503,11 @@
<artifactId>spring-core</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
@ -525,6 +528,11 @@
<artifactId>spring-web</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring_version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
@ -541,6 +549,16 @@
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>de.juplo</groupId>
<artifactId>hibernate4-maven-plugin</artifactId>
<version>1.1.0</version>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.5.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
@ -585,11 +603,21 @@
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.5</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
@ -1218,7 +1246,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${maven_gpg_plugin_version}</version>
<executions>
<execution>
<id>sign-artifacts</id>
@ -1290,7 +1317,7 @@
<module>hapi-fhir-cli</module>
<module>hapi-fhir-dist</module>
<module>examples</module>
<!--<module>hapi-fhir-osgi-core</module>-->
<module>hapi-fhir-osgi-core</module>
</modules>
</profile>
<profile>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
@ -17,12 +17,12 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@ -8,13 +8,13 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>restful-server-example</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<packaging>war</packaging>
<name>HAPI FHIR Sample RESTful Server</name>
@ -35,20 +35,20 @@
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- At least one "structures" JAR must also be included -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
</dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>1.2</version>
<version>1.3-SNAPSHOT</version>
<type>war</type>
<scope>provided</scope>
</dependency>

View File

@ -6,6 +6,50 @@
<title>HAPI FHIR Changelog</title>
</properties>
<body>
<release version="1.3" date="TBD">
<action type="add">
Bump the version of a few dependencies to the
latest versions (dependent HAPI modules listed in brackets):
<![CDATA[
<ul>
<li>Springframework (JPA, Web Tester): 4.1.5 -> 4.2.1</li>
<li>Hibernate (JPA, Web Tester): 4.2.17 -> 5.0.1</li>
</ul>
]]>
</action>
<action type="add">
JPA server removes duplicate resource index entries before storing them
(e.g. if a patient has the same name twice, only one index entry is created
for that name)
</action>
<action type="fix">
JPA server did not correctly index search parameters of type "reference" where the
path had multiple entries (i.e. "Resource.path1 | Resource.path2")
</action>
<action type="fix">
JPA server _history operations (server, type, instance) not correctly set the
Bundle.entry.request.method to POST or PUT for create and updates of the resource.
</action>
<action type="add" issue="225">
Support AND/OR on _id search parameter in JPA
</action>
<action type="fix">
Constructor for DateRanfeParam which dates in two DateParam instances was ignoring
comparators on the DateParam.
</action>
<action type="fix">
In JSON parsing, finding an object where an array was expected led to an unhelpful
error message. Thanks to Avinash Shanbhag for reporting!
</action>
<action type="add">
JPA server gave an unhelpful error message if $meta-add or $meta-delete were called
with no meta elements in the input Parameters
</action>
<action type="fix">
Narrative generator did not include OperationOutcome.issue.diagnostics in the
generated narrative.
</action>
</release>
<release version="1.2" date="2015-09-18">
<action type="add">
JPA server now validates QuestionnaireAnswers for conformance to their respective Questionnaire