Narrative generator now working
This commit is contained in:
parent
4953c5629c
commit
082ebb64c1
|
@ -35,6 +35,9 @@
|
|||
|
||||
---------
|
||||
Issues:
|
||||
|
||||
* Submit _narrative parameter as enhancement suggestion
|
||||
|
||||
* Need to be able to bind Identifier.system to a set of allowable values in a profile. Graeme
|
||||
has suggested making value[x] repeatable in the profile definition
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||
|
||||
public interface IResource extends ICompositeElement {
|
||||
|
||||
|
@ -15,6 +16,8 @@ public interface IResource extends ICompositeElement {
|
|||
* </p>
|
||||
* TODO: document contained resources and link there
|
||||
*/
|
||||
public ContainedDt getContained();
|
||||
ContainedDt getContained();
|
||||
|
||||
NarrativeDt getText();
|
||||
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import ca.uhn.fhir.model.api.IElement;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||
|
||||
@ResourceDef(name="Binary", profile="http://hl7.org/fhir/profiles/Binary", id="binary")
|
||||
public class Binary extends BaseElement implements IResource {
|
||||
|
@ -36,4 +37,9 @@ public class Binary extends BaseElement implements IResource {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NarrativeDt getText() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -227,8 +227,11 @@ public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGe
|
|||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResourceAsStream(TemplateProcessingParameters theTemplateProcessingParameters, String theResourceName) {
|
||||
String template = myDatatypeClassNameToNarrativeTemplate.get(theResourceName);
|
||||
public InputStream getResourceAsStream(TemplateProcessingParameters theTemplateProcessingParameters, String theClassName) {
|
||||
String template = myDatatypeClassNameToNarrativeTemplate.get(theClassName);
|
||||
if (template==null) {
|
||||
throw new NullPointerException("No narrative template exists for datatype: " +theClassName);
|
||||
}
|
||||
return new ReaderInputStream(new StringReader(template));
|
||||
}
|
||||
}
|
||||
|
@ -255,10 +258,9 @@ public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGe
|
|||
final Object value = expression.execute(configuration, theArguments);
|
||||
|
||||
Context context = new Context();
|
||||
QuantityDt datatype = new QuantityDt();
|
||||
context.setVariable("resource", value);
|
||||
|
||||
String result = myDatatypeTemplateEngine.process(datatype.getClass().getCanonicalName(), context);
|
||||
String result = myDatatypeTemplateEngine.process(value.getClass().getCanonicalName(), context);
|
||||
Document dom = DOMUtils.getXhtmlDOMFor(new StringReader(result));
|
||||
|
||||
theElement.removeAttribute(theAttributeName);
|
||||
|
|
|
@ -19,6 +19,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
|
||||
public abstract class BaseParser implements IParser {
|
||||
|
||||
private boolean mySuppressNarratives;
|
||||
|
||||
@SuppressWarnings("cast")
|
||||
@Override
|
||||
public <T extends IResource> T parseResource(Class<T> theResourceType, String theMessageString) {
|
||||
|
@ -81,4 +83,19 @@ public abstract class BaseParser implements IParser {
|
|||
throw new DataFormatException(nextChild + " has no child of type " + type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser setSuppressNarratives(boolean theSuppressNarratives) {
|
||||
mySuppressNarratives=theSuppressNarratives;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>), narratives will not be included in the
|
||||
* encoded values.
|
||||
*/
|
||||
public boolean getSuppressNarratives() {
|
||||
return mySuppressNarratives;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -32,4 +32,10 @@ public interface IParser {
|
|||
|
||||
IParser setPrettyPrint(boolean thePrettyPrint);
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>), narratives will not be included in the
|
||||
* encoded values.
|
||||
*/
|
||||
IParser setSuppressNarratives(boolean theSuppressNarratives);
|
||||
|
||||
}
|
|
@ -252,7 +252,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
hashSet.add("id");
|
||||
hashSet.add("updated");
|
||||
hashSet.add("published");
|
||||
BUNDLE_TEXTNODE_CHILDREN=Collections.unmodifiableSet(hashSet);
|
||||
BUNDLE_TEXTNODE_CHILDREN = Collections.unmodifiableSet(hashSet);
|
||||
}
|
||||
|
||||
private void parseBundleChildren(JsonObject theObject, ParserState<?> theState) {
|
||||
|
@ -439,7 +439,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
return eventWriter;
|
||||
}
|
||||
|
||||
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef, String theChildName) throws IOException {
|
||||
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition<?> theChildDef,
|
||||
String theChildName) throws IOException {
|
||||
|
||||
switch (theChildDef.getChildType()) {
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
|
@ -518,12 +519,20 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML: {
|
||||
if (!getSuppressNarratives()) {
|
||||
XhtmlDt dt = (XhtmlDt) theValue;
|
||||
if (theChildName != null) {
|
||||
theWriter.write(theChildName, dt.getValueAsString());
|
||||
} else {
|
||||
theWriter.write(dt.getValueAsString());
|
||||
}
|
||||
} else {
|
||||
if (theChildName != null) {
|
||||
// do nothing
|
||||
} else {
|
||||
theWriter.writeNull();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UNDECL_EXT:
|
||||
|
@ -533,13 +542,14 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
|
||||
}
|
||||
|
||||
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, List<? extends BaseRuntimeChildDefinition> theChildren) throws IOException {
|
||||
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter,
|
||||
List<? extends BaseRuntimeChildDefinition> theChildren) throws IOException {
|
||||
for (BaseRuntimeChildDefinition nextChild : theChildren) {
|
||||
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
|
||||
INarrativeGenerator gen = myContext.getNarrativeGenerator();
|
||||
if (gen != null) {
|
||||
NarrativeDt narr = gen.generateNarrative(theResDef.getResourceProfile(), theResource);
|
||||
if (narr!=null) {
|
||||
if (narr != null) {
|
||||
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
|
||||
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
|
||||
|
@ -672,7 +682,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef) throws IOException, DataFormatException {
|
||||
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter,
|
||||
BaseRuntimeElementCompositeDefinition<?> resDef) throws IOException, DataFormatException {
|
||||
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement);
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions());
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren());
|
||||
|
@ -707,7 +718,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
theEventWriter.writeEnd();
|
||||
}
|
||||
|
||||
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, List<UndeclaredExtension> extensions, String theTagName) throws IOException {
|
||||
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, List<UndeclaredExtension> extensions, String theTagName)
|
||||
throws IOException {
|
||||
if (extensions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -473,7 +473,7 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
}
|
||||
|
||||
private void encodeXhtml(XhtmlDt theDt, XMLStreamWriter theEventWriter) throws XMLStreamException {
|
||||
if (theDt == null || theDt.getValue() == null) {
|
||||
if (theDt == null || theDt.getValue() == null || getSuppressNarratives()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,14 @@ import ca.uhn.fhir.model.api.IResource;
|
|||
@Target(value=ElementType.METHOD)
|
||||
public @interface Search {
|
||||
|
||||
/**
|
||||
* If specified, this the name for the Named Query
|
||||
*
|
||||
* @see See the FHIR specification section on
|
||||
* <a href="http://www.hl7.org/implement/standards/fhir/search.html#advanced">named queries</a>
|
||||
*/
|
||||
String queryName() default "";
|
||||
|
||||
/**
|
||||
* The return type for this search method. This generally does not need
|
||||
* to be populated for a server implementation, since servers will return
|
||||
|
|
|
@ -88,7 +88,8 @@ public abstract class BaseMethodBinding {
|
|||
if (read != null) {
|
||||
return new ReadMethodBinding(methodReturnTypeEnum, returnType, theMethod);
|
||||
} else if (search != null) {
|
||||
return new SearchMethodBinding(methodReturnTypeEnum, returnType, theMethod);
|
||||
String queryName = search.queryName();
|
||||
return new SearchMethodBinding(methodReturnTypeEnum, returnType, theMethod, queryName);
|
||||
} else if (conformance != null) {
|
||||
return new ConformanceMethodBinding(methodReturnTypeEnum, returnType, theMethod);
|
||||
} else {
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
|
@ -9,7 +11,7 @@ public class Request {
|
|||
|
||||
private IdDt myId;
|
||||
private String myOperation;
|
||||
private Set<String> myParameterNames;
|
||||
private Map<String, String[]> myParameterNames;
|
||||
private RequestType myRequestType;
|
||||
private String myResourceName;
|
||||
private IdDt myVersion;
|
||||
|
@ -22,7 +24,7 @@ public class Request {
|
|||
return myOperation;
|
||||
}
|
||||
|
||||
public Set<String> getParameterNames() {
|
||||
public Map<String, String[]> getParameterNames() {
|
||||
return myParameterNames;
|
||||
}
|
||||
|
||||
|
@ -46,8 +48,8 @@ public class Request {
|
|||
myOperation = theOperation;
|
||||
}
|
||||
|
||||
public void setParameterNames(Set<String> theParameterNames) {
|
||||
myParameterNames = theParameterNames;
|
||||
public void setParameterNames(Map<String, String[]> theParams) {
|
||||
myParameterNames = theParams;
|
||||
}
|
||||
|
||||
public void setRequestType(RequestType theRequestType) {
|
||||
|
@ -62,11 +64,15 @@ public class Request {
|
|||
myVersion = theVersion;
|
||||
}
|
||||
|
||||
public static Request withResourceAndParams(String theResourceName, RequestType theRequestType, Set<String> theParamNamess) {
|
||||
public static Request withResourceAndParams(String theResourceName, RequestType theRequestType, Set<String> theParamNames) {
|
||||
Request retVal = new Request();
|
||||
retVal.setResourceName(theResourceName);
|
||||
retVal.setParameterNames(theParamNamess);
|
||||
retVal.setRequestType(theRequestType);
|
||||
Map<String, String[]> paramNames = new HashMap<String, String[]>();
|
||||
for (String next : theParamNames) {
|
||||
paramNames.put(next, new String[0]);
|
||||
}
|
||||
retVal.setParameterNames(paramNames);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,15 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.client.GetClientInvocation;
|
||||
import ca.uhn.fhir.rest.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -27,16 +30,16 @@ import ca.uhn.fhir.util.QueryUtil;
|
|||
public class SearchMethodBinding extends BaseMethodBinding {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchMethodBinding.class);
|
||||
|
||||
private Method method;
|
||||
|
||||
private Method myMethod;
|
||||
private Class<?> myDeclaredResourceType;
|
||||
private List<IParameter> myParameters;
|
||||
private String myQueryName;
|
||||
|
||||
public SearchMethodBinding(MethodReturnTypeEnum theMethodReturnTypeEnum, Class<? extends IResource> theReturnResourceType, Method theMethod) {
|
||||
public SearchMethodBinding(MethodReturnTypeEnum theMethodReturnTypeEnum, Class<? extends IResource> theReturnResourceType, Method theMethod, String theQueryName) {
|
||||
super(theMethodReturnTypeEnum, theReturnResourceType);
|
||||
this.method = theMethod;
|
||||
this.myMethod = theMethod;
|
||||
this.myParameters = Util.getResourceParameters(theMethod);
|
||||
|
||||
this.myQueryName = StringUtils.defaultIfBlank(theQueryName, null);
|
||||
this.myDeclaredResourceType = theMethod.getReturnType();
|
||||
}
|
||||
|
||||
|
@ -45,7 +48,7 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
}
|
||||
|
||||
public Method getMethod() {
|
||||
return method;
|
||||
return myMethod;
|
||||
}
|
||||
|
||||
public List<IParameter> getParameters() {
|
||||
|
@ -59,10 +62,15 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
|
||||
@Override
|
||||
public GetClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
assert theArgs.length == myParameters.size() : "Wrong number of arguments: " + theArgs.length;
|
||||
assert (myQueryName == null || ((theArgs != null ? theArgs.length : 0) == myParameters.size())) : "Wrong number of arguments: " + theArgs;
|
||||
|
||||
Map<String, List<String>> args = new LinkedHashMap<String, List<String>>();
|
||||
|
||||
if (myQueryName != null) {
|
||||
args.put(Constants.PARAM_QUERY, Collections.singletonList(myQueryName));
|
||||
}
|
||||
|
||||
if (theArgs != null) {
|
||||
for (int idx = 0; idx < theArgs.length; idx++) {
|
||||
Object object = theArgs[idx];
|
||||
IParameter nextParam = myParameters.get(idx);
|
||||
|
@ -90,12 +98,14 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return new GetClientInvocation(args, getResourceName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> parameterValues) throws InvalidRequestException, InternalErrorException {
|
||||
public List<IResource> invokeServer(IResourceProvider theResourceProvider, IdDt theId, IdDt theVersionId, Map<String, String[]> parameterValues) throws InvalidRequestException,
|
||||
InternalErrorException {
|
||||
assert theId == null;
|
||||
assert theVersionId == null;
|
||||
|
||||
|
@ -110,11 +120,11 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
continue;
|
||||
}
|
||||
|
||||
List<List<String>> paramList=new ArrayList<List<String>>(value.length);
|
||||
List<List<String>> paramList = new ArrayList<List<String>>(value.length);
|
||||
for (String nextParam : value) {
|
||||
if (nextParam.contains(",")==false) {
|
||||
if (nextParam.contains(",") == false) {
|
||||
paramList.add(Collections.singletonList(nextParam));
|
||||
}else {
|
||||
} else {
|
||||
paramList.add(QueryUtil.splitQueryStringByCommasIgnoreEscape(nextParam));
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +135,7 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
|
||||
Object response;
|
||||
try {
|
||||
response = this.method.invoke(theResourceProvider, params);
|
||||
response = this.myMethod.invoke(theResourceProvider, params);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new InternalErrorException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
|
@ -141,7 +151,7 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
@Override
|
||||
public boolean matches(Request theRequest) {
|
||||
if (!theRequest.getResourceName().equals(getResourceName())) {
|
||||
ourLog.trace("Method {} doesn't match because resource name {} != {}", method.getName(), theRequest.getResourceName(), getResourceName());
|
||||
ourLog.trace("Method {} doesn't match because resource name {} != {}", myMethod.getName(), theRequest.getResourceName(), getResourceName());
|
||||
return false;
|
||||
}
|
||||
if (theRequest.getId() != null || theRequest.getVersion() != null) {
|
||||
|
@ -161,20 +171,35 @@ public class SearchMethodBinding extends BaseMethodBinding {
|
|||
for (int i = 0; i < this.myParameters.size(); i++) {
|
||||
IParameter temp = this.myParameters.get(i);
|
||||
methodParamsTemp.add(temp.getName());
|
||||
if (temp.isRequired() && !theRequest.getParameterNames().contains(temp.getName())) {
|
||||
ourLog.trace("Method {} doesn't match param '{}' is not present", method.getName(), temp.getName());
|
||||
if (temp.isRequired() && !theRequest.getParameterNames().containsKey(temp.getName())) {
|
||||
ourLog.trace("Method {} doesn't match param '{}' is not present", myMethod.getName(), temp.getName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean retVal = methodParamsTemp.containsAll(theRequest.getParameterNames());
|
||||
if (myQueryName != null) {
|
||||
String[] queryNameValues = theRequest.getParameterNames().get(Constants.PARAM_QUERY);
|
||||
if (queryNameValues != null && StringUtils.isNotBlank(queryNameValues[0])) {
|
||||
String queryName = queryNameValues[0];
|
||||
if (!myQueryName.equals(queryName)) {
|
||||
ourLog.trace("Query name does not match {}", myQueryName);
|
||||
return false;
|
||||
} else {
|
||||
methodParamsTemp.add(Constants.PARAM_QUERY);
|
||||
}
|
||||
} else {
|
||||
ourLog.trace("Query name does not match {}", myQueryName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean retVal = methodParamsTemp.containsAll(theRequest.getParameterNames().keySet());
|
||||
|
||||
ourLog.trace("Method {} matches: {}", method.getName(), retVal);
|
||||
ourLog.trace("Method {} matches: {}", myMethod.getName(), retVal);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public void setMethod(Method method) {
|
||||
this.method = method;
|
||||
this.myMethod = method;
|
||||
}
|
||||
|
||||
public void setParameters(List<IParameter> parameters) {
|
||||
|
|
|
@ -18,6 +18,11 @@ public class Constants {
|
|||
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";
|
||||
public static final String CT_HTML = "text/html";
|
||||
public static final String PARAM_NARRATIVE = "_narrative";
|
||||
public static final String PARAM_HISTORY = "_history";
|
||||
public static final String PARAM_PRETTY = "_pretty";
|
||||
public static final String PARAM_QUERY = "_query";
|
||||
|
||||
static {
|
||||
Map<String, EncodingUtil> valToEncoding = new HashMap<String, EncodingUtil>();
|
||||
|
|
|
@ -41,8 +41,6 @@ import ca.uhn.fhir.rest.server.provider.ServerProfileProvider;
|
|||
|
||||
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);
|
||||
|
||||
|
@ -164,7 +162,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
return myFhirContext;
|
||||
}
|
||||
|
||||
private IParser getNewParser(EncodingUtil theResponseEncoding, boolean thePrettyPrint) {
|
||||
private IParser getNewParser(EncodingUtil theResponseEncoding, boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode) {
|
||||
IParser parser;
|
||||
switch (theResponseEncoding) {
|
||||
case JSON:
|
||||
|
@ -175,7 +173,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
parser = myFhirContext.newXmlParser();
|
||||
break;
|
||||
}
|
||||
return parser.setPrettyPrint(thePrettyPrint);
|
||||
return parser.setPrettyPrint(thePrettyPrint).setSuppressNarratives(theNarrativeMode == NarrativeModeEnum.SUPPRESS);
|
||||
}
|
||||
|
||||
public Collection<ResourceBinding> getResourceBindings() {
|
||||
|
@ -202,6 +200,16 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
return new ServerProfileProvider(getFhirContext());
|
||||
}
|
||||
|
||||
public enum NarrativeModeEnum {
|
||||
NORMAL,
|
||||
SUPPRESS,
|
||||
ONLY;
|
||||
|
||||
public static NarrativeModeEnum valueOfCaseInsensitive(String theCode) {
|
||||
return valueOf(NarrativeModeEnum.class, theCode.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
protected void handleRequest(SearchMethodBinding.RequestType requestType, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||
try {
|
||||
|
||||
|
@ -260,7 +268,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
Map<String, String[]> params = new HashMap<String, String[]>(request.getParameterMap());
|
||||
EncodingUtil responseEncoding = determineResponseEncoding(request, params);
|
||||
|
||||
String[] pretty = params.remove(PARAM_PRETTY);
|
||||
String[] pretty = params.remove(Constants.PARAM_PRETTY);
|
||||
boolean prettyPrint = false;
|
||||
if (pretty != null && pretty.length > 0) {
|
||||
if ("true".equals(pretty[0])) {
|
||||
|
@ -268,6 +276,15 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
}
|
||||
}
|
||||
|
||||
String[] narrative = params.remove(Constants.PARAM_NARRATIVE);
|
||||
NarrativeModeEnum narrativeMode = null;
|
||||
if (narrative != null && narrative.length > 0) {
|
||||
narrativeMode = NarrativeModeEnum.valueOfCaseInsensitive(narrative[0]);
|
||||
}
|
||||
if (narrativeMode==null) {
|
||||
narrativeMode = NarrativeModeEnum.NORMAL;
|
||||
}
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(requestPath, "/");
|
||||
if (!tok.hasMoreTokens()) {
|
||||
throw new MethodNotFoundException("No resource name specified");
|
||||
|
@ -297,7 +314,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
if (tok.hasMoreTokens()) {
|
||||
String nextString = tok.nextToken();
|
||||
if (nextString.startsWith(PARAM_HISTORY)) {
|
||||
if (nextString.startsWith(Constants.PARAM_HISTORY)) {
|
||||
if (tok.hasMoreTokens()) {
|
||||
versionId = new IdDt(tok.nextToken());
|
||||
} else {
|
||||
|
@ -313,7 +330,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
r.setId(id);
|
||||
r.setVersion(versionId);
|
||||
r.setOperation(operation);
|
||||
r.setParameterNames(params.keySet());
|
||||
r.setParameterNames(params);
|
||||
r.setRequestType(requestType);
|
||||
|
||||
BaseMethodBinding resourceMethod = resourceBinding.getMethod(r);
|
||||
|
@ -324,7 +341,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
List<IResource> result = resourceMethod.invokeServer(resourceBinding.getResourceProvider(), id, versionId, params);
|
||||
switch (resourceMethod.getReturnType()) {
|
||||
case BUNDLE:
|
||||
streamResponseAsBundle(response, result, responseEncoding, fhirServerBase, completeUrl, prettyPrint, requestIsBrowser);
|
||||
streamResponseAsBundle(response, result, responseEncoding, fhirServerBase, completeUrl, prettyPrint, requestIsBrowser, narrativeMode);
|
||||
break;
|
||||
case RESOURCE:
|
||||
if (result.size() == 0) {
|
||||
|
@ -332,7 +349,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
} else if (result.size() > 1) {
|
||||
throw new InternalErrorException("Method returned multiple resources");
|
||||
}
|
||||
streamResponseAsResource(response, result.get(0), responseEncoding, prettyPrint, requestIsBrowser);
|
||||
streamResponseAsResource(response, result.get(0), responseEncoding, prettyPrint, requestIsBrowser, narrativeMode);
|
||||
break;
|
||||
}
|
||||
// resourceMethod.get
|
||||
|
@ -409,13 +426,15 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
}
|
||||
|
||||
private void streamResponseAsBundle(HttpServletResponse theHttpResponse, List<IResource> theResult, EncodingUtil theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
boolean thePrettyPrint, boolean theRequestIsBrowser) throws IOException {
|
||||
boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
|
||||
assert !theServerBase.endsWith("/");
|
||||
|
||||
theHttpResponse.setStatus(200);
|
||||
|
||||
if (theRequestIsBrowser && myUseBrowserFriendlyContentTypes) {
|
||||
theHttpResponse.setContentType(theResponseEncoding.getBrowserFriendlyBundleContentType());
|
||||
} else if (theNarrativeMode == NarrativeModeEnum.ONLY) {
|
||||
theHttpResponse.setContentType(Constants.CT_HTML);
|
||||
} else {
|
||||
theHttpResponse.setContentType(theResponseEncoding.getBundleContentType());
|
||||
}
|
||||
|
@ -449,7 +468,7 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
b.append(next.getId().getValue());
|
||||
boolean haveQ = false;
|
||||
if (thePrettyPrint) {
|
||||
b.append('?').append(PARAM_PRETTY).append("=true");
|
||||
b.append('?').append(Constants.PARAM_PRETTY).append("=true");
|
||||
haveQ = true;
|
||||
}
|
||||
if (theResponseEncoding == EncodingUtil.JSON) {
|
||||
|
@ -461,6 +480,9 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
}
|
||||
b.append(Constants.PARAM_FORMAT).append("=json");
|
||||
}
|
||||
if (theNarrativeMode != NarrativeModeEnum.NORMAL) {
|
||||
b.append(Constants.PARAM_NARRATIVE).append("=").append(theNarrativeMode.name().toLowerCase());
|
||||
}
|
||||
entry.getLinkSelf().setValue(b.toString());
|
||||
}
|
||||
}
|
||||
|
@ -469,26 +491,41 @@ public abstract class RestfulServer extends HttpServlet {
|
|||
|
||||
PrintWriter writer = theHttpResponse.getWriter();
|
||||
try {
|
||||
getNewParser(theResponseEncoding, thePrettyPrint).encodeBundleToWriter(bundle, writer);
|
||||
} finally {
|
||||
if (theNarrativeMode == NarrativeModeEnum.ONLY) {
|
||||
for (IResource next : theResult) {
|
||||
writer.append(next.getText().getDiv().getValueAsString());
|
||||
writer.append("<hr/>");
|
||||
}
|
||||
} else {
|
||||
getNewParser(theResponseEncoding, thePrettyPrint, theNarrativeMode).encodeBundleToWriter(bundle, writer);
|
||||
} } finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void streamResponseAsResource(HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser)
|
||||
private void streamResponseAsResource(HttpServletResponse theHttpResponse, IResource theResource, EncodingUtil theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode)
|
||||
throws IOException {
|
||||
|
||||
theHttpResponse.setStatus(200);
|
||||
if (theRequestIsBrowser && myUseBrowserFriendlyContentTypes) {
|
||||
theHttpResponse.setContentType(theResponseEncoding.getBrowserFriendlyBundleContentType());
|
||||
} else if (theNarrativeMode == NarrativeModeEnum.ONLY) {
|
||||
theHttpResponse.setContentType(Constants.CT_HTML);
|
||||
} else {
|
||||
theHttpResponse.setContentType(theResponseEncoding.getBundleContentType());
|
||||
theHttpResponse.setContentType(theResponseEncoding.getResourceContentType());
|
||||
}
|
||||
theHttpResponse.setCharacterEncoding("UTF-8");
|
||||
|
||||
PrintWriter writer = theHttpResponse.getWriter();
|
||||
getNewParser(theResponseEncoding, thePrettyPrint).encodeResourceToWriter(theResource, writer);
|
||||
try {
|
||||
if (theNarrativeMode == NarrativeModeEnum.ONLY) {
|
||||
writer.append(theResource.getText().getDiv().getValueAsString());
|
||||
} else {
|
||||
getNewParser(theResponseEncoding, thePrettyPrint, theNarrativeMode).encodeResourceToWriter(theResource, writer);
|
||||
}
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<div th:switch="${resource.precision.name()}">
|
||||
<th:block th:case="YEAR" th:text="${#dates.format(resource.value,'yyyy')}">22 March 2012</th:block>
|
||||
<th:block th:case="MONTH" th:text="${#dates.format(resource.value,'MMMM yyyy')}"></th:block>
|
||||
<th:block th:case="DAY" th:text="${#dates.format(resource.value,'dd MMMM yyyy')}"></th:block>
|
||||
<th:block th:case="SECOND" th:text="${#dates.format(resource.value,'dd MMMM yyyy HH:mm:ss')}"></th:block>
|
||||
<th:block th:case="MILLI" th:text="${#dates.format(resource.value,'dd MMMM yyyy HH:mm:ss')}"></th:block>
|
||||
</div>
|
|
@ -19,6 +19,23 @@
|
|||
<!--/*--> Complete Blood Count <!--*/-->
|
||||
</div>
|
||||
|
||||
<table class="hapiPropertyTable">
|
||||
<tbody>
|
||||
<tr th:if="${not resource.status.empty}">
|
||||
<td>Status</td>
|
||||
<td th:text="${resource.status.value}">Final</td>
|
||||
</tr>
|
||||
<tr th:if="${not resource.issued.empty}">
|
||||
<td>Issued</td>
|
||||
<td th:narrative="${resource.issued}">22 March 2012</td>
|
||||
</tr>
|
||||
<tr th:if="${not resource.conclusion.empty}">
|
||||
<td>Conclusion</td>
|
||||
<td th:narrative="${resource.conclusion}">This is the conclusion text</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="hapiTableOfValues" th:if="${not #lists.isEmpty(resource.result)} and ${resource.result[0].resource != null}">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -53,13 +70,15 @@
|
|||
</td>
|
||||
<td th:text="${result.resource.status.value}">final</td>
|
||||
</tr>
|
||||
<tr th:class="${rowStat.odd}? 'hapiTableOfValuesRowOdd' : 'hapiTableOfValuesRowEven'" class="hapiTableOfValuesRowOdd">
|
||||
<tr th:if="${not result.resource.comments.empty}" th:class="${rowStat.odd}? 'hapiTableOfValuesRowOdd' : 'hapiTableOfValuesRowEven'" class="hapiTableOfValuesRowOdd">
|
||||
<td th:text="${result.resource.comments.value}" colspan="5">This is a comment</td>
|
||||
</tr>
|
||||
<!--/*-->
|
||||
|
||||
<!--/* The following are just examples that don't appear in the generated narrative -->
|
||||
<tr class="hapiTableOfValuesRowEven"><td>Lkc</td><td>198 g/L</td><td>H</td><td>78 g/L - 99 g/L</td><td>final</td></tr>
|
||||
<tr class="hapiTableOfValuesRowEven"><td colspan="5">Yet another comment</td></tr>
|
||||
<!--*/-->
|
||||
|
||||
</th:block>
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
@ -1,9 +1,19 @@
|
|||
|
||||
datetime.dtclass=ca.uhn.fhir.model.primitive.DateTimeDt
|
||||
datetime.dtnarrative=classpath:ca/uhn/fhir/narrative/DateTimeDt.html
|
||||
|
||||
diagnosticreport.profile=http://hl7.org/fhir/profiles/DiagnosticReport
|
||||
diagnosticreport.narrative=classpath:ca/uhn/fhir/narrative/DiagnosticReport.html
|
||||
|
||||
# Instant uses DateTime narrative
|
||||
instant.dtclass=ca.uhn.fhir.model.primitive.InstantDt
|
||||
instant.dtnarrative=classpath:ca/uhn/fhir/narrative/DateTimeDt.html
|
||||
|
||||
patient.profile=http://hl7.org/fhir/profiles/Patient
|
||||
patient.narrative=classpath:ca/uhn/fhir/narrative/Patient.html
|
||||
|
||||
quantity.dtclass=ca.uhn.fhir.model.dstu.composite.QuantityDt
|
||||
quantity.dtnarrative=classpath:ca/uhn/fhir/narrative/QuantityDt.html
|
||||
|
||||
string.dtclass=ca.uhn.fhir.model.primitive.StringDt
|
||||
string.dtnarrative=classpath:ca/uhn/fhir/narrative/StringDt.html
|
|
@ -11,11 +11,13 @@ public class ExampleRestfulClient {
|
|||
|
||||
//START SNIPPET: client
|
||||
public static void main(String[] args) {
|
||||
FhirContext ctx = new FhirContext(Patient.class);
|
||||
FhirContext ctx = new FhirContext();
|
||||
String serverBase = "http://foo.com/fhirServerBase";
|
||||
|
||||
// Create the client
|
||||
RestfulClientImpl client = ctx.newRestfulClient(RestfulClientImpl.class, serverBase);
|
||||
|
||||
// The client is now ready for use!
|
||||
// Try the client out! This method will invoke the server
|
||||
List<Patient> patients = client.getPatient(new StringDt("SMITH"));
|
||||
|
||||
}
|
||||
|
|
|
@ -54,8 +54,14 @@ public class MyPatient extends Patient {
|
|||
|
||||
/********
|
||||
* Accessors and mutators follow
|
||||
*
|
||||
* IMPORTANT:
|
||||
* Each extension is required to have an getter/accessor and a stter/mutator.
|
||||
* You are highly recommended to create getters which create instances if they
|
||||
* do not already exist, since this is how the rest of the HAPI FHIR API works.
|
||||
********/
|
||||
|
||||
/** Getter for important dates */
|
||||
public List<DateTimeDt> getImportantDates() {
|
||||
if (myImportantDates==null) {
|
||||
myImportantDates = new ArrayList<DateTimeDt>();
|
||||
|
@ -63,14 +69,20 @@ public class MyPatient extends Patient {
|
|||
return myImportantDates;
|
||||
}
|
||||
|
||||
/** Getter for pet name */
|
||||
public StringDt getPetName() {
|
||||
if (myPetName == null) {
|
||||
myPetName = new StringDt();
|
||||
}
|
||||
return myPetName;
|
||||
}
|
||||
|
||||
/** Setter for important dates */
|
||||
public void setImportantDates(List<DateTimeDt> theImportantDates) {
|
||||
myImportantDates = theImportantDates;
|
||||
}
|
||||
|
||||
/** Setter for pet name */
|
||||
public void setPetName(StringDt thePetName) {
|
||||
myPetName = thePetName;
|
||||
}
|
||||
|
|
|
@ -67,6 +67,15 @@ public List<Patient> searchByLastName(@Required(name=Patient.SP_FAMILY) StringDt
|
|||
}
|
||||
//END SNIPPET: searchStringParam
|
||||
|
||||
//START SNIPPET: searchNamedQuery
|
||||
@Search(queryName="namedQuery1")
|
||||
public List<Patient> searchByNamedQuery(@Required(name="someparam") StringDt theSomeParam) {
|
||||
List<Patient> retVal = new ArrayList<Patient>();
|
||||
// ...populate...
|
||||
return retVal;
|
||||
}
|
||||
//END SNIPPET: searchNamedQuery
|
||||
|
||||
//START SNIPPET: searchIdentifierParam
|
||||
@Search()
|
||||
public List<Patient> searchByIdentifier(@Required(name=Patient.SP_IDENTIFIER) IdentifierDt theId) {
|
||||
|
|
|
@ -228,6 +228,19 @@
|
|||
<code>http://fhir.example.com/Observation?name=urn:fakenames|123,urn:fakenames|456</code>
|
||||
</p>
|
||||
|
||||
<h4>AND Relationship Query Parameters</h4>
|
||||
|
||||
<p>
|
||||
To accept a composite parameter, use a parameter type which implements the
|
||||
<a href="./apidocs/ca/uhn/fhir/model/api/IQueryParameterAnd.html">IQueryParameterAnd</a>
|
||||
interface.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
See the section below on <a href="#DATE_RANGES">date ranges</a> for
|
||||
one example of an AND parameter.
|
||||
</p>
|
||||
|
||||
</subsection>
|
||||
|
||||
<subsection name="Date Parameters - Simple">
|
||||
|
@ -270,6 +283,7 @@
|
|||
|
||||
</subsection>
|
||||
|
||||
<a name="DATE_RANGES"/>
|
||||
<subsection name="Date Parameters - Ranges">
|
||||
|
||||
<p>
|
||||
|
@ -335,6 +349,31 @@
|
|||
|
||||
</subsection>
|
||||
|
||||
<subsection name="Named Queries (_query)">
|
||||
|
||||
<p>
|
||||
FHIR supports <a href="http://www.hl7.org/implement/standards/fhir/search.html#advanced">named queries</a>,
|
||||
which may have specific behaviour defined. The following example shows how to create a Search
|
||||
operation with a name.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This operation can only be invoked by explicitly specifying the given query name
|
||||
in the request URL. Note that the query does not need to take any parameters.
|
||||
</p>
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="searchNamedQuery" />
|
||||
<param name="file" value="src/site/example/java/example/RestfulPatientResourceProviderMore.java" />
|
||||
</macro>
|
||||
|
||||
<p>
|
||||
Example URL to invoke this method:<br/>
|
||||
<code>http://fhir.example.com/Patient?_query=namedQuery1&someparam=value</code>
|
||||
</p>
|
||||
|
||||
</subsection>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ package ca.uhn.fhir.context;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import javax.naming.OperationNotSupportedException;
|
||||
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IExtension;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
@ -11,6 +13,7 @@ import ca.uhn.fhir.model.api.annotation.Extension;
|
|||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.dstu.composite.ContainedDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
|
||||
import ca.uhn.fhir.model.primitive.DateDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
|
@ -232,8 +235,12 @@ public class ResourceWithExtensionsA implements IResource {
|
|||
|
||||
@Override
|
||||
public ContainedDt getContained() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NarrativeDt getText() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
}
|
|
@ -17,7 +17,9 @@ import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
|||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu.valueset.DiagnosticReportStatusEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ObservationStatusEnum;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
|
||||
public class ThymeleafNarrativeGeneratorTest {
|
||||
|
@ -64,8 +66,12 @@ public class ThymeleafNarrativeGeneratorTest {
|
|||
@Test
|
||||
public void testGenerateDiagnosticReportWithObservations() throws DataFormatException, IOException {
|
||||
DiagnosticReport value = new DiagnosticReport();
|
||||
value.getName().setText("Some Diagnostic Report");
|
||||
|
||||
value.getIssued().setValueAsString("2011-02-22T11:13:00");
|
||||
value.setStatus(DiagnosticReportStatusEnum.FINAL);
|
||||
|
||||
value.getName().setText("Some Diagnostic Report");
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.getName().addCoding().setCode("1938HB").setDisplay("Hemoglobin");
|
||||
obs.setValue(new QuantityDt(null, 2.223, "mg/L"));
|
||||
|
@ -75,7 +81,12 @@ public class ThymeleafNarrativeGeneratorTest {
|
|||
|
||||
ResourceReferenceDt result = value.addResult();
|
||||
result.setResource(obs);
|
||||
|
||||
}
|
||||
{
|
||||
Observation obs = new Observation();
|
||||
obs.setValue(new StringDt("HELLO!"));
|
||||
value.addResult().setResource(obs);
|
||||
}
|
||||
NarrativeDt generateNarrative = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value);
|
||||
String output = generateNarrative.getDiv().getValueAsString();
|
||||
|
||||
|
|
|
@ -64,8 +64,9 @@ public class JsonParserTest {
|
|||
public void testNarrativeGeneration() throws DataFormatException, IOException {
|
||||
|
||||
Patient patient = new Patient();
|
||||
|
||||
patient.addName().addFamily("Smith");
|
||||
Organization org = new Organization();
|
||||
patient.getManagingOrganization().setResource(org);
|
||||
|
||||
INarrativeGenerator gen = mock(INarrativeGenerator.class);
|
||||
XhtmlDt xhtmlDt = new XhtmlDt("<div>help</div>");
|
||||
|
|
|
@ -268,6 +268,42 @@ public class ClientTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNamedQueryOneParam() throws Exception {
|
||||
|
||||
String msg = getPatientFeedWithOneResult();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
client.getPatientOneParam(new StringDt("BB"));
|
||||
|
||||
assertEquals("http://foo/Patient?_query=someQueryOneParam¶m1=BB", capt.getValue().getURI().toString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNamedQueryNoParams() throws Exception {
|
||||
|
||||
String msg = getPatientFeedWithOneResult();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
client.getPatientNoParams();
|
||||
|
||||
assertEquals("http://foo/Patient?_query=someQueryNoParams", capt.getValue().getURI().toString());
|
||||
|
||||
}
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
//@formatter:off
|
||||
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
|
||||
|
|
|
@ -44,4 +44,10 @@ public interface ITestClient extends IBasicClient {
|
|||
@Search()
|
||||
public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString, @Include List<PathSpecification> theIncludes);
|
||||
|
||||
@Search(queryName="someQueryNoParams")
|
||||
public Patient getPatientNoParams();
|
||||
|
||||
@Search(queryName="someQueryOneParam")
|
||||
public Patient getPatientOneParam(@Required(name="param1") StringDt theParam);
|
||||
|
||||
}
|
||||
|
|
|
@ -546,6 +546,47 @@ public class ResfulServerMethodTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchNamedNoParams() 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/?_query=someQueryNoParams");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Patient patient = (Patient) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource();
|
||||
assertEquals("someQueryNoParams", patient.getName().get(1).getFamilyAsSingleString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNamedOneParam() 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/?_query=someQueryOneParam¶m1=AAAA");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Patient patient = (Patient) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource();
|
||||
assertEquals("AAAA", patient.getName().get(1).getFamilyAsSingleString());
|
||||
|
||||
}
|
||||
|
||||
public static class DummyRestfulServer extends RestfulServer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -604,6 +645,20 @@ public class ResfulServerMethodTest {
|
|||
return idToPatient;
|
||||
}
|
||||
|
||||
@Search(queryName="someQueryNoParams")
|
||||
public Patient getPatientNoParams() {
|
||||
Patient next = getIdToPatient().get("1");
|
||||
next.addName().addFamily("someQueryNoParams");
|
||||
return next;
|
||||
}
|
||||
|
||||
@Search(queryName="someQueryOneParam")
|
||||
public Patient getPatientOneParam(@Required(name="param1") StringDt theParam) {
|
||||
Patient next = getIdToPatient().get("1");
|
||||
next.addName().addFamily(theParam.getValue());
|
||||
return next;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient getPatientWithIncludes(@Required(name = "withIncludes") StringDt theString,
|
||||
@Include(allow= {"include1","include2", "include3"}) List<PathSpecification> theIncludes) {
|
||||
|
|
|
@ -24,7 +24,7 @@ public class ResourceMethodTest {
|
|||
|
||||
@Before
|
||||
public void before() throws NoSuchMethodException, SecurityException {
|
||||
rm = new SearchMethodBinding(MethodReturnTypeEnum.RESOURCE, Patient.class, ResourceMethodTest.class.getMethod("before"));
|
||||
rm = new SearchMethodBinding(MethodReturnTypeEnum.RESOURCE, Patient.class, ResourceMethodTest.class.getMethod("before"), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue