Many bugfixes

This commit is contained in:
jamesagnew 2014-03-21 15:32:37 -04:00
parent 79bdd94f72
commit cb19b17e59
26 changed files with 398 additions and 116 deletions

View File

@ -33,6 +33,8 @@
* Support "Binary" resource, which is a special resource type * Support "Binary" resource, which is a special resource type
* Submit "_pretty" as possible parameter to HL7
--------- ---------
Issues: Issues:
* Need to be able to bind Identifier.system to a set of allowable values in a profile. Graeme * Need to be able to bind Identifier.system to a set of allowable values in a profile. Graeme

View File

@ -8,7 +8,6 @@ import java.util.Set;
import ca.uhn.fhir.model.api.ICodeEnum; import ca.uhn.fhir.model.api.ICodeEnum;
import ca.uhn.fhir.model.api.IDatatype; import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.model.api.annotation.Description;
@ -35,7 +34,8 @@ public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDecl
@Override @Override
public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theDatatype) { public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theDatatype) {
if (myDatatype.equals(theDatatype)) { Class<? extends IElement> datatype = theDatatype;
if (myDatatype.equals(datatype)) {
return myElementDefinition; return myElementDefinition;
} }
return null; return null;
@ -74,4 +74,11 @@ public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDecl
} }
myCodeType = theType; myCodeType = theType;
} }
@Override
public String toString() {
return getClass().getSimpleName() + "[" + getElementName() + "]";
}
} }

View File

@ -13,5 +13,4 @@ public class RuntimeChildCompositeDatatypeDefinition extends BaseRuntimeChildDat
} }
} }

View File

@ -83,4 +83,9 @@ public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefi
myValidChildNames = Collections.unmodifiableSet(myValidChildNames); myValidChildNames = Collections.unmodifiableSet(myValidChildNames);
} }
@Override
public String toString() {
return getClass().getSimpleName() + "[" + getElementName() + "]";
}
} }

View File

@ -30,7 +30,7 @@ public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt
return; return;
} }
for (T next : theValues) { for (T next : theValues) {
getCoding().add(new BoundCodingDt<T>(myBinder, next)); getCoding().add(new CodingDt(myBinder.toSystemString(next), myBinder.toCodeString(next)));
} }
} }

View File

@ -5,16 +5,16 @@ import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.model.api.annotation.DatatypeDef; import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu.composite.CodingDt; import ca.uhn.fhir.model.dstu.composite.CodingDt;
@DatatypeDef(name = "Coding") @DatatypeDef(name = "Coding", isSpecialization=true)
public class BoundCodingDt<T extends Enum<?>> extends CodingDt { public class BoundCodingDt__<T extends Enum<?>> extends CodingDt {
private IValueSetEnumBinder<T> myBinder; private IValueSetEnumBinder<T> myBinder;
public BoundCodingDt(IValueSetEnumBinder<T> theBinder) { public BoundCodingDt__(IValueSetEnumBinder<T> theBinder) {
myBinder = theBinder; myBinder = theBinder;
} }
public BoundCodingDt(IValueSetEnumBinder<T> theBinder, T theValue) { public BoundCodingDt__(IValueSetEnumBinder<T> theBinder, T theValue) {
myBinder = theBinder; myBinder = theBinder;
setValueAsEnum(theValue); setValueAsEnum(theValue);
} }

View File

@ -8,9 +8,7 @@ import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
/** /**
* Represents the FHIR ID type. This is the actual resource ID, meaning the ID that * Represents the FHIR ID type. This is the actual resource ID, meaning the ID that will be used in RESTful URLs, Resource References, etc. to represent a specific instance of a resource.
* will be used in RESTful URLs, Resource References, etc. to represent a specific
* instance of a resource.
* *
* <p> * <p>
* <b>Description</b>: A whole number in the range 0 to 2^64-1 (optionally represented in hex), a uuid, an oid, or any other combination of lowercase letters, numerals, "-" and ".", with a length * <b>Description</b>: A whole number in the range 0 to 2^64-1 (optionally represented in hex), a uuid, an oid, or any other combination of lowercase letters, numerals, "-" and ".", with a length
@ -32,6 +30,17 @@ public class IdDt extends BasePrimitive<String> {
super(); super();
} }
/**
* Create a new ID, using a BigDecimal input. Uses {@link BigDecimal#toPlainString()} to generate the string representation.
*/
public IdDt(BigDecimal thePid) {
if (thePid != null) {
setValue(thePid.toPlainString());
} else {
setValue(null);
}
}
/** /**
* Create a new ID using a long * Create a new ID using a long
*/ */
@ -56,14 +65,24 @@ public class IdDt extends BasePrimitive<String> {
} }
/** /**
* Create a new ID, using a BigDecimal input. Uses {@link BigDecimal#toPlainString()} to generate the string representation. * Returns the value of this ID as a big decimal, or <code>null</code> if the value is null
*
* @throws NumberFormatException
* If the value is not a valid BigDecimal
*/ */
public IdDt(BigDecimal thePid) { public BigDecimal asBigDecimal() {
if (thePid != null) { if (getValue() == null) {
setValue(thePid.toPlainString()); return null;
} else {
setValue(null);
} }
return new BigDecimal(getValueAsString());
}
/**
* Returns a reference to <code>this</code> IdDt. It is generally not neccesary to use this method but it is provided for consistency with the rest of the API.
*/
@Override
public IdDt getId() {
return this;
} }
@Override @Override
@ -76,6 +95,14 @@ public class IdDt extends BasePrimitive<String> {
return myValue; return myValue;
} }
/**
* Copies the value from the given IdDt to <code>this</code> IdDt. It is generally not neccesary to use this method but it is provided for consistency with the rest of the API.
*/
@Override
public void setId(IdDt theId) {
setValue(theId.getValue());
}
/** /**
* Set the value * Set the value
* *
@ -114,16 +141,4 @@ public class IdDt extends BasePrimitive<String> {
return myValue; return myValue;
} }
/**
* Returns the value of this ID as a big decimal, or <code>null</code> if the value is null
*
* @throws NumberFormatException If the value is not a valid BigDecimal
*/
public BigDecimal asBigDecimal() {
if (getValue() == null){
return null;
}
return new BigDecimal(getValueAsString());
}
} }

