diff --git a/examples/pom.xml b/examples/pom.xml
index 79b0490d5fe..a0e3908996b 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -18,22 +18,22 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-hl7org-dstu2
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-validation-resources-dstu2
- 1.2
+ 1.3-SNAPSHOTjavax.servlet
diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml
index 87deb1fd76b..99ab0ccd399 100644
--- a/hapi-deployable-pom/pom.xml
+++ b/hapi-deployable-pom/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml
index 1448c8c9f63..29fbcbcfc3a 100644
--- a/hapi-fhir-android/pom.xml
+++ b/hapi-fhir-android/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -18,7 +18,7 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOT
-
+
+
@@ -126,8 +120,7 @@
-
+
@@ -162,6 +155,10 @@
org.springframeworkspring-beans
+
+ org.springframework.data
+ spring-data-jpa
+ org.springframeworkspring-tx
@@ -226,7 +223,7 @@
com.google.guavaguava
-
+
org.eclipse.jettyjetty-servlets
@@ -252,7 +249,7 @@
spring-testtest
-
+
@@ -277,84 +274,14 @@
org.apache.maven.pluginsmaven-surefire-plugin
-
+
alphabetical
-
- de.juplo
- hibernate4-maven-plugin
- 1.0.5
-
- true
- SCRIPT
- ${skip-hib4}
-
-
-
-
- o10g
-
- export
-
- test
-
- org.hibernate.dialect.Oracle10gDialect
- ${project.build.directory}/schema_oracle_10g.sql
-
-
-
- derby
-
- export
-
- test
-
- org.hibernate.dialect.DerbyTenSevenDialect
- ${project.build.directory}/schema_derby.sql
-
-
-
- hsql
-
- export
-
- test
-
- org.hibernate.dialect.HSQLDialect
- ${project.build.directory}/schema_hsql.sql
-
-
-
- mysql5
-
- export
-
- test
-
- org.hibernate.dialect.MySQL5Dialect
- ${project.build.directory}/schema_mysql_5.sql
-
-
-
- ca.uhn.hapi.fhirhapi-tinder-plugin
- 1.2
+ 1.3-SNAPSHOTbuild_dstu1
@@ -389,12 +316,12 @@
ca.uhn.hapi.fhirhapi-fhir-structures-dstu
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOT
@@ -413,11 +340,10 @@
-
+ org.apache.maven.pluginsmaven-jxr-plugin
- ${maven_jxr_plugin_version}
@@ -429,6 +355,70 @@
true
+
+ DIST
+
+
+
+ de.juplo
+ hibernate4-maven-plugin
+
+ true
+ SCRIPT
+ ${skip-hib4}
+
+
+
+
+ o10g
+
+ export
+
+ test
+
+ org.hibernate.dialect.Oracle10gDialect
+ ${project.build.directory}/schema_oracle_10g.sql
+
+
+
+ derby
+
+ export
+
+ test
+
+ org.hibernate.dialect.DerbyTenSevenDialect
+ ${project.build.directory}/schema_derby.sql
+
+
+
+ hsql
+
+ export
+
+ test
+
+ org.hibernate.dialect.HSQLDialect
+ ${project.build.directory}/schema_hsql.sql
+
+
+
+ mysql5
+
+ export
+
+ test
+
+ org.hibernate.dialect.MySQL5Dialect
+ ${project.build.directory}/schema_mysql_5.sql
+
+
+
+
+
+
+
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
index 952362ae003..8f675b4a2a3 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
@@ -166,8 +166,8 @@ public abstract class BaseHapiFhirDao implements IDao {
return InstantDt.withCurrentTime();
}
- protected List extractResourceLinks(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ protected Set extractResourceLinks(ResourceTable theEntity, IResource theResource) {
+ Set retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -185,73 +185,76 @@ public abstract class BaseHapiFhirDao 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 implements IDao {
return retVal;
}
- protected List extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamDates(theEntity, theResource);
}
- protected List extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamNumber(theEntity, theResource);
}
- protected List extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamUri(theEntity, theResource);
}
- protected List extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamCoords(theEntity, theResource);
}
- protected List extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamQuantity(theEntity, theResource);
}
- protected List extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamStrings(theEntity, theResource);
}
- protected List extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
+ protected Set extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
return mySearchParamExtractor.extractSearchParamTokens(theEntity, theResource);
}
- private List
*/
- public void setInterceptors(List theInterceptors) {
- myInterceptors = theInterceptors;
- }
-
- public void setResourceEncoding(ResourceEncodingEnum theResourceEncoding) {
- myResourceEncoding = theResourceEncoding;
+ public void setInterceptors(IServerInterceptor... theInterceptor) {
+ setInterceptors(new ArrayList());
+ if (theInterceptor != null && theInterceptor.length != 0) {
+ getInterceptors().addAll(Arrays.asList(theInterceptor));
+ }
}
/**
@@ -107,12 +119,27 @@ public class DaoConfig {
* ID).
*
*/
- public void setInterceptors(IServerInterceptor... theInterceptor) {
- if (theInterceptor == null || theInterceptor.length==0){
- setInterceptors(new ArrayList());
- } else {
- setInterceptors(Arrays.asList(theInterceptor));
- }
+ public void setInterceptors(List 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;
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu2.java
index 0daa1bc776c..2fa92c6f9d6 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoQuestionnaireResponseDstu2.java
@@ -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;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java
new file mode 100644
index 00000000000..c0033c1d83d
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoSubscriptionDstu2.java
@@ -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 FhirResourceDaoDstu2implements IFhirResourceDaoSubscription {
+
+ 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 q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_NEXT_CHECK", SubscriptionTable.class);
+ q.setParameter("next_check", new Date());
+ q.setParameter("status", SubscriptionStatusEnum.ACTIVE);
+ List 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 flags = new ArrayList();
+ 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;
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoValueSetDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoValueSetDstu2.java
index aa5e3361a1a..48a5374251a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoValueSetDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoValueSetDstu2.java
@@ -60,7 +60,7 @@ public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2
if (sourceEntity == null) {
throw new ResourceNotFoundException(theId);
}
- ValueSet source = (ValueSet) toResource(sourceEntity);
+ ValueSet source = (ValueSet) toResource(sourceEntity, false);
/*
* Add composed concepts
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java
index 94be640520c..16f79a65a38 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu1.java
@@ -104,6 +104,7 @@ public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao> {
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> {
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> {
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> {
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;
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java
index 126f175d6e3..27a72c16d14 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirSystemDaoDstu2.java
@@ -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 {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class);
@@ -92,10 +96,10 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao {
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 callback = new TransactionCallback() {
@@ -118,13 +122,13 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao {
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 {
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 {
ourLog.info("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
long start = System.currentTimeMillis();
+ Date updateTime = new Date();
Set allIds = new LinkedHashSet();
Map idSubstitutions = new HashMap();
@@ -275,11 +211,11 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao {
// 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 {
// 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 {
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 {
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 {
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 {
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 {
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 {
IFhirResourceDao> resourceDao = getDao(nextEntry.getResource().getClass());
Set 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 {
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 {
return retVal;
}
- private static void handleTransactionCreateOrUpdateOutcome(Map idSubstitutions, Map idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome,
- Entry newEntry, String theResourceType, IResource theRes) {
+ private static void handleTransactionCreateOrUpdateOutcome(Map idSubstitutions, Map 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 {
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;
- }
- }
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java
index cac3eca1687..052faf30a08 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IDao.java
@@ -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 RESOURCE_PID = new ResourceMetadataKeyEnum("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);
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoSubscription.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoSubscription.java
new file mode 100644
index 00000000000..2cc89d82ceb
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/IFhirResourceDaoSubscription.java
@@ -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 extends IFhirResourceDao {
+
+ void pollForNewUndeliveredResources();
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamExtractor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamExtractor.java
index 58799408638..a072560042a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamExtractor.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/ISearchParamExtractor.java
@@ -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 extractSearchParamCoords(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamCoords(ResourceTable theEntity, IResource theResource);
- public abstract List extractSearchParamDates(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamDates(ResourceTable theEntity, IResource theResource);
- public abstract ArrayList extractSearchParamNumber(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamNumber(ResourceTable theEntity, IResource theResource);
- public abstract List extractSearchParamQuantity(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamQuantity(ResourceTable theEntity, IResource theResource);
- public abstract List extractSearchParamStrings(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamStrings(ResourceTable theEntity, IResource theResource);
- public abstract List extractSearchParamTokens(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamTokens(ResourceTable theEntity, IResource theResource);
- public abstract List extractSearchParamUri(ResourceTable theEntity, IResource theResource);
+ public abstract Set extractSearchParamUri(ResourceTable theEntity, IResource theResource);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu1.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu1.java
index 6bced7ae6e3..ceff8c5756c 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu1.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu1.java
@@ -75,13 +75,13 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
- public List extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
- return Collections.emptyList();
+ public Set extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
+ return Collections.emptySet();
}
@Override
- public List extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -135,8 +135,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
- public ArrayList extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public HashSet extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -230,8 +230,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
- public List extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -278,8 +278,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
- public List extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -364,8 +364,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
- public List extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -472,8 +472,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
}
@Override
- public List extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
- return Collections.emptyList();
+ public Set extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
+ return Collections.emptySet();
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java
index a23641d9ba5..b8bede8cb10 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParamExtractorDstu2.java
@@ -84,7 +84,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
super(theContext);
}
- private void addSearchTerm(ResourceTable theEntity, ArrayList retVal, String resourceName, String searchTerm) {
+ private void addSearchTerm(ResourceTable theEntity, Set 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 retVal, RuntimeSearchParam nextSpDef, String value) {
+ private void addStringParam(ResourceTable theEntity, Set 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 extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
+ public Set 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 extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
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 extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public HashSet extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
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 extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
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 extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
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 extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
String useSystem = null;
if (theResource instanceof ValueSet) {
@@ -556,8 +556,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
}
@Override
- public List extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
- ArrayList retVal = new ArrayList();
+ public Set extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
+ HashSet retVal = new HashSet();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
@@ -608,13 +608,13 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
private void extractTokensFromCodeableConcept(List theSystems, List theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity,
- ArrayList theListToPopulate, RuntimeSearchParam theParameterDef) {
+ Set theListToPopulate, RuntimeSearchParam theParameterDef) {
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
}
}
- private void extractTokensFromCoding(List theSystems, List theCodes, ResourceTable theEntity, ArrayList theListToPopulate,
+ private void extractTokensFromCoding(List theSystems, List theCodes, ResourceTable theEntity, Set theListToPopulate,
RuntimeSearchParam theParameterDef, CodingDt nextCoding) {
if (nextCoding != null && !nextCoding.isEmpty()) {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java
index 9e2a37f3bfb..fee9d22c9ca 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchParameterMap.java
@@ -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>> {
+public class SearchParameterMap extends LinkedHashMap>> {
private static final long serialVersionUID = 1L;
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionFlaggedResourceDataDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionFlaggedResourceDataDao.java
new file mode 100644
index 00000000000..c6b1abc2ee5
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/ISubscriptionFlaggedResourceDataDao.java
@@ -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 {
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java
index c161109b2ec..62efd040b37 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/BaseHasResource.java
@@ -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() {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java
index 7e6e4e88c8c..2f89be47f57 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamCoords.java
@@ -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();
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamDate.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamDate.java
index 303a2797089..140951b433a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamDate.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamDate.java
@@ -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();
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamNumber.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamNumber.java
index 405f778fae8..50d9dafabc2 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamNumber.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamNumber.java
@@ -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();
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamQuantity.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamQuantity.java
index 71e4356dbb9..ab824f7d109 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamQuantity.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamQuantity.java
@@ -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();
+ }
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamString.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamString.java
index 493d1b08756..2e6b3860855 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamString.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamString.java
@@ -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();
}
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamToken.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamToken.java
index 7f84b351e67..c22dd0ec877 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamToken.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamToken.java
@@ -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();
+ }
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamUri.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamUri.java
index 3309724dfe3..2a2370fcc8c 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamUri.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceIndexedSearchParamUri.java
@@ -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);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java
index 519088cf4c0..27e3aa2e9dd 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceLink.java
@@ -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();
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
index 45e9bd316ac..2dc12fabdc4 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
@@ -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 theNumberParams) {
+ public void setParamsNumber(Collection theNumberParams) {
if (!isParamsNumberPopulated() && theNumberParams.isEmpty()) {
return;
}
@@ -396,7 +394,7 @@ public class ResourceTable extends BaseHasResource implements Serializable {
myProfile = theProfile;
}
- public void setResourceLinks(List theLinks) {
+ public void setResourceLinks(Collection theLinks) {
if (!isHasLinks() && theLinks.isEmpty()) {
return;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionFlaggedResource.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionFlaggedResource.java
new file mode 100644
index 00000000000..e9523dee549
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionFlaggedResource.java
@@ -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;
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java
new file mode 100644
index 00000000000..46427ace7bc
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/SubscriptionTable.java
@@ -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 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;
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProviderDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProviderDstu2.java
index 4f52d6826de..cb14c240d7b 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProviderDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProviderDstu2.java
@@ -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 extends BaseJpaResourceProvider {
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 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 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 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);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/HapiDerbyTenSevenDialect.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/HapiDerbyTenSevenDialect.java
new file mode 100644
index 00000000000..c71c054a85f
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/HapiDerbyTenSevenDialect.java
@@ -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";
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/SubscriptionsRequireManualActivationInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/SubscriptionsRequireManualActivationInterceptor.java
new file mode 100644
index 00000000000..ba2289bfd1a
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/SubscriptionsRequireManualActivationInterceptor.java
@@ -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 ALLOW_STATUS_CHANGE = new ResourceMetadataKeyEnum(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 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 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;
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml b/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml
index 05bfbe60266..31c1630d367 100644
--- a/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml
+++ b/hapi-fhir-jpaserver-base/src/main/resources/fhir-spring-config.xml
@@ -35,7 +35,7 @@
-
+
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java
index 3143be96d85..dbdc63ae895 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/BaseJpaDstu2Test.java
@@ -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 myConceptMapDao;
@Autowired
protected DaoConfig myDaoConfig;
@Autowired
@Qualifier("myDeviceDaoDstu2")
protected IFhirResourceDao myDeviceDao;
@Autowired
+ @Qualifier("myDiagnosticOrderDaoDstu2")
+ protected IFhirResourceDao myDiagnosticOrderDao;
+ @Autowired
@Qualifier("myDiagnosticReportDaoDstu2")
protected IFhirResourceDao myDiagnosticReportDao;
@Autowired
@@ -82,6 +92,9 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
protected EntityManager myEntityManager;
@Autowired
protected FhirContext myFhirCtx;
+ @Autowired
+ @Qualifier("myImmunizationDaoDstu2")
+ protected IFhirResourceDao myImmunizationDao;
protected IServerInterceptor myInterceptor;
@Autowired
@Qualifier("myLocationDaoDstu2")
@@ -111,6 +124,12 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@Qualifier("myStructureDefinitionDaoDstu2")
protected IFhirResourceDao myStructureDefinitionDao;
@Autowired
+ @Qualifier("mySubscriptionDaoDstu2")
+ protected IFhirResourceDaoSubscription mySubscriptionDao;
+ @Autowired
+ @Qualifier("mySubstanceDaoDstu2")
+ protected IFhirResourceDao mySubstanceDao;
+ @Autowired
@Qualifier("mySystemDaoDstu2")
protected IFhirSystemDao 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() {
@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() {
@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();
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchTest.java
index 78ba3c9ca45..9137609fc73 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SearchTest.java
@@ -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 type = ResourceIndexedSearchParamString.class;
+ List results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
+ ourLog.info(toStringMultiline(results));
+ assertEquals(2, results.size());
+
+ List 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 actual = toUnqualifiedVersionlessIds(myDiagnosticOrderDao.search(DiagnosticOrder.SP_ITEM_DATE, new DateParam("2011-12-12T11:12:12Z")));
+ assertThat(actual, contains(id));
+
+ Class 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 actual = toUnqualifiedVersionlessIds(myImmunizationDao.search(Immunization.SP_DOSE_SEQUENCE, new NumberParam("1")));
+ assertThat(actual, contains(id));
+
+ Class 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 type = ResourceIndexedSearchParamUri.class;
+ List> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
+ ourLog.info(toStringMultiline(results));
+ assertEquals(2, results.size());
+
+ List 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 type = ResourceIndexedSearchParamQuantity.class;
+ List> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
+ ourLog.info(toStringMultiline(results));
+ assertEquals(2, results.size());
+
+ List 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 type = ResourceIndexedSearchParamToken.class;
+ List> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
+ ourLog.info(toStringMultiline(results));
+ assertEquals(2, results.size());
+
+ List 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 type = ResourceLink.class;
+ List> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
+ ourLog.info(toStringMultiline(results));
+ assertEquals(2, results.size());
+
+ List 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 params = new HashMap();
+ 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();
+ 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 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";
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SubscriptionTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SubscriptionTest.java
new file mode 100644
index 00000000000..68018559a09
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2SubscriptionTest.java
@@ -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 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());
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java
index 45b11e2f92a..8051448f839 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoDstu2Test.java
@@ -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
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java
new file mode 100644
index 00000000000..7206040068e
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/BaseResourceProviderDstu2Test.java
@@ -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 toIdListUnqualifiedVersionless(Bundle found) {
+ List list = new ArrayList();
+ for (BundleEntry next : found.getEntries()) {
+ list.add(next.getResource().getId().toUnqualifiedVersionless());
+ }
+ return list;
+ }
+
+ protected List toNameList(Bundle resp) {
+ List names = new ArrayList();
+ 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;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
index bc760d1c938..bf6f6cf8bc0 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
@@ -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 = "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+ //@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 toIdListUnqualifiedVersionless(Bundle found) {
- List list = new ArrayList();
- for (BundleEntry next : found.getEntries()) {
- list.add(next.getResource().getId().toUnqualifiedVersionless());
- }
- return list;
- }
-
- private List toNameList(Bundle resp) {
- List names = new ArrayList();
- 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;
- }
- }
-
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsRequireManualActivationInterceptorTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsRequireManualActivationInterceptorTest.java
new file mode 100644
index 00000000000..c9fbd966018
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/SubscriptionsRequireManualActivationInterceptorTest.java
@@ -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);
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/test/resources/META-INF/persistence.xml b/hapi-fhir-jpaserver-base/src/test/resources/META-INF/persistence.xml
index 6feb16c727e..897f9420809 100644
--- a/hapi-fhir-jpaserver-base/src/test/resources/META-INF/persistence.xml
+++ b/hapi-fhir-jpaserver-base/src/test/resources/META-INF/persistence.xml
@@ -21,16 +21,13 @@
ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoordsca.uhn.fhir.jpa.entity.ResourceLinkca.uhn.fhir.jpa.entity.ResourceTag
+ ca.uhn.fhir.jpa.entity.SubscriptionTable
+ ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResourceca.uhn.fhir.jpa.entity.TagDefinitionfalse
-
-
-
-
-
diff --git a/hapi-fhir-jpaserver-base/src/test/resources/fhir-jpabase-spring-test-config.xml b/hapi-fhir-jpaserver-base/src/test/resources/fhir-jpabase-spring-test-config.xml
index cc840460f79..3ff4d8ca889 100644
--- a/hapi-fhir-jpaserver-base/src/test/resources/fhir-jpabase-spring-test-config.xml
+++ b/hapi-fhir-jpaserver-base/src/test/resources/fhir-jpabase-spring-test-config.xml
@@ -33,7 +33,7 @@
-
+
diff --git a/hapi-fhir-jpaserver-example/pom.xml b/hapi-fhir-jpaserver-example/pom.xml
index 8edd2bf9915..84d895fd8b8 100644
--- a/hapi-fhir-jpaserver-example/pom.xml
+++ b/hapi-fhir-jpaserver-example/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -31,33 +31,33 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-jpaserver-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-testpage-overlay
- 1.2
+ 1.3-SNAPSHOTwarprovided
diff --git a/hapi-fhir-jpaserver-example/src/main/resources/META-INF/fhirtest_persistence.xml b/hapi-fhir-jpaserver-example/src/main/resources/META-INF/fhirtest_persistence.xml
index 6ec380207c0..29aef2bb642 100644
--- a/hapi-fhir-jpaserver-example/src/main/resources/META-INF/fhirtest_persistence.xml
+++ b/hapi-fhir-jpaserver-example/src/main/resources/META-INF/fhirtest_persistence.xml
@@ -20,6 +20,8 @@
ca.uhn.fhir.jpa.entity.ResourceLinkca.uhn.fhir.jpa.entity.ResourceTableca.uhn.fhir.jpa.entity.ResourceTag
+ ca.uhn.fhir.jpa.entity.SubscriptionTable
+ ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResourceca.uhn.fhir.jpa.entity.TagDefinitiontrue
diff --git a/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml b/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml
index 8e993d11811..6e9f1f4a0d0 100644
--- a/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml
+++ b/hapi-fhir-jpaserver-example/src/main/webapp/WEB-INF/hapi-fhir-server-database-config.xml
@@ -21,7 +21,7 @@
and other properties supported by BasicDataSource.
-->
-
+
@@ -40,7 +40,7 @@
-
+
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
index c3c4e747871..c48ff1618c3 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -18,27 +18,27 @@
ca.uhn.hapi.fhirhapi-fhir-jpaserver-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-hl7org-dstu2
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-testpage-overlay
- 1.2
+ 1.3-SNAPSHOTwarprovided
@@ -52,13 +52,6 @@
phloc-commons
-
-
org.springframeworkspring-web
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml
index 8c4c112e780..ed759870e4e 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/META-INF/fhirtest_persistence.xml
@@ -20,11 +20,13 @@
ca.uhn.fhir.jpa.entity.ResourceLinkca.uhn.fhir.jpa.entity.ResourceTableca.uhn.fhir.jpa.entity.ResourceTag
+ ca.uhn.fhir.jpa.entity.SubscriptionTable
+ ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResourceca.uhn.fhir.jpa.entity.TagDefinitiontrue
-
+
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml
index 40f2e402ccb..13c6c5fdad2 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu1.xml
@@ -44,7 +44,7 @@
-
+
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml
index 0d67234ab21..95fbacb6f31 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/resources/hapi-fhir-server-database-config-dstu2.xml
@@ -31,7 +31,7 @@
-
+
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml
index de236aebcff..1a6325c3666 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/webapp/WEB-INF/hapi-fhir-server-config.xml
@@ -18,6 +18,7 @@
+
+
+
+
+
+
+ bundle
+
+ package
+
+
+
+
src/main/resources
diff --git a/hapi-fhir-osgi-core/src/main/resources/META-INF/MANIFEST.MF b/hapi-fhir-osgi-core/src/main/resources/META-INF/MANIFEST.MF__
similarity index 100%
rename from hapi-fhir-osgi-core/src/main/resources/META-INF/MANIFEST.MF
rename to hapi-fhir-osgi-core/src/main/resources/META-INF/MANIFEST.MF__
diff --git a/hapi-fhir-structures-dstu/pom.xml b/hapi-fhir-structures-dstu/pom.xml
index 3b76a30dade..78bbaca4bd9 100644
--- a/hapi-fhir-structures-dstu/pom.xml
+++ b/hapi-fhir-structures-dstu/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhirhapi-deployable-pom
- 1.2
+ 1.3-SNAPSHOT../hapi-deployable-pom/pom.xml
@@ -17,7 +17,7 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOT
@@ -136,7 +136,7 @@
ca.uhn.hapi.fhirhapi-tinder-plugin
- 1.2
+ 1.3-SNAPSHOT
diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java
index 105d22e155b..97553951cba 100644
--- a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java
+++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java
@@ -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());
diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml
index 7534f06a29f..afe1059abeb 100644
--- a/hapi-fhir-structures-dstu2/pom.xml
+++ b/hapi-fhir-structures-dstu2/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhirhapi-deployable-pom
- 1.2
+ 1.3-SNAPSHOT../hapi-deployable-pom/pom.xml
@@ -17,13 +17,13 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-validation-resources-dstu2
- 1.2
+ 1.3-SNAPSHOTtest
@@ -144,7 +144,7 @@
ca.uhn.hapi.fhirhapi-tinder-plugin
- 1.2
+ 1.3-SNAPSHOTgenerate
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTestDstu2.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTestDstu2.java
index 769e279a4f0..02e71f67872 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTestDstu2.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTestDstu2.java
@@ -116,11 +116,11 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
String parse = "\n" +
" \n" +
" \n" +
- " \n" +
+ " \n" +
" \n" +
" \n" +
" \n" +
- " \n" +
+ " \n" +
" \n" +
"";
//@formatter:on
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java
index 0e2f0c16c20..c99f26db979 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java
@@ -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
*/
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java
index 534060da738..e481fc4b9c2 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/SearchDstu2Test.java
@@ -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 searchNoList(
+ @RequiredParam(name = "ref") ReferenceParam theParam) {
+ ourLastMethod = "searchNoList";
+ ourLastRef = theParam;
+ return Collections.emptyList();
+ }
+ //@formatter:on
+
//@formatter:off
@Search()
public List searchDateAndList(
diff --git a/hapi-fhir-structures-dstu2/src/test/resources/invalid_metadata.json b/hapi-fhir-structures-dstu2/src/test/resources/invalid_metadata.json
new file mode 100644
index 00000000000..07b9c5a77e7
--- /dev/null
+++ b/hapi-fhir-structures-dstu2/src/test/resources/invalid_metadata.json
@@ -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"
+ }
+ ]
+ }
+ ]
+}
diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml
index 7c3ea94a0d7..71ce3eff461 100644
--- a/hapi-fhir-structures-hl7org-dstu2/pom.xml
+++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhirhapi-deployable-pom
- 1.2
+ 1.3-SNAPSHOT../hapi-deployable-pom/pom.xml
@@ -18,12 +18,12 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-validation-resources-dstu2
- 1.2
+ 1.3-SNAPSHOTtest
diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml
index ea5466fb44b..595ac70b4ed 100644
--- a/hapi-fhir-testpage-overlay/pom.xml
+++ b/hapi-fhir-testpage-overlay/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -27,22 +27,22 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-jpaserver-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOT
-
ch.qos.logbacklogback-classic
@@ -111,12 +104,10 @@
org.springframeworkspring-webmvc
- ${spring_version}org.springframeworkspring-context
- ${spring_version}xml-apis
@@ -127,53 +118,44 @@
org.springframeworkspring-beans
- ${spring_version}org.springframeworkspring-tx
- ${spring_version}org.springframeworkspring-context-support
- ${spring_version}org.springframeworkspring-web
- ${spring_version}org.eclipse.jettyjetty-servlets
- ${jetty_version}testorg.eclipse.jettyjetty-webapp
- ${jetty_version}testorg.eclipse.jettyjetty-server
- ${jetty_version}testorg.eclipse.jettyjetty-servlet
- ${jetty_version}testorg.eclipse.jettyjetty-util
- ${jetty_version}test
diff --git a/hapi-fhir-testpage-overlay/src/test/resources/META-INF/persistence.xml b/hapi-fhir-testpage-overlay/src/test/resources/META-INF/persistence.xml
index 6feb16c727e..cdfcfad2d68 100644
--- a/hapi-fhir-testpage-overlay/src/test/resources/META-INF/persistence.xml
+++ b/hapi-fhir-testpage-overlay/src/test/resources/META-INF/persistence.xml
@@ -21,13 +21,15 @@
ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoordsca.uhn.fhir.jpa.entity.ResourceLinkca.uhn.fhir.jpa.entity.ResourceTag
+ ca.uhn.fhir.jpa.entity.SubscriptionTable
+ ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResourceca.uhn.fhir.jpa.entity.TagDefinitionfalse
-
+
diff --git a/hapi-fhir-testpage-overlay/src/test/resources/fhir-jpabase-spring-test-config.xml b/hapi-fhir-testpage-overlay/src/test/resources/fhir-jpabase-spring-test-config.xml
index 2a8f7ae311b..65e49701718 100644
--- a/hapi-fhir-testpage-overlay/src/test/resources/fhir-jpabase-spring-test-config.xml
+++ b/hapi-fhir-testpage-overlay/src/test/resources/fhir-jpabase-spring-test-config.xml
@@ -38,7 +38,7 @@
-
+
diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml
index ebdd42d0a0a..c7414794597 100644
--- a/hapi-fhir-validation-resources-dstu2/pom.xml
+++ b/hapi-fhir-validation-resources-dstu2/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhirhapi-deployable-pom
- 1.2
+ 1.3-SNAPSHOT../hapi-deployable-pom/pom.xml
diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml
index ce971faff82..0e7d9772b68 100644
--- a/hapi-tinder-plugin/pom.xml
+++ b/hapi-tinder-plugin/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -19,7 +19,7 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOT
- 4.2.17.Final
- 5.1.0.Final
+ for that plugin... -->
+ 5.0.1.Final
+ 5.2.1.Final9.2.6.v201412051.9.12.5.32.18.1
- 1.6
- 2.51.82.82.18.1
@@ -231,7 +229,7 @@
1.1.82.7.14.3.6
- 4.1.5.RELEASE
+ 4.2.1.RELEASE2.1.4.RELEASE1.0.11.6
@@ -505,6 +503,11 @@
spring-core${spring_version}
+
+ org.springframework.data
+ spring-data-jpa
+ 1.9.0.RELEASE
+ org.springframeworkspring-orm
@@ -525,6 +528,11 @@
spring-web${spring_version}
+
+ org.springframework
+ spring-webmvc
+ ${spring_version}
+ org.thymeleafthymeleaf
@@ -541,6 +549,16 @@
+
+ de.juplo
+ hibernate4-maven-plugin
+ 1.1.0
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ 2.5.4
+ org.apache.maven.pluginsmaven-antrun-plugin
@@ -585,11 +603,21 @@
maven-deploy-plugin2.8.2
+
+ org.apache.maven.plugins
+ maven-gpg-plugin
+ 1.6
+ org.apache.maven.pluginsmaven-javadoc-plugin2.10.1
+
+ org.apache.maven.plugins
+ maven-jxr-plugin
+ 2.5
+ org.apache.maven.pluginsmaven-failsafe-plugin
@@ -1218,7 +1246,6 @@
org.apache.maven.pluginsmaven-gpg-plugin
- ${maven_gpg_plugin_version}sign-artifacts
@@ -1290,7 +1317,7 @@
hapi-fhir-clihapi-fhir-distexamples
-
+ hapi-fhir-osgi-core
diff --git a/restful-server-example-test/pom.xml b/restful-server-example-test/pom.xml
index 03635d4cbce..f185b8d387f 100644
--- a/restful-server-example-test/pom.xml
+++ b/restful-server-example-test/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xml
@@ -17,12 +17,12 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOTtest
diff --git a/restful-server-example/pom.xml b/restful-server-example/pom.xml
index 39c04a924d7..aa9dccc6af2 100644
--- a/restful-server-example/pom.xml
+++ b/restful-server-example/pom.xml
@@ -8,13 +8,13 @@
ca.uhn.hapi.fhirhapi-fhir
- 1.2
+ 1.3-SNAPSHOT../pom.xmlca.uhn.hapi.fhirrestful-server-example
- 1.2
+ 1.3-SNAPSHOTwarHAPI FHIR Sample RESTful Server
@@ -35,20 +35,20 @@
ca.uhn.hapi.fhirhapi-fhir-base
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-structures-dstu2
- 1.2
+ 1.3-SNAPSHOTca.uhn.hapi.fhirhapi-fhir-testpage-overlay
- 1.2
+ 1.3-SNAPSHOTwarprovided
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 349eaa2d071..03e8ed1806d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -6,6 +6,50 @@
HAPI FHIR Changelog
+
+
+ Bump the version of a few dependencies to the
+ latest versions (dependent HAPI modules listed in brackets):
+
+
Springframework (JPA, Web Tester): 4.1.5 -> 4.2.1
+
Hibernate (JPA, Web Tester): 4.2.17 -> 5.0.1
+
+ ]]>
+
+
+ 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)
+
+
+ JPA server did not correctly index search parameters of type "reference" where the
+ path had multiple entries (i.e. "Resource.path1 | Resource.path2")
+
+
+ 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.
+
+
+ Support AND/OR on _id search parameter in JPA
+
+
+ Constructor for DateRanfeParam which dates in two DateParam instances was ignoring
+ comparators on the DateParam.
+
+
+ In JSON parsing, finding an object where an array was expected led to an unhelpful
+ error message. Thanks to Avinash Shanbhag for reporting!
+
+
+ JPA server gave an unhelpful error message if $meta-add or $meta-delete were called
+ with no meta elements in the input Parameters
+
+
+ Narrative generator did not include OperationOutcome.issue.diagnostics in the
+ generated narrative.
+
+
JPA server now validates QuestionnaireAnswers for conformance to their respective Questionnaire