Lots more work getting the JPA tester working

This commit is contained in:
jamesagnew 2014-06-17 07:48:50 -04:00
parent e0ae780ff2
commit 5152f0ba9b
35 changed files with 1009 additions and 304 deletions

View File

@ -47,21 +47,23 @@ public class Tag extends BaseElement implements IElement {
}
public Tag(String theTerm) {
this(theTerm, null, (String) null);
this((String)null, theTerm, null);
}
public Tag(String theTerm, String theLabel, String theScheme) {
public Tag(String theScheme, String theTerm, String theLabel) {
myTerm = theTerm;
myLabel = theLabel;
myScheme = theScheme;
}
public Tag(String theTerm, String theLabel, URI theScheme) {
myTerm = theTerm;
myLabel = theLabel;
public Tag(URI theScheme, URI theTerm, String theLabel) {
if (theScheme != null) {
myScheme = theScheme.toASCIIString();
}
if (theTerm != null) {
myTerm = theTerm.toASCIIString();
}
myLabel = theLabel;
}
@Override
@ -147,10 +149,10 @@ public class Tag extends BaseElement implements IElement {
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE);
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("Scheme", myScheme);
b.append("Term", myTerm);
b.append("Label", myLabel);
b.append("Scheme", myScheme);
return b.toString();
}

View File

@ -30,7 +30,7 @@ public class TagList extends ArrayList<Tag> {
public static final String ELEMENT_NAME_LC = ELEMENT_NAME.toLowerCase();
public Tag addTag(String theScheme, String theTerm, String theLabel) {
Tag retVal = new Tag(theTerm, theLabel, theScheme);
Tag retVal = new Tag(theScheme, theTerm, theLabel);
add(retVal);
return retVal;
}

View File

@ -30,7 +30,7 @@ import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.parser.DataFormatException;
@DatatypeDef(name = "decimal")
public class DecimalDt extends BasePrimitive<BigDecimal> {
public class DecimalDt extends BasePrimitive<BigDecimal> implements Comparable<DecimalDt> {
private BigDecimal myValue;
@ -144,4 +144,18 @@ public class DecimalDt extends BasePrimitive<BigDecimal> {
return myValue.intValue();
}
@Override
public int compareTo(DecimalDt theObj) {
if (myValue == null && theObj.getValue() == null) {
return 0;
}
if (myValue != null && theObj.getValue() == null) {
return 1;
}
if (myValue == null && theObj.getValue() != null) {
return -1;
}
return myValue.compareTo(theObj.getValue());
}
}

View File

@ -55,6 +55,10 @@ public class IntegerDt extends BasePrimitive<Integer> {
setValueAsString(theIntegerAsString);
}
public IntegerDt(Long theCount) {
// TODO Auto-generated constructor stub
}
@Override
public Integer getValue() {
return myValue;

View File

@ -20,9 +20,12 @@ package ca.uhn.fhir.rest.client;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -38,14 +41,17 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.gclient.IClientExecutable;
import ca.uhn.fhir.rest.gclient.ICriterion;
import ca.uhn.fhir.rest.gclient.ICriterionInternal;
import ca.uhn.fhir.rest.gclient.IGetTags;
import ca.uhn.fhir.rest.gclient.IParam;
import ca.uhn.fhir.rest.gclient.IQuery;
import ca.uhn.fhir.rest.gclient.ISort;
@ -134,6 +140,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
return myLastRequest;
}
@Override
public IGetTags getTags() {
return new GetTagsInternal();
}
@Override
public <T extends IResource> Bundle history(final Class<T> theType, IdDt theIdDt, DateTimeDt theSince, Integer theLimit) {
String resourceName = theType != null ? toResourceName(theType) : null;
@ -216,10 +227,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
myLogRequestAndResponse = theLogRequestAndResponse;
}
private String toResourceName(Class<? extends IResource> theType) {
return myContext.getResourceDefinition(theType).getName();
}
@Override
public List<IResource> transaction(List<IResource> theResources) {
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(theResources, myContext);
@ -284,6 +291,68 @@ public class GenericClient extends BaseClient implements IGenericClient {
return vread(theType, new IdDt(theId), new IdDt(theVersionId));
}
private String toResourceName(Class<? extends IResource> theType) {
return myContext.getResourceDefinition(theType).getName();
}
private abstract class BaseClientExecutable<T extends IClientExecutable<?, ?>, Y> implements IClientExecutable<T, Y> {
private EncodingEnum myParamEncoding;
private Boolean myPrettyPrint;
private boolean myQueryLogRequestAndResponse;
@SuppressWarnings("unchecked")
@Override
public T andLogRequestAndResponse(boolean theLogRequestAndResponse) {
myQueryLogRequestAndResponse = theLogRequestAndResponse;
return (T) this;
}
@SuppressWarnings("unchecked")
@Override
public T encodedJson() {
myParamEncoding = EncodingEnum.JSON;
return (T) this;
}
@Override
public T encodedXml() {
myParamEncoding = EncodingEnum.XML;
return null;
}
@SuppressWarnings("unchecked")
@Override
public T prettyPrint() {
myPrettyPrint = true;
return (T) this;
}
protected void addParam(Map<String, List<String>> params, String parameterName, String parameterValue) {
if (!params.containsKey(parameterName)) {
params.put(parameterName, new ArrayList<String>());
}
params.get(parameterName).add(parameterValue);
}
protected <Z> Z invoke(Map<String, List<String>> theParams, IClientResponseHandler<Z> theHandler, HttpGetClientInvocation theInvocation) {
if (myParamEncoding != null) {
theParams.put(Constants.PARAM_FORMAT, Collections.singletonList(myParamEncoding.getFormatContentType()));
}
if (myPrettyPrint != null) {
theParams.put(Constants.PARAM_PRETTY, Collections.singletonList(myPrettyPrint.toString()));
}
if (isKeepResponses()) {
myLastRequest = theInvocation.asHttpRequest(getServerBase(), null, getEncoding());
}
Z resp = invokeClient(theHandler, theInvocation, myQueryLogRequestAndResponse || myLogRequestAndResponse);
return resp;
}
}
private final class BundleResponseHandler implements IClientResponseHandler<Bundle> {
private Class<? extends IResource> myType;
@ -303,17 +372,20 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
private class ForInternal implements IQuery {
private class ForInternal extends BaseClientExecutable<IQuery, Bundle> implements IQuery {
private List<ICriterionInternal> myCriterion = new ArrayList<ICriterionInternal>();
private List<Include> myInclude = new ArrayList<Include>();
private EncodingEnum myParamEncoding;
private Integer myParamLimit;
private boolean myQueryLogRequestAndResponse;
private final String myResourceName;
private final Class<? extends IResource> myResourceType;
private List<SortInternal> mySort = new ArrayList<SortInternal>();
public ForInternal() {
myResourceType = null;
myResourceName = null;
}
public ForInternal(Class<? extends IResource> theResourceType) {
myResourceType = theResourceType;
myResourceName = myContext.getResourceDefinition(theResourceType).getName();
@ -324,54 +396,21 @@ public class GenericClient extends BaseClient implements IGenericClient {
myResourceName = theResourceName;
}
public ForInternal() {
myResourceType = null;
myResourceName = null;
}
private void addParam(Map<String, List<String>> params, String parameterName, String parameterValue) {
if (!params.containsKey(parameterName)) {
params.put(parameterName, new ArrayList<String>());
}
params.get(parameterName).add(parameterValue);
}
@Override
public IQuery and(ICriterion theCriterion) {
myCriterion.add((ICriterionInternal) theCriterion);
return this;
}
@Override
public IQuery andLogRequestAndResponse(boolean theLogRequestAndResponse) {
myQueryLogRequestAndResponse = theLogRequestAndResponse;
return this;
}
@Override
public IQuery encodedJson() {
myParamEncoding = EncodingEnum.JSON;
return this;
}
@Override
public IQuery encodedXml() {
myParamEncoding = EncodingEnum.XML;
return null;
}
@Override
public Bundle execute() {
StringBuilder b = new StringBuilder();
b.append(getServerBase());
if (myResourceType != null) {
b.append('/');
b.append(myResourceType);
}
b.append('?');
Map<String, List<String>> params = new LinkedHashMap<String, List<String>>();
Map<String, List<String>> initial = createExtraParams();
if (initial != null) {
params.putAll(initial);
}
for (ICriterionInternal next : myCriterion) {
String parameterName = next.getParameterName();
String parameterValue = next.getParameterValue();
@ -386,23 +425,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
addParam(params, next.getParamName(), next.getParamValue());
}
if (myParamEncoding != null) {
addParam(params, Constants.PARAM_FORMAT, myParamEncoding.getFormatContentType());
}
if (myParamLimit != null) {
addParam(params, Constants.PARAM_COUNT, Integer.toString(myParamLimit));
}
HttpGetClientInvocation invocation = new HttpGetClientInvocation(params, myResourceName);
if (isKeepResponses()) {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
}
BundleResponseHandler binding = new BundleResponseHandler(myResourceType);
HttpGetClientInvocation invocation = new HttpGetClientInvocation(params, myResourceName);
Bundle resp = invokeClient(binding, invocation, myQueryLogRequestAndResponse || myLogRequestAndResponse);
return resp;
return invoke(params, binding, invocation);
}
@ -422,12 +452,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
return this;
}
@Override
public IQuery prettyPrint() {
setPrettyPrint(true);
return this;
}
@Override
public ISort sort() {
SortInternal retVal = new SortInternal(this);
@ -443,6 +467,72 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
private class GetTagsInternal extends BaseClientExecutable<IGetTags, TagList> implements IGetTags {
private String myResourceName;
private String myId;
private String myVersionId;
@Override
public TagList execute() {
Map<String, List<String>> params = new LinkedHashMap<String, List<String>>();
Map<String, List<String>> initial = createExtraParams();
if (initial != null) {
params.putAll(initial);
}
TagListResponseHandler binding = new TagListResponseHandler();
List<String> urlFragments = new ArrayList<String>();
if (isNotBlank(myResourceName)) {
urlFragments.add(myResourceName);
if (isNotBlank(myId)) {
urlFragments.add(myId);
if (isNotBlank(myVersionId)) {
urlFragments.add(Constants.PARAM_HISTORY);
urlFragments.add(myVersionId);
}
}
}
urlFragments.add(Constants.PARAM_TAGS);
HttpGetClientInvocation invocation = new HttpGetClientInvocation(params, urlFragments);
return invoke(params, binding, invocation);
}
@Override
public IGetTags forResource(Class<? extends IResource> theClass) {
setResourceClass(theClass);
return this;
}
private void setResourceClass(Class<? extends IResource> theClass) {
if (theClass != null) {
myResourceName = myContext.getResourceDefinition(theClass).getName();
} else {
myResourceName = null;
}
}
@Override
public IGetTags forResource(Class<? extends IResource> theClass, String theId) {
setResourceClass(theClass);
myId=theId;
return this;
}
@Override
public IGetTags forResource(Class<? extends IResource> theClass, String theId, String theVersionId) {
setResourceClass(theClass);
myId=theId;
myVersionId=theVersionId;
return this;
}
}
private final class OutcomeResponseHandler implements IClientResponseHandler<MethodOutcome> {
private final String myResourceName;
@ -459,6 +549,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
private class QueryInternal implements IUntypedQuery {
@Override
public IQuery forAllResources() {
return new ForInternal();
}
@Override
public IQuery forResource(Class<? extends IResource> theResourceType) {
return new ForInternal(theResourceType);
@ -469,11 +564,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
return new ForInternal(theResourceName);
}
@Override
public IQuery forAllResources() {
return new ForInternal();
}
}
private final class ResourceResponseHandler<T extends IResource> implements IClientResponseHandler<T> {
@ -533,4 +623,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
private final class TagListResponseHandler implements IClientResponseHandler<TagList> {
@Override
public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
IParser parser = respType.newParser(myContext);
return parser.parseTagList(theResponseReader);
}
}
}

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.gclient.IGetTags;
import ca.uhn.fhir.rest.gclient.IUntypedQuery;
public interface IGenericClient {
@ -220,4 +221,9 @@ public interface IGenericClient {
*/
void setLogRequestAndResponse(boolean theLogRequestAndResponse);
/**
* Fluent method for the "get tags" operation
*/
IGetTags getTags();
}

View File

@ -0,0 +1,20 @@
package ca.uhn.fhir.rest.gclient;
public interface IClientExecutable<T extends IClientExecutable<?,?>, Y> {
Y execute();
T encodedJson();
T encodedXml();
/**
* If set to true, the client will log the request and response to the SLF4J logger. This can be useful for
* debugging, but is generally not desirable in a production situation.
*/
T andLogRequestAndResponse(boolean theLogRequestAndResponse);
T prettyPrint();
}

View File

@ -0,0 +1,14 @@
package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
public interface IGetTags extends IClientExecutable<IGetTags, TagList> {
IGetTags forResource(Class<? extends IResource> theClass);
IGetTags forResource(Class<? extends IResource> theClass, String theId);
IGetTags forResource(Class<? extends IResource> theClass, String theId, String theVersionId);
}

View File

@ -23,30 +23,16 @@ package ca.uhn.fhir.rest.gclient;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.Include;
public interface IQuery {
public interface IQuery extends IClientExecutable<IQuery,Bundle> {
IQuery where(ICriterion theCriterion);
IQuery and(ICriterion theCriterion);
Bundle execute();
IQuery include(Include theIncludeManagingorganization);
IQuery encodedJson();
IQuery encodedXml();
ISort sort();
IQuery limitTo(int theLimitTo);
/**
* If set to true, the client will log the request and response to the SLF4J logger. This
* can be useful for debugging, but is generally not desirable in a production situation.
*/
IQuery andLogRequestAndResponse(boolean theLogRequestAndResponse);
IQuery prettyPrint();
}

View File

@ -324,10 +324,10 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') {
theBuffer.deleteCharAt(0);
}
theTagList.add(new Tag(term, label, scheme));
theTagList.add(new Tag(scheme, term, label));
parseTagValue(theTagList, theCompleteHeaderValue, theBuffer);
} else {
theTagList.add(new Tag(term, label, scheme));
theTagList.add(new Tag(scheme, term, label));
}
if (theBuffer.length() > 0) {

View File

@ -128,7 +128,10 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
}
BaseHttpClientInvocation retVal = createClientInvocation(theArgs, resource);
return retVal;
}
static void addTagsToPostOrPut(IResource resource, BaseHttpClientInvocation retVal) {
TagList list = (TagList) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
if (list != null) {
for (Tag tag : list) {
@ -137,8 +140,6 @@ abstract class BaseOutcomeReturningMethodBindingWithResourceParam extends BaseOu
}
}
}
return retVal;
}
}

View File

@ -56,10 +56,10 @@ public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
}
@Override
protected BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource resource) {
protected BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource theResource) {
FhirContext context = getContext();
BaseHttpClientInvocation retVal = createCreateInvocation(resource, context);
BaseHttpClientInvocation retVal = createCreateInvocation(theResource, context);
if (theArgs != null) {
for (int idx = 0; idx < theArgs.length; idx++) {
@ -71,14 +71,18 @@ public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
return retVal;
}
public static HttpPostClientInvocation createCreateInvocation(IResource resource, FhirContext context) {
RuntimeResourceDefinition def = context.getResourceDefinition(resource);
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, FhirContext theContext) {
RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
String resourceName = def.getName();
StringBuilder urlExtension = new StringBuilder();
urlExtension.append(resourceName);
return new HttpPostClientInvocation(context, resource, urlExtension.toString());
HttpPostClientInvocation retVal = new HttpPostClientInvocation(theContext, theResource, urlExtension.toString());
addTagsToPostOrPut(theResource, retVal);
return retVal;
}
@Override

View File

@ -45,6 +45,11 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
public HttpGetClientInvocation(Map<String, List<String>> theParameters, List<String> theUrlFragments) {
myParameters = theParameters;
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
public HttpGetClientInvocation(String theUrlPath) {
myParameters = new HashMap<String, List<String>>();
myUrlPath = theUrlPath;
@ -55,6 +60,12 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
public HttpGetClientInvocation(List<String> theUrlFragments) {
myParameters = new HashMap<String, List<String>>();
myUrlPath = StringUtils.join(theUrlFragments, '/');
}
public Map<String, List<String>> getParameters() {
return myParameters;
}
@ -92,9 +103,10 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
}
private boolean addQueryParameter(StringBuilder b, boolean first, String nextKey, String nextValue) {
if (first) {
boolean retVal = first;
if (retVal) {
b.append('?');
first = false;
retVal = false;
} else {
b.append('&');
}
@ -105,7 +117,7 @@ public class HttpGetClientInvocation extends BaseHttpClientInvocation {
} catch (UnsupportedEncodingException e) {
throw new ConfigurationException("Could not find UTF-8 encoding. This shouldn't happen.", e);
}
return first;
return retVal;
}
}

View File

@ -145,6 +145,9 @@ public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
retVal.addHeader(Constants.HEADER_CONTENT_LOCATION, b.toString());
}
}
addTagsToPostOrPut(theResource, retVal);
return retVal;
}

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.rest.server.provider;
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@ -58,6 +57,7 @@ public class ServerConformanceProvider {
private volatile Conformance myConformance;
private final RestfulServer myRestfulServer;
private boolean myCache = true;
public ServerConformanceProvider(RestfulServer theRestfulServer) {
myRestfulServer = theRestfulServer;
@ -65,7 +65,7 @@ public class ServerConformanceProvider {
@Metadata
public Conformance getServerConformance() {
if (myConformance != null) {
if (myConformance != null && myCache) {
return myConformance;
}
@ -85,8 +85,9 @@ public class ServerConformanceProvider {
@Override
public int compare(ResourceBinding theArg0, ResourceBinding theArg1) {
return theArg0.getResourceName().compareToIgnoreCase(theArg1.getResourceName());
}});
}
});
for (ResourceBinding next : bindings) {
Set<RestfulOperationTypeEnum> resourceOps = new HashSet<RestfulOperationTypeEnum>();
@ -117,7 +118,7 @@ public class ServerConformanceProvider {
if (nextMethodBinding instanceof SearchMethodBinding) {
List<IParameter> params = ((SearchMethodBinding) nextMethodBinding).getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>();
for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter);
@ -138,8 +139,8 @@ public class ServerConformanceProvider {
if (searchParameters.isEmpty()) {
continue;
}
boolean allOptional = searchParameters.get(0).isRequired()==false;
boolean allOptional = searchParameters.get(0).isRequired() == false;
RestResourceSearchParam searchParam = null;
ExtensionDt searchParamChain = null;
for (SearchParameter nextParameter : searchParameters) {
@ -162,11 +163,12 @@ public class ServerConformanceProvider {
} else {
searchParamChain = searchParam.addUndeclaredExtension(false, ExtensionConstants.CONF_ADDITIONAL_PARAM);
// if (searchParamChain == null) {
// } else {
// searchParamChain = searchParamChain.addUndeclaredExtension(false, ExtensionConstants.CONF_ADDITIONAL_PARAM);
// }
// if (searchParamChain == null) {
// } else {
// searchParamChain = searchParamChain.addUndeclaredExtension(false,
// ExtensionConstants.CONF_ADDITIONAL_PARAM);
// }
ExtensionDt ext = new ExtensionDt();
ext.setUrl(ExtensionConstants.CONF_ADDITIONAL_PARAM_NAME);
@ -220,4 +222,12 @@ public class ServerConformanceProvider {
myConformance = retVal;
return retVal;
}
/**
* Sets the cache property (default is true). If set to true, the same response will be returned for each
* invocation.
*/
public void setCache(boolean theCache) {
myCache = theCache;
}
}

View File

@ -26,10 +26,14 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@ -56,11 +60,17 @@ import org.thymeleaf.templateresolver.TemplateResolver;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.Metadata;
@ -69,11 +79,16 @@ import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.gclient.IQuery;
import ca.uhn.fhir.rest.gclient.IUntypedQuery;
import ca.uhn.fhir.rest.gclient.StringParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public class RestfulTesterServlet extends HttpServlet {
private static final String PARAM_RESOURCE = "resource";
private static final String RESOURCE_COUNT_EXT_URL = "http://hl7api.sourceforge.net/hapi-fhir/res/extdefs.html#resourceCount";
private static final boolean DEBUGMODE = true;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulTesterServlet.class);
private static final String PUBLIC_TESTER_RESULT_HTML = "/PublicTesterResult.html";
@ -145,7 +160,7 @@ public class RestfulTesterServlet extends HttpServlet {
}
private RuntimeResourceDefinition getResourceType(HttpServletRequest theReq) throws ServletException {
String resourceName = StringUtils.defaultString(theReq.getParameter("resource"));
String resourceName = StringUtils.defaultString(theReq.getParameter(PARAM_RESOURCE));
RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName);
if (def == null) {
throw new ServletException("Invalid resourceName: " + resourceName);
@ -166,6 +181,7 @@ public class RestfulTesterServlet extends HttpServlet {
boolean returnsResource;
long latency = 0;
String outcomeDescription = null;
try {
String method = theReq.getParameter("action");
@ -199,10 +215,36 @@ public class RestfulTesterServlet extends HttpServlet {
String versionId = StringUtils.defaultString(theReq.getParameter("vid"));
if (StringUtils.isBlank(versionId)) {
versionId = null;
outcomeDescription = "Read Resource";
} else {
outcomeDescription = "VRead Resource";
}
client.read(def.getImplementingClass(), new IdDt(def.getName(), id, versionId));
} else if ("get-tags".equals(method)) {
Class<? extends IResource> resType = null;
if (isNotBlank(theReq.getParameter(PARAM_RESOURCE))) {
RuntimeResourceDefinition def = getResourceType(theReq);
resType = def.getImplementingClass();
String id = theReq.getParameter("resource-tags-id");
if (isNotBlank(id)) {
String vid = theReq.getParameter("resource-tags-vid");
if (isNotBlank(vid)) {
client.getTags().forResource(resType, id, vid).execute();
} else {
client.getTags().forResource(resType, id).execute();
}
} else {
client.getTags().forResource(resType).execute();
}
} else {
client.getTags().execute();
}
returnsResource = false;
outcomeDescription = "Tag List";
} else if ("delete".equals(method)) {
RuntimeResourceDefinition def = getResourceType(theReq);
String id = StringUtils.defaultString(theReq.getParameter("resource-delete-id"));
@ -212,6 +254,7 @@ public class RestfulTesterServlet extends HttpServlet {
}
returnsResource = false;
outcomeDescription = "Delete Resource";
client.delete(def.getImplementingClass(), new IdDt(id));
@ -245,6 +288,7 @@ public class RestfulTesterServlet extends HttpServlet {
}
returnsResource = false;
outcomeDescription = "Resource History";
client.history(type, id, since, limit);
@ -276,11 +320,14 @@ public class RestfulTesterServlet extends HttpServlet {
if (validate) {
client.validate(resource);
outcomeDescription = "Validate Resource";
} else {
String id = theReq.getParameter("resource-create-id");
if (isNotBlank(id)) {
outcomeDescription = "Update Resource";
client.update(id, resource);
} else {
outcomeDescription = "Create Resource";
client.create(resource);
}
}
@ -295,21 +342,54 @@ public class RestfulTesterServlet extends HttpServlet {
query = search.forAllResources();
}
int paramIdx = 0;
outcomeDescription = "Search for Resources";
int paramIdx = -1;
while (true) {
paramIdx++;
String nextName = theReq.getParameter("param." + paramIdx + ".name");
if (isBlank(nextName)) {
break;
}
String nextType = theReq.getParameter("param." + paramIdx + ".type");
StringBuilder b = new StringBuilder();
for (int i = 0; i < 100; i++) {
b.append(defaultString(theReq.getParameter("param." + paramIdx + "." + i)));
}
query.where(new StringParam(nextName).matches().value(b.toString()));
String paramValue = b.toString();
if (isBlank(paramValue)) {
continue;
}
paramIdx++;
if ("token".equals(nextType)) {
if (paramValue.length() < 2) {
continue;
}
}
query.where(new StringParam(nextName).matches().value(paramValue));
}
String[] incValues = theReq.getParameterValues(Constants.PARAM_INCLUDE);
if (incValues != null) {
for (String next : incValues) {
if (isNotBlank(next)) {
query.include(new Include(next));
}
}
}
String limit = theReq.getParameter("resource-search-limit");
if (isNotBlank(limit)) {
if (!limit.matches("[0-9]+")) {
theContext.getVariables().put("errorMsg", "Search limit must be a numeric value.");
return;
}
query.limitTo(Integer.parseInt(limit));
}
query.execute();
@ -374,14 +454,19 @@ public class RestfulTesterServlet extends HttpServlet {
EncodingEnum ctEnum = EncodingEnum.forContentType(mimeType);
String narrativeString = "";
String resultDescription;
if (ctEnum == null) {
resultSyntaxHighlighterClass = "brush: plain";
resultDescription = "Non-FHIR response";
} else {
switch (ctEnum) {
case JSON:
resultSyntaxHighlighterClass = "brush: jscript";
if (returnsResource) {
narrativeString = parseNarrative(ctEnum, resultBody);
resultDescription = "JSON encoded resource";
} else {
resultDescription = "JSON encoded bundle";
}
break;
case XML:
@ -389,6 +474,9 @@ public class RestfulTesterServlet extends HttpServlet {
resultSyntaxHighlighterClass = "brush: xml";
if (returnsResource) {
narrativeString = parseNarrative(ctEnum, resultBody);
resultDescription = "XML encoded resource";
} else {
resultDescription = "XML encoded bundle";
}
break;
}
@ -397,6 +485,8 @@ public class RestfulTesterServlet extends HttpServlet {
Header[] requestHeaders = lastRequest != null ? applyHeaderFilters(lastRequest.getAllHeaders()) : new Header[0];
Header[] responseHeaders = lastResponse != null ? applyHeaderFilters(lastResponse.getAllHeaders()) : new Header[0];
theContext.setVariable("outcomeDescription", outcomeDescription);
theContext.setVariable("resultDescription", resultDescription);
theContext.setVariable("action", action);
theContext.setVariable("resultStatus", resultStatus);
theContext.setVariable("requestUrl", requestUrl);
@ -435,9 +525,48 @@ public class RestfulTesterServlet extends HttpServlet {
Conformance conformance = client.getConformance();
WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale());
Map<String, Number> resourceCounts = new HashMap<String, Number>();
long total = 0;
for (Rest nextRest : conformance.getRest()) {
for (RestResource nextResource : nextRest.getResource()) {
List<ExtensionDt> exts = nextResource.getUndeclaredExtensionsByUrl(RESOURCE_COUNT_EXT_URL);
if (exts != null && exts.size() > 0) {
Number nextCount = ((DecimalDt) (exts.get(0).getValue())).getValueAsNumber();
resourceCounts.put(nextResource.getType().getValue(), nextCount);
total += nextCount.longValue();
}
}
}
if (total > 0) {
for (Rest nextRest : conformance.getRest()) {
Collections.sort(nextRest.getResource(), new Comparator<RestResource>() {
@Override
public int compare(RestResource theO1, RestResource theO2) {
DecimalDt count1 = new DecimalDt();
List<ExtensionDt> count1exts = theO1.getUndeclaredExtensionsByUrl(RESOURCE_COUNT_EXT_URL);
if (count1exts != null && count1exts.size() > 0) {
count1 = (DecimalDt) count1exts.get(0).getValue();
}
DecimalDt count2 = new DecimalDt();
List<ExtensionDt> count2exts = theO2.getUndeclaredExtensionsByUrl(RESOURCE_COUNT_EXT_URL);
if (count2exts != null && count2exts.size() > 0) {
count2 = (DecimalDt) count2exts.get(0).getValue();
}
int retVal = count2.compareTo(count1);
if (retVal == 0) {
retVal = theO1.getType().getValue().compareTo(theO2.getType().getValue());
}
return retVal;
}
});
}
}
ctx.setVariable("resourceCounts", resourceCounts);
ctx.setVariable("conf", conformance);
ctx.setVariable("base", myServerBase);
String resourceName = defaultString(theReq.getParameter("resource"));
String resourceName = defaultString(theReq.getParameter(PARAM_RESOURCE));
ctx.setVariable("resourceName", resourceName);
ctx.setVariable("jsonEncodedConf", myCtx.newJsonParser().encodeResourceToString(conformance));
addStandardVariables(ctx, theReq.getParameterMap());
@ -448,9 +577,18 @@ public class RestfulTesterServlet extends HttpServlet {
if (isNotBlank(resourceName)) {
RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName);
// myCtx.newTerser().
TreeSet<String> includes = new TreeSet<String>();
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != SearchParamTypeEnum.REFERENCE) {
continue;
}
String nextPath = nextSpDef.getPath();
includes.add(nextPath);
}
ctx.setVariable("includes", includes);
}
theResp.setContentType("text/html");
theResp.setCharacterEncoding("UTF-8");

View File

@ -153,7 +153,7 @@ This file is a Thymeleaf template for the
</td>
</tr>
</table>
</body>
</html>

View File

@ -15,6 +15,14 @@
var resourceName = '<th:block th:utext="${resourceName}"/>';
</script>
<!-- Syntaxhighlighter -->
<script src="shCore.js" type="text/javascript"></script>
<script src="shBrushJScript.js" type="text/javascript"></script>
<script src="shBrushXml.js" type="text/javascript"></script>
<script src="shBrushPlain.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="shCore.css"/>
<link rel="stylesheet" type="text/css" href="shThemeDefault.css"/>
<!-- Bootstrap core CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet" />
@ -45,7 +53,17 @@
class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">HAPI FHIR RESTful Server</a>
<a class="navbar-brand" th:href="'?encoding=' + ${encoding} + '&amp;pretty=' + ${pretty}">
HAPI FHIR RESTful Server
</a>
<a class="navbar-left navbarBreadcrumb" th:if="${resourceName.empty} == false" th:href="'?encoding=' + ${encoding} + '&amp;pretty=' + ${pretty} + '&amp;resource=' + ${resourceName}">
<span class="glyphicon glyphicon-chevron-right"></span>
<span th:text="'Resource[' + ${resourceName} + ']'"></span>
</a>
<div class="navbar-left navbarBreadcrumb" th:if="${outcomeDescription} != null">
<span class="glyphicon glyphicon-chevron-right"></span>
<span th:text="${outcomeDescription}"></span>
</div>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
@ -74,7 +92,7 @@
</div>
<br /> <label class="navBarButtonLabel">Pretty</label>
<div class="btn-group" data-toggle="buttons">
<div class="btn-group top-buffer" data-toggle="buttons">
<label class="btn btn-sm btn-default active"> <input
type="radio" name="pretty" id="pretty-default" value="" />(default)
</label> <label class="btn btn-sm btn-default"> <input
@ -110,6 +128,11 @@
if (resourceName != null) {
var rbtn = $('<input />', { type: 'hidden', name: 'resource', value: resourceName });
$(source).append(rbtn);
} else {
var resource = $('#resource');
if (resource) {
resource.val('');
}
}
$('#outerForm').submit();
}
@ -124,12 +147,15 @@
<th:block
th:each="resource, resIterStat : ${conf.restFirstRep.resource}">
<li th:class="${resourceName} == ${resource.type.valueAsString} ? 'active' : ''">
<a href="#" th:text="${resource.type.valueAsString}" th:onclick="'doAction(this, \'home\', \'' + ${resource.type.valueAsString} + '\');'">Patient</a>
<a href="#" th:onclick="'doAction(this, \'home\', \'' + ${resource.type.valueAsString} + '\');'">
<th:block th:text="${resource.type.valueAsString}" >Patient</th:block>
<span class="badge" th:if="${resourceCounts[resource.type.valueAsString]} != null" th:text="${resourceCounts[resource.type.valueAsString]}"/>
</a>
</li>
</th:block>
</ul>
<input th:if="${resourceName.empty} == false" type="hidden" name="resource" th:value="${resourceName}"/>
<input th:if="${resourceName.empty} == false" type="hidden" id="resource" name="resource" th:value="${resourceName}"/>
</div>
@ -199,8 +225,7 @@
<div class="col-sm-2">
<button type="submit" id="fetch-conformance-btn"
data-loading-text="Loading..." class="btn btn-primary btn-block"
name="action" value="conformance">Fetch
Conformance</button>
name="action" value="conformance">Conformance</button>
<script type="text/javascript">
$('#fetch-conformance-btn').click(
function() {
@ -210,9 +235,10 @@
</script>
</div>
</div>
<!-- Server History -->
<br clear="all"/>
<div class="row-fluid">
Retrieve the update <b>history</b> across all resource types on
the server.
@ -223,7 +249,7 @@
data-loading-text="Loading..." class="btn btn-primary btn-block"
name="action" value="history-server">Server History</button>
</div>
<div class='col-sm-4'>
<div class='col-sm-5'>
<div class="form-group">
<div class='input-group date' id='server-history-datetime' data-date-format="YYYY-MM-DDTHH:mm:ss">
<div class="input-group-addon">
@ -238,7 +264,7 @@
</div>
<div class='col-sm-3'>
<div class="form-group">
<div class='input-group date'>
<div class='input-group'>
<div class="input-group-addon">
Limit #
</div>
@ -267,6 +293,27 @@
</div>
<!-- Get Tags -->
<br clear="all"/>
<div class="row-fluid">
Show all of the tags currently in use on the server
</div>
<div class="row-fluid">
<div class="col-sm-2">
<button type="submit" id="get-server-tags-btn"
data-loading-text="Loading..." class="btn btn-primary btn-block"
name="action" value="get-tags">Get Tags</button>
<script type="text/javascript">
$('#get-server-tags-btn').click(
function() {
var btn = $(this);
btn.button('loading');
});
</script>
</div>
</div>
<!-- Next Server Action? -->
</div>
@ -295,7 +342,7 @@
<div class="container-fluid">
<div class="row-fluid">
<div class="col-sm-2">
<button type="submit" id="read-btn" data-loading-text="Loading..." class="btn btn-primary btn-block" name="action" value="search">
<button type="submit" id="search-btn" class="btn btn-primary btn-block" name="action" value="search">
<span class="glyphicon glyphicon-search"></span>
Search
</button>
@ -311,8 +358,36 @@
<!-- Placeholder: gets populated by script below -->
</div>
<br clear="all"/>
<div class="row-fluid">
<h4>Includes <small>Also load and include referenced resources in results</small></h4>
</div>
<div class="row-fluid">
<span th:each="include : ${includes}" class="includeCheckContainer">
<span class="includeCheckCheck">
<input type="checkbox" name="_include" th:value="${include}" th:id="'inc_' + ${include}" />
</span>
<span class="includeCheckName" th:text="${include}"/>
</span>
</div>
<div class="row-fluid">
<h4>Other Options</h4>
</div>
<div class="row-fluid">
<div class='col-sm-3'>
<div class="form-group">
<div class='input-group date'>
<div class="input-group-addon">
Limit
</div>
<input type="text" class="form-control" name="resource-search-limit" placeholder="max # returned"/>
</div>
</div>
</div>
</div>
<!--
<div class="col-sm-1">
<button type="button" class="btn btn-success btn-block">Add
@ -320,11 +395,20 @@
</button>
</div>
-->
<br clear="all"/>
</div>
</div>
</div>
<script type="text/javascript">
/*
$('#search-btn').click(
function() {
$(this).html('<i class="fa fa-cog fa-spin"></i> Searching...')
//btn.button('loading');
});
*/
var numRows = 0;
function addSearchParamRow() {
var nextRow = numRows++;
@ -372,10 +456,14 @@
}
$('#search-param-rowopts-' + rowNum).empty();
var searchParam = params[newVal];
$('#search-param-rowopts-' + rowNum).append(
$('<input />', { name: 'param.' + rowNum + '.name', type: 'hidden', value: searchParam.name }),
$('<input />', { name: 'param.' + rowNum + '.type', type: 'hidden', value: searchParam.type })
);
if (searchParam.type == 'token') {
$('#search-param-rowopts-' + rowNum).append(
$('<div />', { 'class': 'col-sm-3' }).append(
$('<input />', { name: 'param.' + rowNum + '.name', type: 'hidden', value: searchParam.name }),
$('<input />', { name: 'param.' + rowNum + '.0', placeholder: 'system/namespace', type: 'text', 'class': 'form-control' })
),
$('<div />', { 'class': 'col-sm-3' }).append(
@ -386,7 +474,6 @@
} else if (searchParam.type == 'string' || searchParam.type == 'number') {
$('#search-param-rowopts-' + rowNum).append(
$('<div />', { 'class': 'col-sm-3' }).append(
$('<input />', { name: 'param.' + rowNum + '.name', type: 'hidden', value: searchParam.name }),
$('<input />', { name: 'param.' + rowNum + '.0', placeholder: 'value', type: 'text', 'class': 'form-control' })
)
);
@ -417,9 +504,9 @@
}
$('#search-param-rowopts-' + rowNum).append(
$('<div />', { 'class': 'col-sm-1 btn-group' }).append(
$('<div />', { 'class': 'col-sm-2 btn-group' }).append(
$('<select />', {type:'text', name:'param.'+rowNum+'.0', 'class':'form-control', autocomplete:'off'}).append(
$('<option value="">(qual)</option>'),
$('<option value="">(qualifier)</option>'),
$('<option value="=">=</option>'),
$('<option value=">=">&gt;=</option>'),
$('<option value=">">&gt;</option>'),
@ -428,7 +515,6 @@
)
),
$('<div />', { 'class': 'col-sm-4' }).append(
$('<input />', { name: 'param.' + rowNum + '.name', type: 'hidden', value: searchParam.name }),
input
)
);
@ -469,6 +555,7 @@
<div class='input-group date'>
<div class="input-group-addon">
ID
<span class="loadingStar">*</span>
</div>
<input type="text" class="form-control" id="read-id"/>
</div>
@ -480,7 +567,7 @@
<div class="input-group-addon">
Version ID
</div>
<input type="text" class="form-control" id="read-vid" placeholder="(opt)"/>
<input type="text" class="form-control" id="read-vid" placeholder="(add for vread)"/>
</div>
</div>
</div>
@ -518,11 +605,11 @@
<div class="input-group-addon">
ID
</div>
<input type="text" class="form-control" id="resource-history-id" placeholder="(opt)"/>
<input type="text" class="form-control" id="resource-history-id" placeholder="(instance ID)"/>
</div>
</div>
</div>
<div class='col-sm-4'>
<div class='col-sm-5'>
<div class="form-group">
<div class='input-group date' id='resource-history-datetime' data-date-format="YYYY-MM-DDTHH:mm:ss">
<div class="input-group-addon">
@ -539,9 +626,9 @@
<div class="form-group">
<div class='input-group date'>
<div class="input-group-addon">
Limit #
Limit
</div>
<input type="text" class="form-control" id="resource-history-limit" placeholder="(opt)"/>
<input type="text" class="form-control" id="resource-history-limit" placeholder="(#)"/>
</div>
</div>
</div>
@ -584,6 +671,7 @@
<div class='input-group date'>
<div class="input-group-addon">
ID
<span class="loadingStar">*</span>
</div>
<input type="text" class="form-control" id="resource-delete-id"/>
</div>
@ -620,7 +708,7 @@
<div class="input-group-addon">
ID
</div>
<input type="text" class="form-control" id="resource-create-id" placeholder="(opt)" />
<input type="text" class="form-control" id="resource-create-id" placeholder="(add for update)" />
</div>
</div>
</div>
@ -629,6 +717,7 @@
<div class='input-group date'>
<div class="input-group-addon">
Contents
<span class="loadingStar">*</span>
</div>
<textarea class="form-control" id="resource-create-body" style="white-space: nowrap; overflow: auto;" placeholder="(place resource body here)" rows="1"></textarea>
</div>
@ -691,6 +780,7 @@
<div class='input-group date'>
<div class="input-group-addon">
Contents
<span class="loadingStar">*</span>
</div>
<textarea class="form-control" id="resource-validate-body" style="white-space: nowrap; overflow: auto;" placeholder="(place resource body here)" rows="1"></textarea>
</div>
@ -711,7 +801,53 @@
});
</script>
</div>
<!-- Get Tags -->
<br clear="all"/>
<div class="row-fluid">
Show all of the tags currently in use on the server for this resource type. If an ID is specified,
returns only tags posted to the given version. If an ID and a version are specified,
returns only the tags posted to the given resource version.
</div>
<div class="row-fluid">
<div class="col-sm-2">
<button type="submit" id="get-resource-tags-btn"
data-loading-text="Loading..." class="btn btn-primary btn-block"
name="action" value="get-tags">Get Tags</button>
</div>
<div class='col-sm-3'>
<div class="form-group">
<div class='input-group date'>
<div class="input-group-addon">
ID
</div>
<input type="text" class="form-control" id="resource-tags-id" placeholder="(instance ID)"/>
</div>
</div>
</div>
<div class='col-sm-3'>
<div class="form-group">
<div class='input-group date'>
<div class="input-group-addon">
VID
</div>
<input type="text" class="form-control" id="resource-tags-vid" placeholder="(version)"/>
</div>
</div>
</div>
<script type="text/javascript">
$('#get-resource-tags-btn').click(
function() {
var btn = $(this);
btn.button('loading');
var id = $('#resource-tags-id').val();
if (id != null) btn.append($('<input />', { type: 'hidden', name: 'resource-tags-id', value: id }));
var vid = $('#resource-tags-vid').val();
if (vid != null) btn.append($('<input />', { type: 'hvidden', name: 'resource-tags-vid', value: vid }));
});
</script>
</div>
</div>
</div>
@ -757,9 +893,9 @@
</tr>
<tr th:if="${#strings.isEmpty(requestBody)} == false">
<td>Request Body</td>
<td valign="top">
<pre class="requestBodyPre" id="requestBodyPlaceholder">...loading...</pre>
<pre th:text="${requestBody}" class="requestBodyPre pre-scrollable" id="requestBodyActual" style="display: none;">{}</pre>
<td valign="top" style="margin: 0px; padding: 0px;">
<pre class="requestBodyPre resultBodyPlaceholder" id="requestBodyPlaceholder">...loading...</pre>
<pre th:text="${requestBody}" th:class="${requestSyntaxHighlighterClass} + ' resultBodyPre pre-scrollable'" id="requestBodyActual" style="display: none;">{}</pre>
</td>
</tr>
</tbody>
@ -788,10 +924,17 @@
</td>
</tr>
<tr th:if="${!#strings.isEmpty(resultBody)}">
<td>Result Body</td>
<td valign="top">
<pre class="resultBodyPre" id="resultBodyPlaceholder">...loading...</pre>
<pre th:text="${resultBody}" class="resultBodyPre pre-scrollable" id="resultBodyActual" style="display: none;">{}</pre>
<td rowspan="2">Result Body</td>
<td>
<span th:text="${resultDescription}"/>
</td>
</tr>
<tr th:if="${!#strings.isEmpty(resultBody)}">
<td valign="top" style="margin: 0px; padding: 0px;">
<pre class="resultBodyPre resultBodyPlaceholder" id="resultBodyPlaceholder">...loading...</pre>
<div id="resultBodyActual" class="resultBodyActual">
<pre th:text="${resultBody}" th:class="${resultSyntaxHighlighterClass} + ' resultBodyPre pre-scrollable'" style="display: none;">{}</pre>
</div>
</td>
</tr>
<tr th:if="${!#strings.isEmpty(narrative)}">
@ -803,18 +946,24 @@
<script type="text/javascript">
$( document ).ready(function() {
var width = $('#resultBodyPlaceholder').width();
var reswidth = $('#resultBodyPlaceholder').width();
var reqwidth = 0;
if ($('#requestBodyPlaceholder') != null) {
reqwidth = $('#requestBodyPlaceholder').width();
}
SyntaxHighlighter.all();
$('#resultBodyPlaceholder').hide();
$('#resultBodyActual').width(width);
$('#resultBodyActual').width(reswidth);
$('#resultBodyActual').show();
if ($('#requestBodyPlaceholder') != null) {
width = $('#requestBodyPlaceholder').width();
$('#requestBodyPlaceholder').hide();
$('#requestBodyActual').width(width);
$('#requestBodyActual').width(reqwidth);
$('#requestBodyActual').show();
}
});
});
</script>
</div>
@ -828,6 +977,7 @@
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="js/bootstrap.min.js"></script>
</form>
</body>
</html>

View File

@ -30,9 +30,67 @@ SPAN.headerValue {
font-size: 0.8em;
}
SPAN.includeCheckContainer {
margin-top: 6px;
margin-bottom: 6px;
margin-right: 0px;
margin-left: 15px;
white-space: nowrap;
line-height: 35px;
}
SPAN.includeCheckCheck {
border: 1px solid #AAA;
border-right-width: 0px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
padding: 6px;
background: #CCC;
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee));
background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%);
background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr = '#eeeeee', endColorstr = '#cccccc', GradientType = 0);
background-image: linear-gradient(to top, #ccc 0%, #eee 60%);
}
SPAN.includeCheckName {
border: 1px solid #AAA;
border-top-right-radius: 5px;
border-bottom-right-radius: 5px;
padding: 6px;
background: #FFF;
}
SPAN.loadingStar {
color: #F88;
display: inline-block !important;
margin: 0px !important;
padding: 0px !important;
width: 3px !important;
}
DIV.navbarBreadcrumb, A.navbarBreadcrumb {
color: #999;
padding: 15px;
padding-left: 0px;
font-size: 16px;
line-height: 20px;
height: 50px;
}
DIV.navbarBreadcrumb:HOVER, A.navbarBreadcrumb:HOVER {
color: #FFF;
text-decoration: none;
}
DIV.resultBodyActual {
max-height: 400px;
overflow: scroll;
}
PRE.resultBodyPre {
line-height: 0.9em;
font-size: 0.8em;
border: none;
}
/*
@ -126,6 +184,11 @@ PRE.resultBodyPre {
border-radius: 50%;
}
PRE.resultBodyPlaceholder {
width:100%;
padding: 0px;
}
.select2-container {
width: 100% !important;
}
@ -134,6 +197,16 @@ PRE.resultBodyPre {
height: 33px !important;
}
.syntaxhighlighter,
.syntaxhighlighter .line.alt1,
.syntaxhighlighter .line.alt2 {
background-color: transparent !important;
}
.syntaxhighlighter div {
font-size: 0.9em !important;
}
DIV.top-buffer {
margin-top: 2px;
}

View File

@ -173,8 +173,8 @@ public class ClientTest {
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
TagList tagList = new TagList();
tagList.add(new Tag("Dog", "DogLabel", (String) null));
tagList.add(new Tag("Cat", "CatLabel", "http://cats"));
tagList.add(new Tag((String) null, "Dog", "DogLabel"));
tagList.add(new Tag("http://cats", "Cat", "CatLabel"));
patient.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList);
MethodOutcome response = client.createPatient(patient);

View File

@ -1,29 +1,35 @@
package ca.uhn.fhir.rest.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hamcrest.core.StringContains;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.resource.Encounter;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Organization;
@ -34,13 +40,17 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class GenericClientTest {
private FhirContext myCtx;
private static FhirContext myCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@BeforeClass
public static void beforeClass() {
myCtx = new FhirContext();
}
@Before
public void before() {
myCtx = new FhirContext();
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
@ -48,6 +58,34 @@ public class GenericClientTest {
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
@Test
public void testCreateWithTag() throws Exception {
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
TagList list = new TagList();
list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, list);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
client.create(p1);
assertEquals("http://example.com/fhir/Patient", capt.getValue().getURI().toString());
assertEquals("POST", capt.getValue().getMethod());
Header catH = capt.getValue().getFirstHeader("Category");
assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH);
assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue());
}
private String getPatientFeedWithOneResult() {
//@formatter:off
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
@ -229,6 +267,45 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testGetTags() throws Exception {
TagList tagList = new TagList();
tagList.add(new Tag("CCC", "AAA", "BBB"));
String msg = myCtx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
TagList response = client.getTags()
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/_tags", capt.getValue().getURI().toString());
assertEquals(1,response.size());
assertEquals("CCC", response.get(0).getScheme());
// Now for patient
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
//@formatter:off
response = client.getTags().forResource(Patient.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_tags", capt.getValue().getURI().toString());
assertEquals(1,response.size());
assertEquals("CCC", response.get(0).getScheme());
}
@SuppressWarnings("unused")
@Test
public void testSearchByReferenceSimple() throws Exception {
@ -306,7 +383,7 @@ public class GenericClientTest {
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_format=json&_count=123", capt.getValue().getURI().toString());
assertEquals("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", capt.getValue().getURI().toString());
}

View File

@ -59,7 +59,7 @@ public class TagsClientTest {
public void testGetAllTags() throws Exception {
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
String ser = ctx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -81,7 +81,7 @@ public class TagsClientTest {
public void testGetAllTagsPatient() throws Exception {
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
String ser = ctx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -109,7 +109,7 @@ public class TagsClientTest {
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
client.deleteTags(new IdDt("111"), tagList);
@ -133,7 +133,7 @@ public class TagsClientTest {
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
client.deleteTags(new IdDt("111"), new IdDt("222"),tagList);
@ -157,7 +157,7 @@ public class TagsClientTest {
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
client.addTags(new IdDt("111"), tagList);
@ -181,7 +181,7 @@ public class TagsClientTest {
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
IClient client = ctx.newRestfulClient(IClient.class, "http://foo");
client.addTags(new IdDt("111"), new IdDt("222"),tagList);
@ -199,7 +199,7 @@ public class TagsClientTest {
public void testGetAllTagsPatientId() throws Exception {
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
String ser = ctx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -221,7 +221,7 @@ public class TagsClientTest {
public void testGetAllTagsPatientIdVersion() throws Exception {
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
String ser = ctx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -243,7 +243,7 @@ public class TagsClientTest {
public void testGetAllTagsPatientIdVersionOld() throws Exception {
TagList tagList = new TagList();
tagList.add(new Tag("AAA", "BBB", "CCC"));
tagList.add(new Tag("CCC", "AAA", "BBB"));
String ser = ctx.newXmlParser().encodeTagListToString(tagList);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);

View File

@ -956,8 +956,8 @@ public class ResfulServerMethodTest {
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
ourClient.execute(httpPost);
assertEquals(2, ourReportProvider.getLastTags().size());
assertEquals(new Tag("Dog", "aa", (String)null), ourReportProvider.getLastTags().get(0));
assertEquals(new Tag("Cat", "bb", (String)null), ourReportProvider.getLastTags().get(1));
assertEquals(new Tag((String)null, "Dog", "aa"), ourReportProvider.getLastTags().get(0));
assertEquals(new Tag((String)null, "Cat", "bb"), ourReportProvider.getLastTags().get(1));
}
@ -987,14 +987,14 @@ public class ResfulServerMethodTest {
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
ourClient.execute(httpPost);
assertEquals(1, ourReportProvider.getLastTags().size());
assertEquals(new Tag("Dog", null, "http://foo"), ourReportProvider.getLastTags().get(0));
assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0));
httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
httpPost.addHeader("Category", "Dog; scheme=\"http://foo\";");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
ourClient.execute(httpPost);
assertEquals(1, ourReportProvider.getLastTags().size());
assertEquals(new Tag("Dog", null, "http://foo"), ourReportProvider.getLastTags().get(0));
assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0));
}
@ -1009,14 +1009,14 @@ public class ResfulServerMethodTest {
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
ourClient.execute(httpPost);
assertEquals(1, ourReportProvider.getLastTags().size());
assertEquals(new Tag("Dog", "aaaa", "http://foo"), ourReportProvider.getLastTags().get(0));
assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0));
httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
httpPost.addHeader("Category", "Dog; scheme=\"http://foo\"; label=\"aaaa\"; ");
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
ourClient.execute(httpPost);
assertEquals(1, ourReportProvider.getLastTags().size());
assertEquals(new Tag("Dog", "aaaa", "http://foo"), ourReportProvider.getLastTags().get(0));
assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0));
}

View File

@ -267,40 +267,40 @@ public class TagsServerTest {
@GetTags
public TagList getAllTags() {
TagList tagList = new TagList();
tagList.add(new Tag("AllDog", "DogLabel", (String) null));
tagList.add(new Tag("AllCat", "CatLabel", "http://cats"));
tagList.add(new Tag((String) null, "AllDog", "DogLabel"));
tagList.add(new Tag("http://cats", "AllCat", "CatLabel"));
return tagList;
}
@GetTags(type = Patient.class)
public TagList getAllTagsPatient() {
TagList tagList = new TagList();
tagList.add(new Tag("Patient", "DogLabel", (String) null));
tagList.add(new Tag("AllCat", "CatLabel", "http://cats"));
tagList.add(new Tag((String) null, "Patient", "DogLabel"));
tagList.add(new Tag("http://cats", "AllCat", "CatLabel"));
return tagList;
}
@GetTags(type = Patient.class)
public TagList getAllTagsPatientId(@IdParam IdDt theId) {
TagList tagList = new TagList();
tagList.add(new Tag("Patient" + theId.getUnqualifiedId() + defaultString(theId.getUnqualifiedVersionId()), "DogLabel", (String) null));
tagList.add(new Tag("AllCat", "CatLabel", "http://cats"));
tagList.add(new Tag((String) null, "Patient" + theId.getUnqualifiedId() + defaultString(theId.getUnqualifiedVersionId()), "DogLabel"));
tagList.add(new Tag("http://cats", "AllCat", "CatLabel"));
return tagList;
}
@GetTags(type = Patient.class)
public TagList getAllTagsPatientIdVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersion) {
TagList tagList = new TagList();
tagList.add(new Tag("Patient" + theId.getUnqualifiedId() + theVersion.getUnqualifiedVersionId(), "DogLabel", (String) null));
tagList.add(new Tag("AllCat", "CatLabel", "http://cats"));
tagList.add(new Tag((String) null, "Patient" + theId.getUnqualifiedId() + theVersion.getUnqualifiedVersionId(), "DogLabel"));
tagList.add(new Tag("http://cats", "AllCat", "CatLabel"));
return tagList;
}
@GetTags(type = Observation.class)
public TagList getAllTagsObservationIdVersion(@IdParam IdDt theId) {
TagList tagList = new TagList();
tagList.add(new Tag("Patient" + theId.getUnqualifiedId() + theId.getUnqualifiedVersionId(), "DogLabel", (String) null));
tagList.add(new Tag("AllCat", "CatLabel", "http://cats"));
tagList.add(new Tag((String) null, "Patient" + theId.getUnqualifiedId() + theId.getUnqualifiedVersionId(), "DogLabel"));
tagList.add(new Tag("http://cats", "AllCat", "CatLabel"));
return tagList;
}

View File

@ -1,52 +0,0 @@
package ca.uhn.fhir.test;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import ca.uhn.fhir.rest.server.tester.RestfulServerTesterServlet;
import ca.uhn.fhir.rest.server.tester.RestfulTesterServlet;
public class JpaTestApp {
@SuppressWarnings({ "unused", "unchecked" })
public static void main(String[] args) throws Exception {
// ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("fhir-spring-test-config.xml");
//
// IFhirResourceDao<Patient> patientDao = appCtx.getBean("myPatientDao", IFhirResourceDao.class);
// PatientResourceProvider patientRp = new PatientResourceProvider();
// patientRp.setDao(patientDao);
//
// IFhirResourceDao<Questionnaire> questionnaireDao = appCtx.getBean("myQuestionnaireDao", IFhirResourceDao.class);
// QuestionnaireResourceProvider questionnaireRp = new QuestionnaireResourceProvider();
// questionnaireRp.setDao(questionnaireDao);
//
// RestfulServer restServer = new RestfulServer();
// restServer.setResourceProviders(patientRp, questionnaireRp);
int myPort = 8888;
Server server = new Server(myPort);
ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/");
RestfulTesterServlet testerServlet = new RestfulTesterServlet();
// testerServlet.setServerBase("http://localhost:" + myPort + "/fhir/context");
testerServlet.setServerBase("http://fhir.healthintersections.com.au/open");
ServletHolder handler = new ServletHolder();
handler.setName("Tester");
handler.setServlet(testerServlet);
proxyHandler.addServlet(handler, "/fhir/tester/*");
// ServletHolder servletHolder = new ServletHolder();
// servletHolder.setServlet(restServer);
// proxyHandler.addServlet(servletHolder, "/fhir/context/*");
server.setHandler(proxyHandler);
server.start();
}
}

View File

@ -1,6 +1,6 @@
package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.*;
import java.io.UnsupportedEncodingException;
import java.text.Normalizer;
@ -67,7 +67,6 @@ import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.FhirTerser;
@ -733,7 +732,7 @@ public abstract class BaseFhirDao {
if (theEntity.getTags().size() > 0) {
TagList tagList = new TagList();
for (BaseTag next : theEntity.getTags()) {
tagList.add(new Tag(next.getTag().getTerm(), next.getTag().getLabel(), next.getTag().getScheme()));
tagList.add(new Tag(next.getTag().getScheme(), next.getTag().getTerm(), next.getTag().getLabel()));
}
retVal.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList);
}

View File

@ -12,16 +12,12 @@ import javax.persistence.Tuple;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.hamcrest.generator.qdox.parser.structs.TagDef;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
@ -144,4 +140,23 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
return super.getTags(null, null);
}
@Override
public Map<String, Long> getResourceCounts() {
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
Root<?> from = cq.from(ResourceTable.class);
cq.multiselect(from.get("myResourceType").as(String.class), builder.count(from.get("myResourceType")).as(Long.class));
cq.groupBy(from.get("myResourceType"));
TypedQuery<Tuple> q = myEntityManager.createQuery(cq);
Map<String, Long> retVal = new HashMap<String, Long>();
for (Tuple next : q.getResultList()) {
String resourceName = next.get(0, String.class);
Long count = next.get(1, Long.class);
retVal.put(resourceName, count);
}
return retVal;
}
}

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao;
import java.util.Date;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
@ -14,4 +15,6 @@ public interface IFhirSystemDao {
TagList getAllTags();
Map<String, Long> getResourceCounts();
}

View File

@ -76,7 +76,7 @@ public class TagDefinition implements Serializable {
}
public Tag toTag() {
return new Tag( getTerm(), getLabel(),getScheme());
return new Tag( getScheme(), getTerm(),getLabel());
}
}

View File

@ -0,0 +1,42 @@
package ca.uhn.fhir.jpa.provider;
import java.util.Map;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider;
public class JpaConformanceProvider extends ServerConformanceProvider {
private IFhirSystemDao mySystemDao;
public JpaConformanceProvider(RestfulServer theRestfulServer, IFhirSystemDao theSystemDao) {
super(theRestfulServer);
mySystemDao = theSystemDao;
super.setCache(false);
}
@Override
public Conformance getServerConformance() {
Map<String, Long> counts = mySystemDao.getResourceCounts();
Conformance retVal = super.getServerConformance();
for (Rest nextRest : retVal.getRest()) {
for (RestResource nextResource : nextRest.getResource()) {
Long count = counts.get(nextResource.getType().getValueAsString());
if (count!=null) {
nextResource.addUndeclaredExtension(false, "http://hl7api.sourceforge.net/hapi-fhir/res/extdefs.html#resourceCount", new DecimalDt(count));
}
}
}
return retVal;
}
}

View File

@ -9,6 +9,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils;
import org.junit.AfterClass;
@ -282,6 +283,35 @@ public class FhirSystemDaoTest {
}
@Test
public void testGetResourceCounts() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01");
ourObservationDao.create(obs);
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier("urn:system", "testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient);
Map<String, Long> newCounts = ourSystemDao.getResourceCounts();
if (oldCounts.containsKey("Patient")) {
assertEquals(oldCounts.get("Patient")+1, (long)newCounts.get("Patient"));
}else {
assertEquals(1L, (long)newCounts.get("Patient"));
}
assertEquals((long)oldCounts.get("Observation"), (long)newCounts.get("Observation"));
}
@Test
public void testPersistWithUnknownId() {
Observation obs = new Observation();

View File

@ -103,6 +103,7 @@
<packageBase>ca.uhn.test.jpasrv</packageBase>
<baseResourceNames>
<baseResourceName>device</baseResourceName>
<baseResourceName>diagnosticreport</baseResourceName>
<baseResourceName>location</baseResourceName>
<baseResourceName>observation</baseResourceName>
<baseResourceName>organization</baseResourceName>

View File

@ -1,52 +0,0 @@
package ca.uhn.fhir.jpa.test;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import ca.uhn.fhir.rest.server.tester.RestfulServerTesterServlet;
import ca.uhn.fhir.rest.server.tester.RestfulTesterServlet;
public class JpaTestApp {
@SuppressWarnings({ "unused", "unchecked" })
public static void main(String[] args) throws Exception {
// ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("fhir-spring-test-config.xml");
//
// IFhirResourceDao<Patient> patientDao = appCtx.getBean("myPatientDao", IFhirResourceDao.class);
// PatientResourceProvider patientRp = new PatientResourceProvider();
// patientRp.setDao(patientDao);
//
// IFhirResourceDao<Questionnaire> questionnaireDao = appCtx.getBean("myQuestionnaireDao", IFhirResourceDao.class);
// QuestionnaireResourceProvider questionnaireRp = new QuestionnaireResourceProvider();
// questionnaireRp.setDao(questionnaireDao);
//
// RestfulServer restServer = new RestfulServer();
// restServer.setResourceProviders(patientRp, questionnaireRp);
int myPort = 8888;
Server server = new Server(myPort);
ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/");
RestfulTesterServlet testerServlet = new RestfulTesterServlet();
// testerServlet.setServerBase("http://localhost:" + myPort + "/fhir/context");
testerServlet.setServerBase("http://fhir.healthintersections.com.au/open");
ServletHolder handler = new ServletHolder();
handler.setName("Tester");
handler.setServlet(testerServlet);
proxyHandler.addServlet(handler, "/fhir/tester/*");
// ServletHolder servletHolder = new ServletHolder();
// servletHolder.setServlet(restServer);
// proxyHandler.addServlet(servletHolder, "/fhir/context/*");
server.setHandler(proxyHandler);
server.start();
}
}

View File

@ -0,0 +1,102 @@
package ca.uhn.fhir.jpa.test;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.JpaConformanceProvider;
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu.resource.Organization;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.resource.Questionnaire;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.tester.RestfulTesterServlet;
import ca.uhn.test.jpasrv.DiagnosticReportResourceProvider;
import ca.uhn.test.jpasrv.OrganizationResourceProvider;
import ca.uhn.test.jpasrv.PatientResourceProvider;
import ca.uhn.test.jpasrv.QuestionnaireResourceProvider;
public class JpaTestApp {
@SuppressWarnings({ "unchecked" })
public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext("fhir-spring-test-config.xml");
IFhirResourceDao<Patient> patientDao = appCtx.getBean("myPatientDao", IFhirResourceDao.class);
PatientResourceProvider patientRp = new PatientResourceProvider();
patientRp.setDao(patientDao);
IFhirResourceDao<Questionnaire> questionnaireDao = appCtx.getBean("myQuestionnaireDao", IFhirResourceDao.class);
QuestionnaireResourceProvider questionnaireRp = new QuestionnaireResourceProvider();
questionnaireRp.setDao(questionnaireDao);
IFhirResourceDao<Organization> organizationDao = appCtx.getBean("myOrganizationDao", IFhirResourceDao.class);
OrganizationResourceProvider organizationRp = new OrganizationResourceProvider();
organizationRp.setDao(organizationDao);
IFhirResourceDao<DiagnosticReport> diagnosticReportDao = appCtx.getBean("myDiagnosticReportDao", IFhirResourceDao.class);
DiagnosticReportResourceProvider diagnosticReportRp = new DiagnosticReportResourceProvider();
diagnosticReportRp.setDao(diagnosticReportDao);
IFhirSystemDao systemDao = appCtx.getBean("mySystemDao", IFhirSystemDao.class);
JpaSystemProvider systemProvider = new JpaSystemProvider(systemDao);
RestfulServer restServer = new RestfulServer();
restServer.setResourceProviders(diagnosticReportRp,patientRp, questionnaireRp, organizationRp);
restServer.setProviders(systemProvider);
JpaConformanceProvider confProvider = new JpaConformanceProvider(restServer, systemDao);
restServer.setServerConformanceProvider(confProvider);
int myPort = 8888;
Server server = new Server(myPort);
ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/");
RestfulTesterServlet testerServlet = new RestfulTesterServlet();
String base = "http://localhost:" + myPort + "/fhir/context";
// base = "http://fhir.healthintersections.com.au/open";
testerServlet.setServerBase(base);
ServletHolder handler = new ServletHolder();
handler.setName("Tester");
handler.setServlet(testerServlet);
proxyHandler.addServlet(handler, "/fhir/tester/*");
ServletHolder servletHolder = new ServletHolder();
servletHolder.setServlet(restServer);
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
server.setHandler(proxyHandler);
server.start();
if (true) {
IGenericClient client = restServer.getFhirContext().newRestfulGenericClient(base);
client.setLogRequestAndResponse(true);
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
TagList list = new TagList();
list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, list);
client.create(p1);
List<IResource> resources = restServer.getFhirContext().newJsonParser().parseBundle(IOUtils.toString(JpaTestApp.class.getResourceAsStream("/bundle.json"))).toListOfResources();
client.transaction(resources);
}
}
}

View File

@ -21,6 +21,9 @@
<bean id="mySystemDao" class="ca.uhn.fhir.jpa.dao.FhirSystemDao">
</bean>
<bean id="myDiagnosticReportDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.DiagnosticReport"/>
</bean>
<bean id="myPatientDao" class="ca.uhn.fhir.jpa.dao.FhirResourceDao">
<property name="resourceType" value="ca.uhn.fhir.model.dstu.resource.Patient"/>
</bean>