View File

@ -101,5 +101,13 @@ public class StringDt extends BasePrimitive<String> implements IQueryParameterTy
return getValue(); return getValue();
} }
/**
* Returns <code>true</code> if this datatype has no extensions, and has either a <code>null</code>
* value or an empty ("") value.
*/
@Override
public boolean isEmpty() {
return super.isEmpty() && StringUtils.isBlank(getValue());
}
} }

View File

@ -99,7 +99,7 @@ public class JsonParser extends BaseParser implements IParser {
writeTagWithTextNode(eventWriter, "id", nextEntry.getEntryId()); writeTagWithTextNode(eventWriter, "id", nextEntry.getEntryId());
eventWriter.writeStartArray("link"); eventWriter.writeStartArray("link");
writeAtomLink(eventWriter, "self", theBundle.getLinkSelf()); writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf());
eventWriter.writeEnd(); eventWriter.writeEnd();
writeOptionalTagWithTextNode(eventWriter, "updated", nextEntry.getUpdated()); writeOptionalTagWithTextNode(eventWriter, "updated", nextEntry.getUpdated());

View File

@ -100,7 +100,7 @@ public class XmlParser extends BaseParser implements IParser {
writeAtomLink(eventWriter, "fhir-base", theBundle.getLinkBase()); writeAtomLink(eventWriter, "fhir-base", theBundle.getLinkBase());
if (theBundle.getTotalResults().getValue() != null) { if (theBundle.getTotalResults().getValue() != null) {
eventWriter.writeStartElement("os", "totalResults",OPENSEARCH_NS); eventWriter.writeStartElement("os", "totalResults", OPENSEARCH_NS);
eventWriter.writeNamespace("os", OPENSEARCH_NS); eventWriter.writeNamespace("os", OPENSEARCH_NS);
eventWriter.writeCharacters(theBundle.getTotalResults().getValue().toString()); eventWriter.writeCharacters(theBundle.getTotalResults().getValue().toString());
eventWriter.writeEndElement(); eventWriter.writeEndElement();
@ -119,6 +119,13 @@ public class XmlParser extends BaseParser implements IParser {
for (BundleEntry nextEntry : theBundle.getEntries()) { for (BundleEntry nextEntry : theBundle.getEntries()) {
eventWriter.writeStartElement("entry"); eventWriter.writeStartElement("entry");
writeTagWithTextNode(eventWriter, "title", nextEntry.getTitle());
writeTagWithTextNode(eventWriter, "id", nextEntry.getEntryId());
if (!nextEntry.getLinkSelf().isEmpty()) {
writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf());
}
eventWriter.writeStartElement("content"); eventWriter.writeStartElement("content");
eventWriter.writeAttribute("type", "text/xml"); eventWriter.writeAttribute("type", "text/xml");
@ -138,7 +145,7 @@ public class XmlParser extends BaseParser implements IParser {
@Override @Override
public String encodeResourceToString(IResource theResource) throws DataFormatException { public String encodeResourceToString(IResource theResource) throws DataFormatException {
if (theResource==null) { if (theResource == null) {
throw new NullPointerException("Resource can not be null"); throw new NullPointerException("Resource can not be null");
} }
@ -200,8 +207,6 @@ public class XmlParser extends BaseParser implements IParser {
return parseResource(theResourceType, streamReader); return parseResource(theResourceType, streamReader);
} }
@Override @Override
public IParser setPrettyPrint(boolean thePrettyPrint) { public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint; myPrettyPrint = thePrettyPrint;
@ -290,7 +295,8 @@ public class XmlParser extends BaseParser implements IParser {
} }
} }
private void encodeChildElementToStreamWriter(XMLStreamWriter theEventWriter, IElement nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl) throws XMLStreamException, DataFormatException { private void encodeChildElementToStreamWriter(XMLStreamWriter theEventWriter, IElement nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl)
throws XMLStreamException, DataFormatException {
if (nextValue.isEmpty()) { if (nextValue.isEmpty()) {
return; return;
} }
@ -355,7 +361,8 @@ public class XmlParser extends BaseParser implements IParser {
} }
private void encodeCompositeElementChildrenToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> children) throws XMLStreamException, DataFormatException { private void encodeCompositeElementChildrenToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> children) throws XMLStreamException,
DataFormatException {
for (BaseRuntimeChildDefinition nextChild : children) { for (BaseRuntimeChildDefinition nextChild : children) {
List<? extends IElement> values = nextChild.getAccessor().getValues(theElement); List<? extends IElement> values = nextChild.getAccessor().getValues(theElement);
if (values == null || values.isEmpty()) { if (values == null || values.isEmpty()) {
@ -392,7 +399,8 @@ public class XmlParser extends BaseParser implements IParser {
} }
} }
private void encodeCompositeElementToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException, DataFormatException { private void encodeCompositeElementToStreamWriter(IElement theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws XMLStreamException,
DataFormatException {
encodeExtensionsIfPresent(theEventWriter, theElement); encodeExtensionsIfPresent(theEventWriter, theElement);
encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getExtensions()); encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getExtensions());
encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getChildren()); encodeCompositeElementChildrenToStreamWriter(theElement, theEventWriter, resDef.getChildren());
@ -419,7 +427,6 @@ public class XmlParser extends BaseParser implements IParser {
} }
} }
private void encodeResourceToXmlStreamWriter(IResource theResource, XMLStreamWriter theEventWriter, boolean theIncludeResourceId) throws XMLStreamException, DataFormatException { private void encodeResourceToXmlStreamWriter(IResource theResource, XMLStreamWriter theEventWriter, boolean theIncludeResourceId) throws XMLStreamException, DataFormatException {
super.containResourcesForEncoding(theResource); super.containResourcesForEncoding(theResource);
@ -449,7 +456,7 @@ public class XmlParser extends BaseParser implements IParser {
IElement nextValue = next.getValue(); IElement nextValue = next.getValue();
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition(); RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(nextValue.getClass()); String childName = extDef.getChildNameByDatatype(nextValue.getClass());
if (childName==null) { if (childName == null) {
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + nextValue.getClass().getCanonicalName()); throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + nextValue.getClass().getCanonicalName());
} }
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass()); BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(nextValue.getClass());
@ -579,7 +586,6 @@ public class XmlParser extends BaseParser implements IParser {
} }
} }
private void writeTagWithTextNode(XMLStreamWriter theEventWriter, String theElementName, StringDt theStringDt) throws XMLStreamException { private void writeTagWithTextNode(XMLStreamWriter theEventWriter, String theElementName, StringDt theStringDt) throws XMLStreamException {
theEventWriter.writeStartElement(theElementName); theEventWriter.writeStartElement(theElementName);
if (StringUtils.isNotBlank(theStringDt.getValue())) { if (StringUtils.isNotBlank(theStringDt.getValue())) {

View File

@ -10,11 +10,23 @@ import java.lang.annotation.Target;
* be populated with the "_include" values for a search param. * be populated with the "_include" values for a search param.
* <p> * <p>
* Only one parameter may be annotated with this annotation, and that * Only one parameter may be annotated with this annotation, and that
* parameter should be of type Collection, List, or Set. * parameter should be one of the following:
* </p> * </p>
* <ul>
* <li><code>Collection&lt;PathSpecification&gt;</code></li>
* <li><code>List&lt;PathSpecification&gt;</code></li>
* <li><code>Set&lt;PathSpecification&gt;</code></li>
* </ul>
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(value= {ElementType.PARAMETER}) @Target(value= {ElementType.PARAMETER})
public @interface Include { public @interface Include {
/**
* Optional parameter, if provided the server will only allow the values
* within the given set. If an _include parameter is passed to the server
* which does not match any allowed values the server will return an error.
*/
String[] allow() default {};
} }

View File

@ -106,6 +106,9 @@ public class SearchMethodBinding extends BaseMethodBinding {
IParameter param = myParameters.get(i); IParameter param = myParameters.get(i);
String[] value = parameterValues.get(param.getName()); String[] value = parameterValues.get(param.getName());
if (value == null || value.length == 0) { if (value == null || value.length == 0) {
if (param.handlesMissing()) {
params[i] = param.parse(new ArrayList<List<String>>(0));
}
continue; continue;
} }

View File

@ -8,14 +8,20 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public interface IParameter { public interface IParameter {
public abstract List<List<String>> encode(Object theObject) throws InternalErrorException; List<List<String>> encode(Object theObject) throws InternalErrorException;
public abstract String getName(); String getName();
public abstract Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException; Object parse(List<List<String>> theString) throws InternalErrorException, InvalidRequestException;
public abstract boolean isRequired(); boolean isRequired();
public abstract SearchParamTypeEnum getParamType(); /**
* Parameter should return true if {@link #parse(List)} should be called even
* if the query string contained no values for the given parameter
*/
boolean handlesMissing();
SearchParamTypeEnum getParamType();
} }

View File

@ -3,19 +3,29 @@ package ca.uhn.fhir.rest.param;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.TreeSet;
import ca.uhn.fhir.model.api.PathSpecification; import ca.uhn.fhir.model.api.PathSpecification;
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum; import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.rest.annotation.Include;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class IncludeParameter implements IParameter { public class IncludeParameter implements IParameter {
private Class<? extends Collection<PathSpecification>> myInstantiableCollectionType; private Class<? extends Collection<PathSpecification>> myInstantiableCollectionType;
private HashSet<String> myAllow;
public IncludeParameter(Class<? extends Collection<PathSpecification>> theInstantiableCollectionType) { public IncludeParameter(Include theAnnotation, Class<? extends Collection<PathSpecification>> theInstantiableCollectionType) {
myInstantiableCollectionType = theInstantiableCollectionType; myInstantiableCollectionType = theInstantiableCollectionType;
if (theAnnotation.allow().length > 0) {
myAllow = new HashSet<String>();
for (String next : theAnnotation.allow()) {
myAllow.add(next);
}
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -53,7 +63,13 @@ public class IncludeParameter implements IParameter {
throw new InvalidRequestException("'OR' query parameters (values containing ',') are not supported in _include parameters"); throw new InvalidRequestException("'OR' query parameters (values containing ',') are not supported in _include parameters");
} }
retVal.add(new PathSpecification(nextParamList.get(0))); String value = nextParamList.get(0);
if (myAllow != null) {
if (!myAllow.contains(value)) {
throw new InvalidRequestException("Invalid _include parameter value: '" + value + "'. Valid values are: " + new TreeSet<String>(myAllow));
}
}
retVal.add(new PathSpecification(value));
} }
return retVal; return retVal;
@ -69,4 +85,9 @@ public class IncludeParameter implements IParameter {
return null; return null;
} }
@Override
public boolean handlesMissing() {
return true;
}
} }

View File

@ -100,6 +100,8 @@ public class SearchParameter implements IParameter {
throw new ConfigurationException("Unknown search parameter type: " + type); throw new ConfigurationException("Unknown search parameter type: " + type);
} }
// NB: Once this is enabled, we should return true from handlesMissing if
// it's a collection type
// if (theInnerCollectionType != null) { // if (theInnerCollectionType != null) {
// this.parser = new CollectionBinder(this.parser, theInnerCollectionType); // this.parser = new CollectionBinder(this.parser, theInnerCollectionType);
// } // }
@ -115,4 +117,9 @@ public class SearchParameter implements IParameter {
return myParamType; return myParamType;
} }
@Override
public boolean handlesMissing() {
return false;
}
} }

View File

@ -16,6 +16,8 @@ public class Constants {
public static final Set<String> FORMAT_VAL_XML; public static final Set<String> FORMAT_VAL_XML;
public static final Set<String> FORMAT_VAL_JSON; public static final Set<String> FORMAT_VAL_JSON;
public static final Map<String, EncodingUtil> FORMAT_VAL_TO_ENCODING; public static final Map<String, EncodingUtil> FORMAT_VAL_TO_ENCODING;
public static final String CT_XML = "application/xml";
public static final String CT_JSON = "application/json";
static { static {
Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>(); Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();

View File

@ -2,16 +2,20 @@ package ca.uhn.fhir.rest.server;
public enum EncodingUtil { public enum EncodingUtil {
XML(Constants.CT_FHIR_XML, Constants.CT_ATOM_XML), XML(Constants.CT_FHIR_XML, Constants.CT_ATOM_XML, Constants.CT_XML),
JSON(Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON); JSON(Constants.CT_FHIR_JSON, Constants.CT_FHIR_JSON, Constants.CT_JSON)
;
private String myResourceContentType; private String myResourceContentType;
private String myBundleContentType; private String myBundleContentType;
private String myBrowserFriendlyContentType;
EncodingUtil(String theResourceContentType, String theBundleContentType) { EncodingUtil(String theResourceContentType, String theBundleContentType, String theBrowserFriendlyContentType) {
myResourceContentType = theResourceContentType; myResourceContentType = theResourceContentType;
myBundleContentType = theBundleContentType; myBundleContentType = theBundleContentType;
myBrowserFriendlyContentType = theBrowserFriendlyContentType;
} }
public String getBundleContentType() { public String getBundleContentType() {
@ -22,4 +26,8 @@ public enum EncodingUtil {
return myResourceContentType; return myResourceContentType;
} }
public String getBrowserFriendlyBundleContentType() {
return myBrowserFriendlyContentType;
}
} }

View File

@ -40,11 +40,24 @@ import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
public abstract class RestfulServer extends HttpServlet { public abstract class RestfulServer extends HttpServlet {
private static final String PARAM_HISTORY = "_history";
private static final String PARAM_PRETTY = "_pretty";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServer.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServer.class);
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private FhirContext myFhirContext; private FhirContext myFhirContext;
private boolean myUseBrowserFriendlyContentTypes;
/**
* If set to <code>true</code> (default is false), the server will use browser friendly
* content-types (instead of standard FHIR ones) when it detects that the request
* is coming from a browser instead of a FHIR
*/
public void setUseBrowserFriendlyContentTypes(boolean theUseBrowserFriendlyContentTypes) {
myUseBrowserFriendlyContentTypes = theUseBrowserFriendlyContentTypes;
}
private Map<Class<? extends IResource>, IResourceProvider> myTypeToProvider = new HashMap<Class<? extends IResource>, IResourceProvider>(); private Map<Class<? extends IResource>, IResourceProvider> myTypeToProvider = new HashMap<Class<? extends IResource>, IResourceProvider>();
@ -81,7 +94,6 @@ public abstract class RestfulServer extends HttpServlet {
handleRequest(SearchMethodBinding.RequestType.DELETE, request, response); handleRequest(SearchMethodBinding.RequestType.DELETE, request, response);
} }
@Override @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
handleRequest(SearchMethodBinding.RequestType.GET, request, response); handleRequest(SearchMethodBinding.RequestType.GET, request, response);
@ -102,7 +114,6 @@ public abstract class RestfulServer extends HttpServlet {
handleRequest(SearchMethodBinding.RequestType.PUT, request, response); handleRequest(SearchMethodBinding.RequestType.PUT, request, response);
} }
private void findResourceMethods(IResourceProvider theProvider) throws Exception { private void findResourceMethods(IResourceProvider theProvider) throws Exception {
Class<? extends IResource> resourceType = theProvider.getResourceType(); Class<? extends IResource> resourceType = theProvider.getResourceType();
@ -131,12 +142,11 @@ public abstract class RestfulServer extends HttpServlet {
} }
} }
public FhirContext getFhirContext() { public FhirContext getFhirContext() {
return myFhirContext; return myFhirContext;
} }
private IParser getNewParser(EncodingUtil theResponseEncoding) { private IParser getNewParser(EncodingUtil theResponseEncoding, boolean thePrettyPrint) {
IParser parser; IParser parser;
switch (theResponseEncoding) { switch (theResponseEncoding) {
case JSON: case JSON:
@ -147,7 +157,7 @@ public abstract class RestfulServer extends HttpServlet {
parser = myFhirContext.newXmlParser(); parser = myFhirContext.newXmlParser();
break; break;
} }
return parser; return parser.setPrettyPrint(thePrettyPrint);
} }
public Collection<ResourceBinding> getResourceBindings() { public Collection<ResourceBinding> getResourceBindings() {
@ -160,8 +170,7 @@ public abstract class RestfulServer extends HttpServlet {
public abstract Collection<IResourceProvider> getResourceProviders(); public abstract Collection<IResourceProvider> getResourceProviders();
/** /**
* This method should be overridden to provide a security manager instance. * This method should be overridden to provide a security manager instance. By default, returns null.
* By default, returns null.
*/ */
public ISecurityManager getSecurityManager() { public ISecurityManager getSecurityManager() {
return null; return null;
@ -182,9 +191,16 @@ public abstract class RestfulServer extends HttpServlet {
securityManager.authenticate(request); securityManager.authenticate(request);
} }
String uaHeader = request.getHeader("user-agent");
boolean requestIsBrowser = false;
if (uaHeader != null && uaHeader.contains("Mozilla")) {
requestIsBrowser = true;
}
String resourceName = null; String resourceName = null;
String requestFullPath = StringUtils.defaultString(request.getRequestURI()); String requestFullPath = StringUtils.defaultString(request.getRequestURI());
// String contextPath = StringUtils.defaultString(request.getContextPath()); // String contextPath = StringUtils.defaultString(request.getContextPath());
String servletPath = StringUtils.defaultString(request.getServletPath()); String servletPath = StringUtils.defaultString(request.getServletPath());
StringBuffer requestUrl = request.getRequestURL(); StringBuffer requestUrl = request.getRequestURL();
String servletContextPath = ""; String servletContextPath = "";
@ -208,13 +224,27 @@ public abstract class RestfulServer extends HttpServlet {
requestPath = requestPath.substring(1); requestPath = requestPath.substring(1);
} }
int contextIndex = requestUrl.indexOf(servletPath); int contextIndex;
if (servletPath.length()==0) {
contextIndex = requestUrl.indexOf(requestPath);
}else {
contextIndex = requestUrl.indexOf(servletPath);
}
String fhirServerBase = requestUrl.substring(0, contextIndex + servletPath.length()); String fhirServerBase = requestUrl.substring(0, contextIndex + servletPath.length());
String completeUrl = StringUtils.isNotBlank(request.getQueryString()) ? requestUrl + "?" + request.getQueryString() : requestUrl.toString(); String completeUrl = StringUtils.isNotBlank(request.getQueryString()) ? requestUrl + "?" + request.getQueryString() : requestUrl.toString();
Map<String, String[]> params = new HashMap<String, String[]>(request.getParameterMap()); Map<String, String[]> params = new HashMap<String, String[]>(request.getParameterMap());
EncodingUtil responseEncoding = determineResponseEncoding(request, params); EncodingUtil responseEncoding = determineResponseEncoding(request, params);
String[] pretty = params.remove(PARAM_PRETTY);
boolean prettyPrint = false;
if (pretty != null && pretty.length > 0) {
if ("true".equals(pretty[0])) {
prettyPrint = true;
}
}
StringTokenizer tok = new StringTokenizer(requestPath, "/"); StringTokenizer tok = new StringTokenizer(requestPath, "/");
if (!tok.hasMoreTokens()) { if (!tok.hasMoreTokens()) {
throw new MethodNotFoundException("No resource name specified"); throw new MethodNotFoundException("No resource name specified");
@ -244,7 +274,7 @@ public abstract class RestfulServer extends HttpServlet {
if (tok.hasMoreTokens()) { if (tok.hasMoreTokens()) {
String nextString = tok.nextToken(); String nextString = tok.nextToken();
if (nextString.startsWith("_history")) { if (nextString.startsWith(PARAM_HISTORY)) {
if (tok.hasMoreTokens()) { if (tok.hasMoreTokens()) {
versionId = new IdDt(tok.nextToken()); versionId = new IdDt(tok.nextToken());
} else { } else {
@ -271,7 +301,7 @@ public abstract class RestfulServer extends HttpServlet {
List<IResource> result = resourceMethod.invokeServer(resourceBinding.getResourceProvider(), id, versionId, params); List<IResource> result = resourceMethod.invokeServer(resourceBinding.getResourceProvider(), id, versionId, params);
switch (resourceMethod.getReturnType()) { switch (resourceMethod.getReturnType()) {
case BUNDLE: case BUNDLE:
streamResponseAsBundle(response, result, responseEncoding, fhirServerBase, completeUrl); streamResponseAsBundle(response, result, responseEncoding, fhirServerBase, completeUrl, prettyPrint, requestIsBrowser);
break; break;
case RESOURCE: case RESOURCE:
if (result.size() == 0) { if (result.size() == 0) {
@ -279,7 +309,7 @@ public abstract class RestfulServer extends HttpServlet {
} else if (result.size() > 1) { } else if (result.size() > 1) {
throw new InternalErrorException("Method returned multiple resources"); throw new InternalErrorException("Method returned multiple resources");
} }
streamResponseAsResource(response, result.get(0), resourceBinding, responseEncoding); streamResponseAsResource(response, result.get(0), responseEncoding, prettyPrint, requestIsBrowser);
break; break;
} }
// resourceMethod.get // resourceMethod.get
@ -344,16 +374,25 @@ public abstract class RestfulServer extends HttpServlet {
} }
} }
private void streamResponseAsBundle(HttpServletResponse theHttpResponse, List<IResource> theResult, EncodingUtil theResponseEncoding, String theFhirServerBase, String theCompleteUrl) throws IOException { private void streamResponseAsBundle(HttpServletResponse theHttpResponse, List<IResource> theResult, EncodingUtil theResponseEncoding, String theServerBase, String theCompleteUrl,
boolean thePrettyPrint, boolean theRequestIsBrowser) throws IOException {
assert theServerBase.endsWith("/");
theHttpResponse.setStatus(200); theHttpResponse.setStatus(200);
theHttpResponse.setContentType(theResponseEncoding.getBundleContentType());
if (theRequestIsBrowser && myUseBrowserFriendlyContentTypes) {
theHttpResponse.setContentType(theResponseEncoding.getBrowserFriendlyBundleContentType());
} else {
theHttpResponse.setContentType(theResponseEncoding.getBundleContentType());
}
theHttpResponse.setCharacterEncoding("UTF-8"); theHttpResponse.setCharacterEncoding("UTF-8");
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.getAuthorName().setValue(getClass().getCanonicalName()); bundle.getAuthorName().setValue(getClass().getCanonicalName());
bundle.getBundleId().setValue(UUID.randomUUID().toString()); bundle.getBundleId().setValue(UUID.randomUUID().toString());
bundle.getPublished().setToCurrentTimeInLocalTimeZone(); bundle.getPublished().setToCurrentTimeInLocalTimeZone();
bundle.getLinkBase().setValue(theFhirServerBase); bundle.getLinkBase().setValue(theServerBase);
bundle.getLinkSelf().setValue(theCompleteUrl); bundle.getLinkSelf().setValue(theCompleteUrl);
for (IResource next : theResult) { for (IResource next : theResult) {
@ -361,23 +400,55 @@ public abstract class RestfulServer extends HttpServlet {
bundle.getEntries().add(entry); bundle.getEntries().add(entry);
entry.setResource(next); entry.setResource(next);
RuntimeResourceDefinition def = myFhirContext.getResourceDefinition(next);
if (next.getId() != null && StringUtils.isNotBlank(next.getId().getValue())) {
entry.getEntryId().setValue(next.getId().getValue());
entry.getTitle().setValue(def.getName() + " " + next.getId().getValue());
StringBuilder b = new StringBuilder();
b.append(theServerBase);
b.append(def.getName());
b.append('/');
b.append(next.getId().getValue());
boolean haveQ = false;
if (thePrettyPrint) {
b.append('?').append(PARAM_PRETTY).append("=true");
haveQ = true;
}
if (theResponseEncoding == EncodingUtil.JSON) {
if (!haveQ) {
b.append('?');
haveQ = true;
} else {
b.append('&');
}
b.append(Constants.PARAM_FORMAT).append("=json");
}
entry.getLinkSelf().setValue(b.toString());
}
} }
bundle.getTotalResults().setValue(theResult.size()); bundle.getTotalResults().setValue(theResult.size());
PrintWriter writer = theHttpResponse.getWriter(); PrintWriter writer = theHttpResponse.getWriter();
getNewParser(theResponseEncoding).encodeBundleToWriter(bundle, writer); getNewParser(theResponseEncoding, thePrettyPrint).encodeBundleToWriter(bundle, writer);
writer.close(); writer.close();
} }
private void streamResponseAsResource(HttpServletResponse theHttpResponse, IResource theResource, ResourceBinding theResourceBinding, EncodingUtil theResponseEncoding) throws IOException { private void streamResponseAsResource(HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser) throws IOException {
theHttpResponse.setStatus(200); theHttpResponse.setStatus(200);
theHttpResponse.setContentType(theResponseEncoding.getResourceContentType()); if (theRequestIsBrowser && myUseBrowserFriendlyContentTypes) {
theHttpResponse.setContentType(theResponseEncoding.getBrowserFriendlyBundleContentType());
} else {
theHttpResponse.setContentType(theResponseEncoding.getBundleContentType());
}
theHttpResponse.setCharacterEncoding("UTF-8"); theHttpResponse.setCharacterEncoding("UTF-8");
PrintWriter writer = theHttpResponse.getWriter(); PrintWriter writer = theHttpResponse.getWriter();
getNewParser(theResponseEncoding).encodeResourceToWriter(theResource, writer); getNewParser(theResponseEncoding, thePrettyPrint).encodeResourceToWriter(theResource, writer);
writer.close(); writer.close();
} }

View File

@ -10,7 +10,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import ch.qos.logback.core.joran.action.ParamAction;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.model.api.PathSpecification; import ca.uhn.fhir.model.api.PathSpecification;
import ca.uhn.fhir.rest.annotation.Include; import ca.uhn.fhir.rest.annotation.Include;
@ -89,7 +88,7 @@ public class Util {
} }
Class<? extends Collection<PathSpecification>> instantiableCollectionType = (Class<? extends Collection<PathSpecification>>) CollectionBinder.getInstantiableCollectionType(innerCollectionType, "Method '" + method.getName() + "'"); Class<? extends Collection<PathSpecification>> instantiableCollectionType = (Class<? extends Collection<PathSpecification>>) CollectionBinder.getInstantiableCollectionType(innerCollectionType, "Method '" + method.getName() + "'");
param = new IncludeParameter(instantiableCollectionType); param = new IncludeParameter((Include) nextAnnotation, instantiableCollectionType);
} else { } else {
continue; continue;
} }

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.rest.server.provider; package ca.uhn.fhir.rest.server.provider;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -22,13 +21,11 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.Metadata; import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.ReadMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding; import ca.uhn.fhir.rest.method.SearchMethodBinding;
import ca.uhn.fhir.rest.param.IParameter; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.util.DatatypeUtil;
import ca.uhn.fhir.util.ExtensionConstants; import ca.uhn.fhir.util.ExtensionConstants;
import ca.uhn.fhir.util.VersionUtil; import ca.uhn.fhir.util.VersionUtil;

View File

@ -19,6 +19,8 @@ public class ElementUtil {
if (!isEmpty((List<? extends IElement>) next)) { if (!isEmpty((List<? extends IElement>) next)) {
return false; return false;
} }
} else if (next instanceof String && (!((String)next).isEmpty())) {
return false;
} else if (next != null && !((IElement) next).isEmpty()) { } else if (next != null && !((IElement) next).isEmpty()) {
return false; return false;
} }

View File

@ -94,7 +94,7 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
@Override @Override
public void writeStartElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException { public void writeStartElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
indentAndAdd(); indentAndAdd();
myTarget.writeStartElement(thePrefix, theNamespaceURI, theLocalName); myTarget.writeStartElement(thePrefix, theLocalName, theNamespaceURI);
} }
@Override @Override

View File

@ -138,8 +138,11 @@ public Class<? extends IResource> getResourceType() {
//START SNIPPET: pathSpec //START SNIPPET: pathSpec
@Search() @Search()
public List<DiagnosticReport> getDiagnosticReport( @Required(name=DiagnosticReport.SP_IDENTIFIER) IdentifierDt theIdentifier, public List<DiagnosticReport> getDiagnosticReport(
@Include Set<PathSpecification> theIncludes ) { @Required(name=DiagnosticReport.SP_IDENTIFIER)
IdentifierDt theIdentifier,
@Include(allow= {"DiagnosticReport.subject"})
Set<PathSpecification> theIncludes ) {
List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>(); List<DiagnosticReport> retVal = new ArrayList<DiagnosticReport>();
// Assume this method exists and loads the report from the DB // Assume this method exists and loads the report from the DB

View File

@ -300,7 +300,7 @@
</p> </p>
<p> <p>
Invoking a client of thie type involves the following syntax: Invoking a client of this type involves the following syntax:
</p> </p>
<macro name="snippet"> <macro name="snippet">
@ -328,6 +328,11 @@
<param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" /> <param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" />
</macro> </macro>
<p>
Example URL to invoke this method:<br/>
<code>http://fhir.example.com/DiagnosticReport?subject.identifier=7000135&amp;_include=DiagnosticReport.subject</code>
</p>
</subsection> </subsection>
</section> </section>

View File

@ -27,6 +27,8 @@ import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient; import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.resource.Specimen; import ca.uhn.fhir.model.dstu.resource.Specimen;
import ca.uhn.fhir.model.dstu.resource.ValueSet; import ca.uhn.fhir.model.dstu.resource.ValueSet;
import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum;
import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.DecimalDt; import ca.uhn.fhir.model.primitive.DecimalDt;
@ -44,6 +46,33 @@ public class XmlParserTest {
} }
@Test
public void testEncodeBoundCode() throws IOException {
Patient patient = new Patient();
patient.addAddress().setUse(AddressUseEnum.HOME);
patient.getGender().setValueAsEnum(AdministrativeGenderCodesEnum.M);
String val = new FhirContext().newXmlParser().encodeResourceToString(patient);
ourLog.info(val);
}
@Test
public void testEncodeBundleResultCount() throws IOException {
Bundle b = new Bundle();
b.getTotalResults().setValue(123);
String val = new FhirContext().newXmlParser().setPrettyPrint(true).encodeBundleToString(b);
ourLog.info(val);
assertThat(val, StringContains.containsString("<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">123</os:totalResults>"));
}
@Test @Test
public void testParseContainedResources() throws IOException { public void testParseContainedResources() throws IOException {

View File

@ -1,9 +1,9 @@
package ca.uhn.fhir.rest.server; package ca.uhn.fhir.rest.server;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.OutputStreamWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -23,13 +23,15 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.core.IsNot;
import org.hamcrest.core.StringContains;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.junit.experimental.theories.Theories;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.PathSpecification; import ca.uhn.fhir.model.api.PathSpecification;
import ca.uhn.fhir.model.dstu.composite.CodingDt; import ca.uhn.fhir.model.dstu.composite.CodingDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt; import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
@ -104,12 +106,60 @@ public class ResfulServerMethodTest {
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
Patient patient = (Patient) bundle.getEntries().get(0).getResource(); BundleEntry entry0 = bundle.getEntries().get(0);
Patient patient = (Patient) entry0.getResource();
assertEquals("include1", patient.getCommunication().get(0).getText().getValue()); assertEquals("include1", patient.getCommunication().get(0).getText().getValue());
assertEquals("include2", patient.getAddress().get(0).getLine().get(0).getValue()); assertEquals("include2", patient.getAddress().get(0).getLine().get(0).getValue());
assertEquals("include3", patient.getAddress().get(1).getLine().get(0).getValue()); assertEquals("include3", patient.getAddress().get(1).getLine().get(0).getValue());
} }
@Test
public void testSearchWithIncludesNone() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
// Make sure there is no crash
assertEquals(200, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchWithIncludesBad() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include4");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info("Response was:\n{}", responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testEntryLinkSelf() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include3");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
BundleEntry entry0 = bundle.getEntries().get(0);
assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkSelf().getValue());
assertEquals("1", entry0.getEntryId().getValue());
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include3&_format=json");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
assertEquals(200, status.getStatusLine().getStatusCode());
bundle = ourCtx.newJsonParser().parseBundle(responseContent);
entry0 = bundle.getEntries().get(0);
assertEquals("http://localhost:" + ourPort + "/Patient/1?_format=json", entry0.getLinkSelf().getValue());
}
@Test @Test
public void testSearchAllProfiles() throws Exception { public void testSearchAllProfiles() throws Exception {
@ -216,17 +266,17 @@ public class ResfulServerMethodTest {
assertEquals("urn:bbb|bbb", patient.getIdentifier().get(2).getValueAsQueryToken()); assertEquals("urn:bbb|bbb", patient.getIdentifier().get(2).getValueAsQueryToken());
} }
// @Test // @Test
// public void testSearchByComplex() throws Exception { // public void testSearchByComplex() throws Exception {
// //
// HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?Patient.identifier=urn:oid:2.16.840.1.113883.3.239.18.148%7C7000135&name=urn:oid:1.3.6.1.4.1.12201.102.5%7C522&date="); // HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?Patient.identifier=urn:oid:2.16.840.1.113883.3.239.18.148%7C7000135&name=urn:oid:1.3.6.1.4.1.12201.102.5%7C522&date=");
// HttpResponse status = ourClient.execute(httpGet); // HttpResponse status = ourClient.execute(httpGet);
// //
// String responseContent = IOUtils.toString(status.getEntity().getContent()); // String responseContent = IOUtils.toString(status.getEntity().getContent());
// ourLog.info("Response was:\n{}", responseContent); // ourLog.info("Response was:\n{}", responseContent);
// //
// assertEquals(200, status.getStatusLine().getStatusCode()); // assertEquals(200, status.getStatusLine().getStatusCode());
// } // }
@Test @Test
public void testSearchByDob() throws Exception { public void testSearchByDob() throws Exception {
@ -404,6 +454,31 @@ public class ResfulServerMethodTest {
} }
@Test
public void testPrettyPrint() throws Exception {
// HttpPost httpPost = new HttpPost("http://localhost:" + ourPort +
// "/Patient/1");
// httpPost.setEntity(new StringEntity("test",
// ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
assertThat(responseContent, StringContains.containsString("<identifier><use"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_pretty=false");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
assertThat(responseContent, StringContains.containsString("<identifier><use"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_pretty=true");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
assertThat(responseContent, IsNot.not(StringContains.containsString("<identifier><use")));
}
@Test @Test
public void testGetById() throws Exception { public void testGetById() throws Exception {
@ -510,6 +585,7 @@ public class ResfulServerMethodTest {
patient.getName().get(0).addFamily("Test"); patient.getName().get(0).addFamily("Test");
patient.getName().get(0).addGiven("PatientOne"); patient.getName().get(0).addGiven("PatientOne");
patient.getGender().setText("M"); patient.getGender().setText("M");
patient.getId().setValue("1");
idToPatient.put("1", patient); idToPatient.put("1", patient);
} }
{ {
@ -522,13 +598,15 @@ public class ResfulServerMethodTest {
patient.getName().get(0).addFamily("Test"); patient.getName().get(0).addFamily("Test");
patient.getName().get(0).addGiven("PatientTwo"); patient.getName().get(0).addGiven("PatientTwo");
patient.getGender().setText("F"); patient.getGender().setText("F");
patient.getId().setValue("2");
idToPatient.put("2", patient); idToPatient.put("2", patient);
} }
return idToPatient; return idToPatient;
} }
@Search() @Search()
public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString, @Include List<PathSpecification> theIncludes) { public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString,
@Include(allow= {"include1","include2", "include3"}) List<PathSpecification> theIncludes) {
Patient next = getIdToPatient().get("1"); Patient next = getIdToPatient().get("1");
next.addCommunication().setText(theString.getValue()); next.addCommunication().setText(theString.getValue());
@ -553,11 +631,8 @@ public class ResfulServerMethodTest {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public List<Patient> findDiagnosticReportsByPatient( public List<Patient> findDiagnosticReportsByPatient(@Required(name = "Patient.identifier") IdentifierDt thePatientId, @Required(name = DiagnosticReport.SP_NAME) CodingListParam theNames,
@Required(name="Patient.identifier") IdentifierDt thePatientId, @Optional(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception {
@Required(name=DiagnosticReport.SP_NAME) CodingListParam theNames,
@Optional(name=DiagnosticReport.SP_DATE) DateRangeParam theDateRange
) throws Exception {
return Collections.emptyList(); return Collections.emptyList();
} }