Add _language search support
This commit is contained in:
parent
ba3bc70eae
commit
e17af44a09
|
@ -38,6 +38,10 @@
|
||||||
been removed, as it did not work correctly (and was reinventing a wheel that others
|
been removed, as it did not work correctly (and was reinventing a wheel that others
|
||||||
have done a great job inventing).
|
have done a great job inventing).
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
IResource interface did not expose the getLanguage/setLanguage methods from BaseResource,
|
||||||
|
so the resource language was difficult to access.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="0.5" date="2014-Jul-30">
|
<release version="0.5" date="2014-Jul-30">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.SearchParamDefinition;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
import ca.uhn.fhir.model.primitive.CodeDt;
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
|
@ -36,6 +37,19 @@ import ca.uhn.fhir.util.ElementUtil;
|
||||||
|
|
||||||
public abstract class BaseResource extends BaseElement implements IResource {
|
public abstract class BaseResource extends BaseElement implements IResource {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search parameter constant for <b>_language</b>
|
||||||
|
*/
|
||||||
|
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||||
|
public static final String SP_RES_LANGUAGE = "_language";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search parameter constant for <b>_id</b>
|
||||||
|
*/
|
||||||
|
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
|
||||||
|
public static final String SP_RES_ID = "_id";
|
||||||
|
|
||||||
@Child(name = "contained", order = 2, min = 0, max = 1)
|
@Child(name = "contained", order = 2, min = 0, max = 1)
|
||||||
private ContainedDt myContained;
|
private ContainedDt myContained;
|
||||||
|
|
||||||
|
@ -65,13 +79,10 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
|
||||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
|
||||||
b.append("id", getId().toUnqualified());
|
|
||||||
return b.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public CodeDt getLanguage() {
|
public CodeDt getLanguage() {
|
||||||
|
if (myLanguage == null) {
|
||||||
|
myLanguage = new CodeDt();
|
||||||
|
}
|
||||||
return myLanguage;
|
return myLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +118,7 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setLanguage(CodeDt theLanguage) {
|
public void setLanguage(CodeDt theLanguage) {
|
||||||
myLanguage = theLanguage;
|
myLanguage = theLanguage;
|
||||||
}
|
}
|
||||||
|
@ -121,6 +133,13 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
||||||
myText = theText;
|
myText = theText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||||
|
b.append("id", getId().toUnqualified());
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
|
||||||
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Map;
|
||||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
|
||||||
public interface IResource extends ICompositeElement {
|
public interface IResource extends ICompositeElement {
|
||||||
|
@ -46,9 +47,23 @@ public interface IResource extends ICompositeElement {
|
||||||
ContainedDt getContained();
|
ContainedDt getContained();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the narrative block for this resource
|
* Returns the ID of this resource. Note that this identifier is the URL (or a portion
|
||||||
|
* of the URL) used to access this resource, and is not the same thing as any business
|
||||||
|
* identifiers stored within the resource. For example, a Patient resource might
|
||||||
|
* have any number of medical record numbers but these are not stored here.
|
||||||
|
* <p>
|
||||||
|
* This ID is specified as the "Logical ID" and "Version ID" in the FHIR specification, see
|
||||||
|
* <a href="http://www.hl7.org/implement/standards/fhir/resources.html#metadata">here</a>
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
NarrativeDt getText();
|
IdDt getId();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the language of the resource itself - <b>NOTE that this language attribute
|
||||||
|
* applies to the resource itself, it is not (for example) the language spoken by
|
||||||
|
* a practitioner or patient</b>
|
||||||
|
*/
|
||||||
|
CodeDt getLanguage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the metadata map for this object, creating it if neccesary.
|
* Returns the metadata map for this object, creating it if neccesary.
|
||||||
|
@ -65,26 +80,9 @@ public interface IResource extends ICompositeElement {
|
||||||
Map<ResourceMetadataKeyEnum<?>, Object> getResourceMetadata();
|
Map<ResourceMetadataKeyEnum<?>, Object> getResourceMetadata();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the metadata map for this object. Metadata entries are used to
|
* Returns the narrative block for this resource
|
||||||
* get/set feed bundle entries, such as the resource version, or the last
|
|
||||||
* updated timestamp.
|
|
||||||
*
|
|
||||||
* @throws NullPointerException
|
|
||||||
* The map must not be null
|
|
||||||
*/
|
*/
|
||||||
void setResourceMetadata(Map<ResourceMetadataKeyEnum<?>, Object> theMap);
|
NarrativeDt getText();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the ID of this resource. Note that this identifier is the URL (or a portion
|
|
||||||
* of the URL) used to access this resource, and is not the same thing as any business
|
|
||||||
* identifiers stored within the resource. For example, a Patient resource might
|
|
||||||
* have any number of medical record numbers but these are not stored here.
|
|
||||||
* <p>
|
|
||||||
* This ID is specified as the "Logical ID" and "Version ID" in the FHIR specification, see
|
|
||||||
* <a href="http://www.hl7.org/implement/standards/fhir/resources.html#metadata">here</a>
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
IdDt getId();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the ID of this resource. Note that this identifier is the URL (or a portion
|
* Sets the ID of this resource. Note that this identifier is the URL (or a portion
|
||||||
|
@ -97,5 +95,22 @@ public interface IResource extends ICompositeElement {
|
||||||
* </p>
|
* </p>
|
||||||
*/
|
*/
|
||||||
void setId(IdDt theId);
|
void setId(IdDt theId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the language of the resource itself - <b>NOTE that this language attribute
|
||||||
|
* applies to the resource itself, it is not (for example) the language spoken by
|
||||||
|
* a practitioner or patient</b>
|
||||||
|
*/
|
||||||
|
void setLanguage(CodeDt theLanguage);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the metadata map for this object. Metadata entries are used to
|
||||||
|
* get/set feed bundle entries, such as the resource version, or the last
|
||||||
|
* updated timestamp.
|
||||||
|
*
|
||||||
|
* @throws NullPointerException
|
||||||
|
* The map must not be null
|
||||||
|
*/
|
||||||
|
void setResourceMetadata(Map<ResourceMetadataKeyEnum<?>, Object> theMap);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,9 +65,9 @@
|
||||||
<item name="RESTful Client" href="./doc_rest_client.html" />
|
<item name="RESTful Client" href="./doc_rest_client.html" />
|
||||||
<item name="RESTful Server" href="./doc_rest_server.html" >
|
<item name="RESTful Server" href="./doc_rest_server.html" >
|
||||||
<item name="RESTful Operations" href="./doc_rest_operations.html" />
|
<item name="RESTful Operations" href="./doc_rest_operations.html" />
|
||||||
<item name="FHIR Tester App" href="./doc_server_tester.html" />
|
|
||||||
<item name="Narrative Generator" href="./doc_narrative.html" />
|
<item name="Narrative Generator" href="./doc_narrative.html" />
|
||||||
<item name="CORS Support" href="./doc_cors.html" />
|
<item name="CORS Support" href="./doc_cors.html" />
|
||||||
|
<item name="Web Testing UI" href="./doc_server_tester.html" />
|
||||||
</item>
|
</item>
|
||||||
<item name="Logging" href="./doc_logging.html" />
|
<item name="Logging" href="./doc_logging.html" />
|
||||||
<item name="Tinder Plugin" href="./doc_tinder.html" />
|
<item name="Tinder Plugin" href="./doc_tinder.html" />
|
||||||
|
|
|
@ -1138,6 +1138,7 @@ public abstract class BaseFhirDao implements IDao {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
||||||
stringParams = extractSearchParamStrings(entity, theResource);
|
stringParams = extractSearchParamStrings(entity, theResource);
|
||||||
numberParams = extractSearchParamNumber(entity, theResource);
|
numberParams = extractSearchParamNumber(entity, theResource);
|
||||||
quantityParams = extractSearchParamQuantity(entity, theResource);
|
quantityParams = extractSearchParamQuantity(entity, theResource);
|
||||||
|
@ -1156,6 +1157,7 @@ public abstract class BaseFhirDao implements IDao {
|
||||||
populateResourceIntoEntity(theResource, entity);
|
populateResourceIntoEntity(theResource, entity);
|
||||||
|
|
||||||
entity.setUpdated(new Date());
|
entity.setUpdated(new Date());
|
||||||
|
entity.setLanguage(theResource.getLanguage().getValue());
|
||||||
entity.setParamsString(stringParams);
|
entity.setParamsString(stringParams);
|
||||||
entity.setParamsStringPopulated(stringParams.isEmpty() == false);
|
entity.setParamsStringPopulated(stringParams.isEmpty() == false);
|
||||||
entity.setParamsToken(tokenParams);
|
entity.setParamsToken(tokenParams);
|
||||||
|
|
|
@ -440,7 +440,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
predicates.add(from.get("myId").in(pids));
|
predicates.add(from.get("myId").in(pids));
|
||||||
createSort(builder, from, theParams.getSort(), orders,predicates);
|
createSort(builder, from, theParams.getSort(), orders, predicates);
|
||||||
if (orders.size() > 0) {
|
if (orders.size() > 0) {
|
||||||
loadPids = new LinkedHashSet<Long>();
|
loadPids = new LinkedHashSet<Long>();
|
||||||
cq.multiselect(from.get("myId").as(Long.class));
|
cq.multiselect(from.get("myId").as(Long.class));
|
||||||
|
@ -454,7 +454,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Sort PID order is now: {}", loadPids);
|
ourLog.info("Sort PID order is now: {}", loadPids);
|
||||||
|
|
||||||
pids.clear();
|
pids.clear();
|
||||||
pids.addAll(loadPids);
|
pids.addAll(loadPids);
|
||||||
}
|
}
|
||||||
|
@ -552,30 +552,30 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createSort(CriteriaBuilder theBuilder, Root<ResourceTable> theFrom, SortSpec theSort, List<Order> theOrders, List<Predicate> thePredicates) {
|
private void createSort(CriteriaBuilder theBuilder, Root<ResourceTable> theFrom, SortSpec theSort, List<Order> theOrders, List<Predicate> thePredicates) {
|
||||||
if (theSort==null||isBlank(theSort.getParamName())) {
|
if (theSort == null || isBlank(theSort.getParamName())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(myResourceType);
|
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(myResourceType);
|
||||||
RuntimeSearchParam param = resourceDef.getSearchParam(theSort.getParamName());
|
RuntimeSearchParam param = resourceDef.getSearchParam(theSort.getParamName());
|
||||||
if (param == null) {
|
if (param == null) {
|
||||||
throw new InvalidRequestException("Unknown sort parameter '" + theSort.getParamName() + "'");
|
throw new InvalidRequestException("Unknown sort parameter '" + theSort.getParamName() + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
String joinAttrName = "myParamsString";
|
String joinAttrName = "myParamsString";
|
||||||
String sortAttrName = "myValueExact";
|
String sortAttrName = "myValueExact";
|
||||||
|
|
||||||
switch (param.getParamType()) {
|
switch (param.getParamType()) {
|
||||||
case STRING: {
|
case STRING: {
|
||||||
From<?,?> stringJoin = theFrom.join(joinAttrName, JoinType.LEFT);
|
From<?, ?> stringJoin = theFrom.join(joinAttrName, JoinType.LEFT);
|
||||||
Predicate p = theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName());
|
Predicate p = theBuilder.equal(stringJoin.get("myParamName"), theSort.getParamName());
|
||||||
Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
|
Predicate pn = theBuilder.isNull(stringJoin.get("myParamName"));
|
||||||
thePredicates.add(theBuilder.or(p,pn));
|
thePredicates.add(theBuilder.or(p, pn));
|
||||||
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName)));
|
theOrders.add(theBuilder.asc(stringJoin.get(sortAttrName)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
|
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,6 +612,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
||||||
String nextParamName = nextParamEntry.getKey();
|
String nextParamName = nextParamEntry.getKey();
|
||||||
if (nextParamName.equals("_id")) {
|
if (nextParamName.equals("_id")) {
|
||||||
|
|
||||||
if (nextParamEntry.getValue().isEmpty()) {
|
if (nextParamEntry.getValue().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
} else if (nextParamEntry.getValue().size() > 1) {
|
} else if (nextParamEntry.getValue().size() > 1) {
|
||||||
|
@ -647,8 +648,12 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
} else {
|
} else {
|
||||||
pids.retainAll(joinPids);
|
pids.retainAll(joinPids);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (nextParamName.equals("_language")) {
|
||||||
|
|
||||||
|
pids = addPredicateLanguage(pids, nextParamEntry.getValue());
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
|
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
|
||||||
|
@ -1185,6 +1190,51 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
return new HashSet<Long>(q.getResultList());
|
return new HashSet<Long>(q.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<Long> addPredicateLanguage(Set<Long> thePids, List<List<? extends IQueryParameterType>> theList) {
|
||||||
|
if (theList == null || theList.isEmpty()) {
|
||||||
|
return thePids;
|
||||||
|
}
|
||||||
|
if (theList.size() > 1) {
|
||||||
|
throw new InvalidRequestException("Language parameter can not have more than one AND value, found " + theList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||||
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
cq.select(from.get("myId").as(Long.class));
|
||||||
|
|
||||||
|
Set<String> values = new HashSet<String>();
|
||||||
|
for (IQueryParameterType next : theList.get(0)) {
|
||||||
|
if (next instanceof StringParam) {
|
||||||
|
String nextValue = ((StringParam) next).getValue();
|
||||||
|
if (isBlank(nextValue)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
values.add(nextValue);
|
||||||
|
} else {
|
||||||
|
throw new InternalErrorException("Lanugage parameter must be of type " + StringParam.class.getCanonicalName() + " - Got " + next.getClass().getCanonicalName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.isEmpty()) {
|
||||||
|
return thePids;
|
||||||
|
}
|
||||||
|
|
||||||
|
Predicate typePredicate = builder.equal(from.get("myResourceType"), myResourceName);
|
||||||
|
Predicate langPredicate = from.get("myLanguage").as(String.class).in(values);
|
||||||
|
Predicate masterCodePredicate = builder.and(typePredicate, langPredicate);
|
||||||
|
|
||||||
|
if (thePids.size() > 0) {
|
||||||
|
Predicate inPids = (from.get("myId").in(thePids));
|
||||||
|
cq.where(builder.and(masterCodePredicate, inPids));
|
||||||
|
} else {
|
||||||
|
cq.where(masterCodePredicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypedQuery<Long> q = myEntityManager.createQuery(cq);
|
||||||
|
return new HashSet<Long>(q.getResultList());
|
||||||
|
}
|
||||||
|
|
||||||
private Set<Long> addPredicateToken(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
|
private Set<Long> addPredicateToken(String theParamName, Set<Long> thePids, List<? extends IQueryParameterType> theList) {
|
||||||
if (theList == null || theList.isEmpty()) {
|
if (theList == null || theList.isEmpty()) {
|
||||||
return thePids;
|
return thePids;
|
||||||
|
@ -1250,8 +1300,6 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private Predicate createPredicateDate(CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> theFrom, IQueryParameterType theParam) {
|
private Predicate createPredicateDate(CriteriaBuilder theBuilder, From<ResourceIndexedSearchParamDate, ResourceIndexedSearchParamDate> theFrom, IQueryParameterType theParam) {
|
||||||
Predicate p;
|
Predicate p;
|
||||||
if (theParam instanceof DateParam) {
|
if (theParam instanceof DateParam) {
|
||||||
|
@ -1359,7 +1407,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
||||||
position.put(next, theResourceListToPopulate.size());
|
position.put(next, theResourceListToPopulate.size());
|
||||||
theResourceListToPopulate.add(null);
|
theResourceListToPopulate.add(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<ResourceTable> cq = builder.createQuery(ResourceTable.class);
|
CriteriaQuery<ResourceTable> cq = builder.createQuery(ResourceTable.class);
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.entity;
|
package ca.uhn.fhir.jpa.entity;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -21,12 +23,23 @@ import org.hibernate.annotations.Index;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.server.Constants;
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
@Entity
|
@Entity
|
||||||
@Table(name = "HFJ_RESOURCE", uniqueConstraints = {})
|
@Table(name = "HFJ_RESOURCE", uniqueConstraints = {})
|
||||||
@Inheritance(strategy = InheritanceType.JOINED)
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
@org.hibernate.annotations.Table(appliesTo = "HFJ_RESOURCE", indexes = { @Index(name = "IDX_RES_DATE", columnNames = { "RES_UPDATED" }) })
|
@org.hibernate.annotations.Table(appliesTo = "HFJ_RESOURCE",
|
||||||
|
indexes = {
|
||||||
|
@Index(name = "IDX_RES_DATE", columnNames = { "RES_UPDATED" }),
|
||||||
|
@Index(name = "IDX_RES_LANG", columnNames = { "RES_TYPE", "RES_LANGUAGE" }),
|
||||||
|
@Index(name = "IDX_RES_PROFILE", columnNames = { "RES_PROFILE" })
|
||||||
|
})
|
||||||
|
//@formatter:on
|
||||||
public class ResourceTable extends BaseHasResource implements Serializable {
|
public class ResourceTable extends BaseHasResource implements Serializable {
|
||||||
|
private static final int MAX_LANGUAGE_LENGTH = 20;
|
||||||
|
private static final int MAX_PROFILE_LENGTH = 200;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
static final int RESTYPE_LEN = 30;
|
static final int RESTYPE_LEN = 30;
|
||||||
|
@ -84,6 +97,34 @@ public class ResourceTable extends BaseHasResource implements Serializable {
|
||||||
@Column(name = "RES_VER")
|
@Column(name = "RES_VER")
|
||||||
private long myVersion;
|
private long myVersion;
|
||||||
|
|
||||||
|
@Column(name = "RES_LANGUAGE", length=MAX_LANGUAGE_LENGTH, nullable=true)
|
||||||
|
private String myLanguage;
|
||||||
|
|
||||||
|
@Column(name = "RES_PROFILE", length=MAX_PROFILE_LENGTH,nullable=true)
|
||||||
|
private String myProfile;
|
||||||
|
|
||||||
|
public String getLanguage() {
|
||||||
|
return myLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLanguage(String theLanguage) {
|
||||||
|
if (defaultString(theLanguage).length()> MAX_LANGUAGE_LENGTH) {
|
||||||
|
throw new UnprocessableEntityException("Language exceeds maximum length of " + MAX_LANGUAGE_LENGTH + " chars: " + theLanguage);
|
||||||
|
}
|
||||||
|
myLanguage = theLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProfile() {
|
||||||
|
return myProfile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfile(String theProfile) {
|
||||||
|
if (defaultString(theProfile).length()> MAX_PROFILE_LENGTH) {
|
||||||
|
throw new UnprocessableEntityException("Profile name exceeds maximum length of " + MAX_PROFILE_LENGTH + " chars: " + theProfile);
|
||||||
|
}
|
||||||
|
myProfile = theProfile;
|
||||||
|
}
|
||||||
|
|
||||||
public ResourceTag addTag(TagDefinition theTag) {
|
public ResourceTag addTag(TagDefinition theTag) {
|
||||||
ResourceTag tag = new ResourceTag(this, theTag);
|
ResourceTag tag = new ResourceTag(this, theTag);
|
||||||
tag.setResourceType(getResourceType());
|
tag.setResourceType(getResourceType());
|
||||||
|
|
|
@ -899,6 +899,47 @@ public class FhirResourceDaoTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchLanguageParam() {
|
||||||
|
IdDt id1;
|
||||||
|
{
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.getLanguage().setValue("en_CA");
|
||||||
|
patient.addIdentifier("urn:system", "001");
|
||||||
|
patient.addName().addFamily("testSearchLanguageParam").addGiven("Joe");
|
||||||
|
id1 = ourPatientDao.create(patient).getId();
|
||||||
|
}
|
||||||
|
IdDt id2;
|
||||||
|
{
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.getLanguage().setValue("en_US");
|
||||||
|
patient.addIdentifier("urn:system", "002");
|
||||||
|
patient.addName().addFamily("testSearchLanguageParam").addGiven("John");
|
||||||
|
id2 = ourPatientDao.create(patient).getId();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
|
||||||
|
params.put(Patient.SP_RES_LANGUAGE, new StringParam("en_CA"));
|
||||||
|
List<Patient> patients = toList(ourPatientDao.search(params));
|
||||||
|
assertEquals(1, patients.size());
|
||||||
|
assertEquals(id1.toUnqualifiedVersionless(), patients.get(0).getId().toUnqualifiedVersionless());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
|
||||||
|
params.put(Patient.SP_RES_LANGUAGE, new StringParam("en_US"));
|
||||||
|
List<Patient> patients = toList(ourPatientDao.search(params));
|
||||||
|
assertEquals(1, patients.size());
|
||||||
|
assertEquals(id2.toUnqualifiedVersionless(), patients.get(0).getId().toUnqualifiedVersionless());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
|
||||||
|
params.put(Patient.SP_RES_LANGUAGE, new StringParam("en_GB"));
|
||||||
|
List<Patient> patients = toList(ourPatientDao.search(params));
|
||||||
|
assertEquals(0, patients.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchStringParamWithNonNormalized() {
|
public void testSearchStringParamWithNonNormalized() {
|
||||||
{
|
{
|
||||||
|
|
|
@ -145,13 +145,6 @@
|
||||||
<groupId>org.ebaysf.web</groupId>
|
<groupId>org.ebaysf.web</groupId>
|
||||||
<artifactId>cors-filter</artifactId>
|
<artifactId>cors-filter</artifactId>
|
||||||
<version>${ebay_cors_filter_version}</version>
|
<version>${ebay_cors_filter_version}</version>
|
||||||
<optional>true</optional>
|
|
||||||
<exclusions>
|
|
||||||
<exclusion>
|
|
||||||
<artifactId>servlet-api</artifactId>
|
|
||||||
<groupId>javax.servlet</groupId>
|
|
||||||
</exclusion>
|
|
||||||
</exclusions>
|
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
|
@ -68,7 +68,6 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
setServerConformanceProvider(confProvider);
|
setServerConformanceProvider(confProvider);
|
||||||
|
|
||||||
setUseBrowserFriendlyContentTypes(true);
|
setUseBrowserFriendlyContentTypes(true);
|
||||||
setCorsAllowDomain("*");
|
|
||||||
|
|
||||||
String baseUrl = System.getProperty("fhir.baseurl");
|
String baseUrl = System.getProperty("fhir.baseurl");
|
||||||
if (StringUtils.isBlank(baseUrl)) {
|
if (StringUtils.isBlank(baseUrl)) {
|
||||||
|
|
|
@ -52,4 +52,52 @@
|
||||||
<url-pattern>/</url-pattern>
|
<url-pattern>/</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||||
|
<filter>
|
||||||
|
<filter-name>CORS Filter</filter-name>
|
||||||
|
<filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
|
||||||
|
<param-name>cors.allowed.origins</param-name>
|
||||||
|
<param-value>*</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
|
||||||
|
<param-name>cors.allowed.methods</param-name>
|
||||||
|
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of allowed headers when making a non simple CORS request.</description>
|
||||||
|
<param-name>cors.allowed.headers</param-name>
|
||||||
|
<param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
|
||||||
|
<param-name>cors.exposed.headers</param-name>
|
||||||
|
<param-value></param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A flag that suggests if CORS is supported with cookies</description>
|
||||||
|
<param-name>cors.support.credentials</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A flag to control logging</description>
|
||||||
|
<param-name>cors.logging.enabled</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
|
||||||
|
<param-name>cors.preflight.maxage</param-name>
|
||||||
|
<param-value>300</param-value>
|
||||||
|
</init-param>
|
||||||
|
</filter>
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>CORS Filter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
|
||||||
|
|
||||||
</web-app>
|
</web-app>
|
||||||
|
|
|
@ -29,6 +29,10 @@ public class ${className}ResourceProvider extends JpaResourceProvider<${classNam
|
||||||
@Description(shortDefinition="The resource identity")
|
@Description(shortDefinition="The resource identity")
|
||||||
@OptionalParam(name="_id")
|
@OptionalParam(name="_id")
|
||||||
StringParam theId,
|
StringParam theId,
|
||||||
|
|
||||||
|
@Description(shortDefinition="The resource language")
|
||||||
|
@OptionalParam(name="_language")
|
||||||
|
StringParam theResourceLanguage,
|
||||||
#foreach ( $param in $searchParams ) #{if}(true) #{end}
|
#foreach ( $param in $searchParams ) #{if}(true) #{end}
|
||||||
|
|
||||||
@Description(shortDefinition="${param.description}")
|
@Description(shortDefinition="${param.description}")
|
||||||
|
@ -70,7 +74,8 @@ public class ${className}ResourceProvider extends JpaResourceProvider<${classNam
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
SearchParameterMap paramMap = new SearchParameterMap();
|
SearchParameterMap paramMap = new SearchParameterMap();
|
||||||
paramMap.add("_id", theId);
|
paramMap.add("_id", theId);
|
||||||
|
paramMap.add("_language", theResourceLanguage);
|
||||||
#foreach ( $param in $searchParams )
|
#foreach ( $param in $searchParams )
|
||||||
paramMap.add("${param.name}", the${param.nameCapitalized});
|
paramMap.add("${param.name}", the${param.nameCapitalized});
|
||||||
#end
|
#end
|
||||||
|
|
Loading…
Reference in New Issue