Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
0b7cfec06b
|
@ -8,7 +8,25 @@
|
|||
<body>
|
||||
<release version="0.6" date="TBD">
|
||||
<action type="add">
|
||||
Allow generic client
|
||||
Allow generic client ... OAUTH
|
||||
</action>
|
||||
<action type="fix">
|
||||
Tester UI created double _format and _pretty param entries in searches. Thanks to Gered King of University
|
||||
Health Network for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="4">
|
||||
Create method was incorrectly returning an HTTP 204 on sucessful completion, but
|
||||
should be returning an HTTP 200 per the FHIR specification. Thanks to wanghaisheng
|
||||
for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
FHIR Tester UI now correctly sends UTF-8 charset in responses so that message payloads containing
|
||||
non US-ASCII characters will correctly display in the browser
|
||||
</action>
|
||||
<action type="fix">
|
||||
JSON parser was incorrectly encoding extensions on composite elements outside the element itself
|
||||
(as is done correctly for non-composite elements) instead of inside of them. Thanks to David Hay of
|
||||
Orion for reporting this!
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.5" date="2014-Jul-30">
|
||||
|
|
|
@ -30,6 +30,11 @@ public abstract class BaseRuntimeChildDefinition {
|
|||
|
||||
public abstract IAccessor getAccessor();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()+"[" + getElementName() + "]";
|
||||
}
|
||||
|
||||
public abstract BaseRuntimeElementDefinition<?> getChildByName(String theName);
|
||||
|
||||
public abstract BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IElement> theType);
|
||||
|
|
|
@ -56,6 +56,11 @@ public abstract class BaseRuntimeElementDefinition<T extends IElement> {
|
|||
myImplementingClass = theImplementingClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName()+"[" + getName() + "]";
|
||||
}
|
||||
|
||||
public void addExtension(RuntimeChildDeclaredExtensionDefinition theExtension) {
|
||||
if (theExtension == null) {
|
||||
throw new NullPointerException();
|
||||
|
|
|
@ -181,7 +181,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
for (BundleEntry nextEntry : theBundle.getEntries()) {
|
||||
eventWriter.writeStartObject();
|
||||
|
||||
boolean deleted = nextEntry.getDeletedAt() !=null&&nextEntry.getDeletedAt().isEmpty()==false;
|
||||
boolean deleted = nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false;
|
||||
if (deleted) {
|
||||
writeTagWithTextNode(eventWriter, "deleted", nextEntry.getDeletedAt());
|
||||
}
|
||||
|
@ -227,11 +227,16 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
eventWriter.flush();
|
||||
}
|
||||
|
||||
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: {
|
||||
IPrimitiveDatatype<?> value = (IPrimitiveDatatype<?>) theValue;
|
||||
if (isBlank(value.getValueAsString())) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (value instanceof IntegerDt) {
|
||||
if (theChildName != null) {
|
||||
theWriter.write(theChildName, ((IntegerDt) value).getValue());
|
||||
|
@ -333,7 +338,8 @@ 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();
|
||||
|
@ -372,14 +378,16 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (childDef == null) {
|
||||
super.throwExceptionForUnknownChildType(nextChild, type);
|
||||
}
|
||||
boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE;
|
||||
|
||||
if (nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
|
||||
RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild;
|
||||
if (extDef.isModifier()) {
|
||||
addToHeldExtensions(valueIdx, modifierExtensions, extDef, nextValue);
|
||||
} else {
|
||||
addToHeldExtensions(valueIdx, extensions, extDef, nextValue);
|
||||
}
|
||||
// Don't encode extensions
|
||||
// RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild;
|
||||
// if (extDef.isModifier()) {
|
||||
// addToHeldExtensions(valueIdx, modifierExtensions, extDef, nextValue);
|
||||
// } else {
|
||||
// addToHeldExtensions(valueIdx, extensions, extDef, nextValue);
|
||||
// }
|
||||
} else {
|
||||
|
||||
if (currentChildName == null || !currentChildName.equals(childName)) {
|
||||
|
@ -398,7 +406,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null);
|
||||
}
|
||||
|
||||
if (nextValue instanceof ISupportsUndeclaredExtensions) {
|
||||
if (nextValue instanceof ISupportsUndeclaredExtensions && primitive) {
|
||||
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
|
||||
addToHeldExtensions(valueIdx, ext, extensions);
|
||||
|
||||
|
@ -416,9 +424,6 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
|
||||
if (extensions.size() > 0 || modifierExtensions.size() > 0) {
|
||||
// Ignore extensions if we're encoding a resource, since they
|
||||
// are handled one level up
|
||||
if (currentChildName != null) {
|
||||
theEventWriter.writeStartArray('_' + currentChildName);
|
||||
|
||||
for (int i = 0; i < valueIdx; i++) {
|
||||
|
@ -440,37 +445,20 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
// if (extensions.size() > 0) {
|
||||
//
|
||||
// theEventWriter.name(extType);
|
||||
// theEventWriter.beginArray();
|
||||
// for (ArrayList<HeldExtension> next : extensions) {
|
||||
// if (next == null || next.isEmpty()) {
|
||||
// theEventWriter.nullValue();
|
||||
// } else {
|
||||
// theEventWriter.beginArray();
|
||||
// // next.write(theEventWriter);
|
||||
// theEventWriter.endArray();
|
||||
// }
|
||||
// }
|
||||
// for (int i = extensions.size(); i < valueIdx; i++) {
|
||||
// theEventWriter.nullValue();
|
||||
// }
|
||||
// theEventWriter.endArray();
|
||||
// }
|
||||
|
||||
theEventWriter.writeEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, resDef, theResDef, theResource);
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions());
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren());
|
||||
}
|
||||
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull, boolean theIsSubElementWithinResource) throws IOException {
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull,
|
||||
boolean theIsSubElementWithinResource) throws IOException {
|
||||
if (!theIsSubElementWithinResource) {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
}
|
||||
|
@ -491,9 +479,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
if (theResource instanceof Binary) {
|
||||
Binary bin = (Binary) theResource;
|
||||
theEventWriter.write("contentType", bin.getContentType());
|
||||
theEventWriter.write("content",bin.getContentAsBase64());
|
||||
theEventWriter.write("content", bin.getContentAsBase64());
|
||||
} else {
|
||||
extractAndWriteExtensionsAsDirectChild(theResource, theEventWriter, resDef, theResDef, theResource);
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef);
|
||||
}
|
||||
theEventWriter.writeEnd();
|
||||
|
@ -506,7 +493,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
JsonGenerator eventWriter = createJsonGenerator(theWriter);
|
||||
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null,false);
|
||||
encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null, false);
|
||||
eventWriter.flush();
|
||||
}
|
||||
|
||||
|
@ -541,10 +528,10 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
|
||||
* called _name): resource extensions, and extension extensions
|
||||
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object called _name): resource extensions, and extension extensions
|
||||
*/
|
||||
private void extractAndWriteExtensionsAsDirectChild(IElement theElement, JsonGenerator theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef, IResource theResource) throws IOException {
|
||||
private void extractAndWriteExtensionsAsDirectChild(IElement theElement, JsonGenerator theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef,
|
||||
IResource theResource) throws IOException {
|
||||
List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
|
||||
|
@ -895,7 +882,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
private void writeExtensionsAsDirectChild(IResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) throws IOException {
|
||||
private void writeExtensionsAsDirectChild(IResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions,
|
||||
List<HeldExtension> modifierExtensions) throws IOException {
|
||||
if (extensions.isEmpty() == false) {
|
||||
theEventWriter.writeStartArray("extension");
|
||||
for (HeldExtension next : extensions) {
|
||||
|
|
|
@ -821,10 +821,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
public Bundle execute() {
|
||||
|
||||
Map<String, List<String>> params = new LinkedHashMap<String, List<String>>();
|
||||
Map<String, List<String>> initial = createExtraParams();
|
||||
if (initial != null) {
|
||||
params.putAll(initial);
|
||||
}
|
||||
// Map<String, List<String>> initial = createExtraParams();
|
||||
// if (initial != null) {
|
||||
// params.putAll(initial);
|
||||
// }
|
||||
|
||||
for (ICriterionInternal next : myCriterion) {
|
||||
String parameterName = next.getParameterName();
|
||||
|
|
|
@ -65,7 +65,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
|
||||
if (!theMethod.getReturnType().equals(MethodOutcome.class)) {
|
||||
if (!allowVoidReturnType()) {
|
||||
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " is a @" + theMethodAnnotation.getSimpleName() + " method but it does not return " + MethodOutcome.class);
|
||||
throw new ConfigurationException("Method " + theMethod.getName() + " in type " + theMethod.getDeclaringClass().getCanonicalName() + " is a @" + theMethodAnnotation.getSimpleName()
|
||||
+ " method but it does not return " + MethodOutcome.class);
|
||||
} else if (theMethod.getReturnType() == void.class) {
|
||||
myReturnVoid = true;
|
||||
}
|
||||
|
@ -92,7 +93,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
switch (theResponseStatusCode) {
|
||||
case Constants.STATUS_HTTP_200_OK:
|
||||
case Constants.STATUS_HTTP_201_CREATED:
|
||||
|
@ -149,13 +151,25 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
}
|
||||
}
|
||||
|
||||
if (getResourceOperationType() == RestfulOperationTypeEnum.CREATE) {
|
||||
switch (getResourceOperationType()) {
|
||||
case CREATE:
|
||||
if (response == null) {
|
||||
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null, which is not allowed for create operation");
|
||||
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName()
|
||||
+ " returned null, which is not allowed for create operation");
|
||||
}
|
||||
theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED);
|
||||
addLocationHeader(theRequest, theResponse, response);
|
||||
} else if (response == null) {
|
||||
break;
|
||||
|
||||
case UPDATE:
|
||||
theResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
||||
addLocationHeader(theRequest, theResponse, response);
|
||||
break;
|
||||
|
||||
case VALIDATE:
|
||||
case DELETE:
|
||||
default:
|
||||
if (response == null) {
|
||||
if (isReturnVoid() == false) {
|
||||
throw new InternalErrorException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() + " returned null");
|
||||
}
|
||||
|
@ -172,6 +186,8 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
theServer.addHeadersToResponse(theResponse);
|
||||
|
||||
if (response != null && response.getOperationOutcome() != null) {
|
||||
|
@ -210,48 +226,27 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
}
|
||||
|
||||
/*
|
||||
* @Override public void invokeServer(RestfulServer theServer, Request
|
||||
* theRequest, HttpServletResponse theResponse) throws
|
||||
* BaseServerResponseException, IOException { Object[] params = new
|
||||
* Object[getParameters().size()]; for (int i = 0; i <
|
||||
* getParameters().size(); i++) { IParameter param = getParameters().get(i);
|
||||
* if (param != null) { params[i] =
|
||||
* @Override public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException { Object[] params = new
|
||||
* Object[getParameters().size()]; for (int i = 0; i < getParameters().size(); i++) { IParameter param = getParameters().get(i); if (param != null) { params[i] =
|
||||
* param.translateQueryParametersIntoServerArgument(theRequest, null); } }
|
||||
*
|
||||
* addParametersForServerRequest(theRequest, params);
|
||||
*
|
||||
* MethodOutcome response = (MethodOutcome)
|
||||
* invokeServerMethod(getProvider(), params);
|
||||
* MethodOutcome response = (MethodOutcome) invokeServerMethod(getProvider(), params);
|
||||
*
|
||||
* if (response == null) { if (myReturnVoid == false) { throw new
|
||||
* ConfigurationException("Method " + getMethod().getName() + " in type " +
|
||||
* getMethod().getDeclaringClass().getCanonicalName() + " returned null"); }
|
||||
* else { theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); } }
|
||||
* else if (!myReturnVoid) { if (response.isCreated()) {
|
||||
* theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED); StringBuilder b
|
||||
* = new StringBuilder(); b.append(theRequest.getFhirServerBase());
|
||||
* b.append('/'); b.append(getResourceName()); b.append('/');
|
||||
* b.append(response.getId().getValue()); if (response.getVersionId() !=
|
||||
* null && response.getVersionId().isEmpty() == false) {
|
||||
* b.append("/_history/"); b.append(response.getVersionId().getValue()); }
|
||||
* theResponse.addHeader("Location", b.toString()); } else {
|
||||
* theResponse.setStatus(Constants.STATUS_HTTP_200_OK); } } else {
|
||||
* if (response == null) { if (myReturnVoid == false) { throw new ConfigurationException("Method " + getMethod().getName() + " in type " + getMethod().getDeclaringClass().getCanonicalName() +
|
||||
* " returned null"); } else { theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); } } else if (!myReturnVoid) { if (response.isCreated()) {
|
||||
* theResponse.setStatus(Constants.STATUS_HTTP_201_CREATED); StringBuilder b = new StringBuilder(); b.append(theRequest.getFhirServerBase()); b.append('/'); b.append(getResourceName());
|
||||
* b.append('/'); b.append(response.getId().getValue()); if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) { b.append("/_history/");
|
||||
* b.append(response.getVersionId().getValue()); } theResponse.addHeader("Location", b.toString()); } else { theResponse.setStatus(Constants.STATUS_HTTP_200_OK); } } else {
|
||||
* theResponse.setStatus(Constants.STATUS_HTTP_204_NO_CONTENT); }
|
||||
*
|
||||
* theServer.addHeadersToResponse(theResponse);
|
||||
*
|
||||
* Writer writer = theResponse.getWriter(); try { if (response != null) {
|
||||
* OperationOutcome outcome = new OperationOutcome(); if
|
||||
* (response.getOperationOutcome() != null &&
|
||||
* response.getOperationOutcome().getIssue() != null) {
|
||||
* outcome.getIssue().addAll(response.getOperationOutcome().getIssue()); }
|
||||
* EncodingUtil encoding =
|
||||
* BaseMethodBinding.determineResponseEncoding(theRequest
|
||||
* .getServletRequest(), theRequest.getParameters());
|
||||
* theResponse.setContentType(encoding.getResourceContentType()); IParser
|
||||
* parser = encoding.newParser(getContext());
|
||||
* parser.encodeResourceToWriter(outcome, writer); } } finally {
|
||||
* writer.close(); } // getMethod().in }
|
||||
* Writer writer = theResponse.getWriter(); try { if (response != null) { OperationOutcome outcome = new OperationOutcome(); if (response.getOperationOutcome() != null &&
|
||||
* response.getOperationOutcome().getIssue() != null) { outcome.getIssue().addAll(response.getOperationOutcome().getIssue()); } EncodingUtil encoding =
|
||||
* BaseMethodBinding.determineResponseEncoding(theRequest .getServletRequest(), theRequest.getParameters()); theResponse.setContentType(encoding.getResourceContentType()); IParser parser =
|
||||
* encoding.newParser(getContext()); parser.encodeResourceToWriter(outcome, writer); } } finally { writer.close(); } // getMethod().in }
|
||||
*/
|
||||
|
||||
public boolean isReturnVoid() {
|
||||
|
@ -266,10 +261,10 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
b.append('/');
|
||||
b.append(response.getId().getIdPart());
|
||||
if (response.getId().hasVersionIdPart()) {
|
||||
b.append("/"+Constants.PARAM_HISTORY+"/");
|
||||
b.append("/" + Constants.PARAM_HISTORY + "/");
|
||||
b.append(response.getId().getVersionIdPart());
|
||||
}else if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) {
|
||||
b.append("/"+Constants.PARAM_HISTORY+"/");
|
||||
} else if (response.getVersionId() != null && response.getVersionId().isEmpty() == false) {
|
||||
b.append("/" + Constants.PARAM_HISTORY + "/");
|
||||
b.append(response.getVersionId().getValue());
|
||||
}
|
||||
theResponse.addHeader(Constants.HEADER_LOCATION, b.toString());
|
||||
|
@ -350,8 +345,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
protected abstract void addParametersForServerRequest(Request theRequest, Object[] theParams);
|
||||
|
||||
/**
|
||||
* Subclasses may override to allow a void method return type, which is
|
||||
* allowable for some methods (e.g. delete)
|
||||
* Subclasses may override to allow a void method return type, which is allowable for some methods (e.g. delete)
|
||||
*/
|
||||
protected boolean allowVoidReturnType() {
|
||||
return false;
|
||||
|
@ -360,17 +354,14 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
|
|||
protected abstract BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource resource);
|
||||
|
||||
/**
|
||||
* For servers, this method will match only incoming requests that match the
|
||||
* given operation, or which have no operation in the URL if this method
|
||||
* returns null.
|
||||
* For servers, this method will match only incoming requests that match the given operation, or which have no operation in the URL if this method returns null.
|
||||
*/
|
||||
protected abstract String getMatchingOperation();
|
||||
|
||||
protected abstract Set<RequestType> provideAllowableRequestTypes();
|
||||
|
||||
/**
|
||||
* Subclasses may override if the incoming request should not contain a
|
||||
* resource
|
||||
* Subclasses may override if the incoming request should not contain a resource
|
||||
*/
|
||||
protected boolean requestContainsResource() {
|
||||
return true;
|
||||
|
|
|
@ -57,6 +57,17 @@ import ca.uhn.fhir.rest.server.ResourceBinding;
|
|||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
|
||||
/**
|
||||
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
||||
*
|
||||
* <p>
|
||||
* Note: This class is safe to extend, but it is important to note that the same instance of
|
||||
* {@link Conformance} is always returned unless {@link #setCache(boolean)} is called with a value
|
||||
* of <code>false</code>. This means that if you are adding anything to the returned
|
||||
* conformance instance on each call you should call <code>setCache(false)</code> in
|
||||
* your provider constructor.
|
||||
* </p>
|
||||
*/
|
||||
public class ServerConformanceProvider {
|
||||
|
||||
private volatile Conformance myConformance;
|
||||
|
@ -67,6 +78,11 @@ public class ServerConformanceProvider {
|
|||
myRestfulServer = theRestfulServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually create and return the conformance statement
|
||||
*
|
||||
* See the class documentation for an important note if you are extending this class
|
||||
*/
|
||||
@Metadata
|
||||
public Conformance getServerConformance() {
|
||||
if (myConformance != null && myCache) {
|
||||
|
@ -246,6 +262,9 @@ public class ServerConformanceProvider {
|
|||
/**
|
||||
* Sets the cache property (default is true). If set to true, the same response will be returned for each
|
||||
* invocation.
|
||||
* <p>
|
||||
* See the class documentation for an important note if you are extending this class
|
||||
* </p>
|
||||
*/
|
||||
public void setCache(boolean theCache) {
|
||||
myCache = theCache;
|
||||
|
|
|
@ -83,6 +83,67 @@ public class JsonParserTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionInCompositeElement() {
|
||||
|
||||
Conformance c = new Conformance();
|
||||
c.addRest().getSecurity().addUndeclaredExtension(false, "http://foo", new StringDt("AAA"));
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
|
||||
encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"rest\":[{\"security\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}]}");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionInPrimitiveElement() {
|
||||
|
||||
Conformance c = new Conformance();
|
||||
c.getAcceptUnknown().addUndeclaredExtension(false, "http://foo", new StringDt("AAA"));
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
|
||||
encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"_acceptUnknown\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}]}");
|
||||
|
||||
// Now with a value
|
||||
ourLog.info("---------------");
|
||||
|
||||
c = new Conformance();
|
||||
c.getAcceptUnknown().setValue(true);
|
||||
c.getAcceptUnknown().addUndeclaredExtension(false, "http://foo", new StringDt("AAA"));
|
||||
|
||||
encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
|
||||
encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"acceptUnknown\":true,\"_acceptUnknown\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}]}");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionInResourceElement() {
|
||||
|
||||
Conformance c = new Conformance();
|
||||
// c.addRest().getSecurity().addUndeclaredExtension(false, "http://foo", new StringDt("AAA"));
|
||||
c.addUndeclaredExtension(false, "http://foo", new StringDt("AAA"));
|
||||
|
||||
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
|
||||
encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c);
|
||||
ourLog.info(encoded);
|
||||
assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryResource() {
|
||||
|
@ -388,6 +449,17 @@ public class JsonParserTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeExtensionOnEmptyElement() throws Exception {
|
||||
|
||||
ValueSet valueSet = new ValueSet();
|
||||
valueSet.addTelecom().addUndeclaredExtension(false, "http://foo", new StringDt("AAA"));
|
||||
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(valueSet);
|
||||
assertThat(encoded, containsString("\"telecom\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
|
@ -402,11 +474,11 @@ public class JsonParserTest {
|
|||
code.setDisplay("someDisplay");
|
||||
code.addUndeclaredExtension(false, "urn:alt", new StringDt("alt name"));
|
||||
|
||||
String encoded = new FhirContext().newJsonParser().encodeResourceToString(valueSet);
|
||||
String encoded = ourCtx.newJsonParser().encodeResourceToString(valueSet);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, not(containsString("123456")));
|
||||
assertThat(encoded, containsString("\"define\":{\"concept\":[{\"code\":\"someCode\",\"display\":\"someDisplay\"}],\"_concept\":[{\"extension\":[{\"url\":\"urn:alt\",\"valueString\":\"alt name\"}]}]}"));
|
||||
assertEquals("{\"resourceType\":\"ValueSet\",\"define\":{\"concept\":[{\"extension\":[{\"url\":\"urn:alt\",\"valueString\":\"alt name\"}],\"code\":\"someCode\",\"display\":\"someDisplay\"}]}}", encoded);
|
||||
|
||||
}
|
||||
|
||||
|
@ -500,31 +572,7 @@ public class JsonParserTest {
|
|||
given.addUndeclaredExtension(ext2);
|
||||
String enc = new FhirContext().newJsonParser().encodeResourceToString(patient);
|
||||
ourLog.info(enc);
|
||||
//@formatter:off
|
||||
assertThat(enc, containsString(("{" +
|
||||
" \"resourceType\":\"Patient\"," +
|
||||
" \"name\":[" +
|
||||
" {" +
|
||||
" \"family\":[" +
|
||||
" \"Shmoe\"" +
|
||||
" ]," +
|
||||
" \"given\":[" +
|
||||
" \"Joe\"" +
|
||||
" ]" +
|
||||
" }" +
|
||||
" ]," +
|
||||
" \"_name\":[" +
|
||||
" {" +
|
||||
" \"extension\":[" +
|
||||
" {" +
|
||||
" \"url\":\"http://examples.com#givenext\"," +
|
||||
" \"valueString\":\"Hello\"" +
|
||||
" }" +
|
||||
" ]" +
|
||||
" }" +
|
||||
" ]" +
|
||||
"}").replaceAll(" +", "")));
|
||||
//@formatter:on
|
||||
assertEquals("{\"resourceType\":\"Patient\",\"name\":[{\"extension\":[{\"url\":\"http://examples.com#givenext\",\"valueString\":\"Hello\"}],\"family\":[\"Shmoe\"],\"given\":[\"Joe\"]}]}", enc);
|
||||
|
||||
IParser newJsonParser = new FhirContext().newJsonParser();
|
||||
StringReader reader = new StringReader(enc);
|
||||
|
@ -837,9 +885,7 @@ public class JsonParserTest {
|
|||
ExtensionDt undeclaredExtension = undeclaredExtensions.get(0);
|
||||
assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue());
|
||||
|
||||
fhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out));
|
||||
|
||||
IParser jsonParser = fhirCtx.newJsonParser();
|
||||
IParser jsonParser = fhirCtx.newJsonParser().setPrettyPrint(true);
|
||||
String encoded = jsonParser.encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
|
|||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
import ca.uhn.fhir.rest.method.SearchStyleEnum;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
|
@ -343,6 +344,33 @@ public class GenericClientTest {
|
|||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchWithClientEncodingAndPrettyPrintConfig() throws Exception {
|
||||
|
||||
String msg = getPatientFeedWithOneResult();
|
||||
|
||||
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")));
|
||||
|
||||
GenericClient client = (GenericClient) myCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
client.setPrettyPrint(true);
|
||||
client.setEncoding(EncodingEnum.JSON);
|
||||
|
||||
//@formatter:off
|
||||
Bundle response = client.search()
|
||||
.forResource(Patient.class)
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
assertEquals("http://example.com/fhir/Patient?_format=json&_pretty=true", capt.getValue().getURI().toString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchByDate() throws Exception {
|
||||
|
|
|
@ -104,9 +104,10 @@ public class UpdateTest {
|
|||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
assertEquals(204, status.getStatusLine().getStatusCode());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -118,18 +119,20 @@ public class UpdateTest {
|
|||
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
|
||||
httpPost.addHeader("Category", "Dog, Cat");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
ourClient.execute(httpPost);
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
assertEquals(2, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag("Dog"), ourReportProvider.getLastTags().get(0));
|
||||
assertEquals(new Tag("Cat"), ourReportProvider.getLastTags().get(1));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
|
||||
httpPost.addHeader("Category", "Dog; label=\"aa\", Cat; label=\"bb\"");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
ourClient.execute(httpPost);
|
||||
status = ourClient.execute(httpPost);
|
||||
assertEquals(2, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag((String) null, "Dog", "aa"), ourReportProvider.getLastTags().get(0));
|
||||
assertEquals(new Tag((String) null, "Cat", "bb"), ourReportProvider.getLastTags().get(1));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
}
|
||||
|
||||
|
@ -142,9 +145,10 @@ public class UpdateTest {
|
|||
HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
|
||||
httpPost.addHeader("Category", "Dog");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
ourClient.execute(httpPost);
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
assertEquals(1, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag("Dog"), ourReportProvider.getLastTags().get(0));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
}
|
||||
|
||||
|
@ -157,9 +161,10 @@ public class UpdateTest {
|
|||
HttpPut 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);
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
assertEquals(1, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001");
|
||||
httpPost.addHeader("Category", "Dog; scheme=\"http://foo\";");
|
||||
|
@ -167,6 +172,7 @@ public class UpdateTest {
|
|||
ourClient.execute(httpPost);
|
||||
assertEquals(1, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
}
|
||||
|
||||
|
@ -179,16 +185,18 @@ public class UpdateTest {
|
|||
HttpPut 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);
|
||||
CloseableHttpResponse status = ourClient.execute(httpPost);
|
||||
assertEquals(1, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
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);
|
||||
status=ourClient.execute(httpPost);
|
||||
assertEquals(1, ourReportProvider.getLastTags().size());
|
||||
assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0));
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
}
|
||||
|
||||
|
@ -208,9 +216,9 @@ public class UpdateTest {
|
|||
// IOUtils.toString(status.getEntity().getContent());
|
||||
// ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(204, status.getStatusLine().getStatusCode());
|
||||
assertNull(status.getEntity());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("Location").getValue());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
}
|
||||
|
||||
|
@ -224,10 +232,11 @@ public class UpdateTest {
|
|||
httpPut.addHeader("Content-Location", "/Patient/001/_history/002");
|
||||
httpPut.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
CloseableHttpResponse results = ourClient.execute(httpPut);
|
||||
assertEquals(400, results.getStatusLine().getStatusCode());
|
||||
String responseContent = IOUtils.toString(results.getEntity().getContent());
|
||||
CloseableHttpResponse status = ourClient.execute(httpPut);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -253,6 +253,16 @@
|
|||
<artifactId>validation-api</artifactId>
|
||||
<version>1.1.0.Final</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.el</groupId>
|
||||
<artifactId>javax.el-api</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish</groupId>
|
||||
<artifactId>javax.el</artifactId>
|
||||
<version>3.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Misc -->
|
||||
<dependency>
|
||||
|
|
|
@ -31,23 +31,11 @@ public class JpaConformanceProvider extends ServerConformanceProvider {
|
|||
myRestfulServer = theRestfulServer;
|
||||
mySystemDao = theSystemDao;
|
||||
super.setCache(false);
|
||||
|
||||
// for (IFhirResourceDao<?> nextResourceDao : theResourceDaos) {
|
||||
// nextResourceDao.registerDaoListener(new IDaoListener() {
|
||||
// @Override
|
||||
// public void writeCompleted() {
|
||||
// myCachedValue = null;
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public Conformance getServerConformance() {
|
||||
Conformance retVal = myCachedValue;
|
||||
// if (retVal != null) {
|
||||
// return retVal;
|
||||
// }
|
||||
|
||||
Map<String, Long> counts = mySystemDao.getResourceCounts();
|
||||
|
||||
|
|
|
@ -5,6 +5,10 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
|
|||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
|
@ -30,6 +34,7 @@ import org.apache.http.HttpEntityEnclosingRequest;
|
|||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
|
@ -52,6 +57,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.client.GenericClient;
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.gclient.ICreateTyped;
|
||||
import ca.uhn.fhir.rest.gclient.IQuery;
|
||||
|
@ -59,6 +65,7 @@ import ca.uhn.fhir.rest.gclient.IUntypedQuery;
|
|||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.to.model.HomeRequest;
|
||||
import ca.uhn.fhir.to.model.ResourceRequest;
|
||||
import ca.uhn.fhir.to.model.TransactionRequest;
|
||||
|
@ -96,7 +103,8 @@ public class Controller {
|
|||
public String actionConformance(final HomeRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
ResultType returnsResource = ResultType.RESOURCE;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
@ -107,7 +115,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Loaded conformance");
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Loaded conformance", interceptor);
|
||||
|
||||
ourLog.info(logPrefix(theModel) + "Displayed conformance profile");
|
||||
|
||||
|
@ -124,7 +132,8 @@ public class Controller {
|
|||
public String actionDelete(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
RuntimeResourceDefinition def;
|
||||
try {
|
||||
|
@ -150,7 +159,7 @@ public class Controller {
|
|||
returnsResource = handleClientException(client, e, theModel);
|
||||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription, interceptor);
|
||||
|
||||
ourLog.info(logPrefix(theModel) + "Deleted resource of type " + def.getName());
|
||||
|
||||
|
@ -161,7 +170,8 @@ public class Controller {
|
|||
public String actionGetTags(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
Class<? extends IResource> resType = null;
|
||||
ResultType returnsResource = ResultType.TAGLIST;
|
||||
|
@ -202,7 +212,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription, interceptor);
|
||||
|
||||
return "result";
|
||||
}
|
||||
|
@ -229,7 +239,8 @@ public class Controller {
|
|||
public String actionPage(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
String url = defaultString(theReq.getParameter("page-url"));
|
||||
if (!url.startsWith(theModel.get("base").toString())) {
|
||||
|
@ -253,7 +264,7 @@ public class Controller {
|
|||
|
||||
String outcomeDescription = "Bundle Page";
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription, interceptor);
|
||||
|
||||
return "result";
|
||||
}
|
||||
|
@ -262,7 +273,8 @@ public class Controller {
|
|||
public String actionRead(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
RuntimeResourceDefinition def;
|
||||
try {
|
||||
|
@ -297,7 +309,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription, interceptor);
|
||||
|
||||
return "result";
|
||||
}
|
||||
|
@ -306,7 +318,8 @@ public class Controller {
|
|||
public String actionResource(final ResourceRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
Conformance conformance = addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
String resourceName = theRequest.getResource();
|
||||
RuntimeResourceDefinition def = myCtx.getResourceDefinition(theRequest.getResource());
|
||||
|
@ -372,6 +385,72 @@ public class Controller {
|
|||
return "resource";
|
||||
}
|
||||
|
||||
public static class CaptureInterceptor implements IClientInterceptor {
|
||||
|
||||
private HttpRequestBase myLastRequest;
|
||||
private HttpResponse myLastResponse;
|
||||
private String myResponseBody;
|
||||
|
||||
@Override
|
||||
public void interceptRequest(HttpRequestBase theRequest) {
|
||||
assert myLastRequest == null;
|
||||
myLastRequest = theRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(HttpResponse theResponse) throws IOException {
|
||||
assert myLastResponse == null;
|
||||
myLastResponse = theResponse;
|
||||
|
||||
HttpEntity respEntity = theResponse.getEntity();
|
||||
if (respEntity != null) {
|
||||
final byte[] bytes;
|
||||
try {
|
||||
bytes = IOUtils.toByteArray(respEntity.getContent());
|
||||
} catch (IllegalStateException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
myResponseBody = new String(bytes, "UTF-8");
|
||||
theResponse.setEntity(new MyEntityWrapper(respEntity, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
public HttpRequestBase getLastRequest() {
|
||||
return myLastRequest;
|
||||
}
|
||||
|
||||
public HttpResponse getLastResponse() {
|
||||
return myLastResponse;
|
||||
}
|
||||
|
||||
private static class MyEntityWrapper extends HttpEntityWrapper {
|
||||
|
||||
private byte[] myBytes;
|
||||
|
||||
public MyEntityWrapper(HttpEntity theWrappedEntity, byte[] theBytes) {
|
||||
super(theWrappedEntity);
|
||||
myBytes = theBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getContent() throws IOException {
|
||||
return new ByteArrayInputStream(myBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream theOutstream) throws IOException {
|
||||
theOutstream.write(myBytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getLastResponseBody() {
|
||||
return myResponseBody;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/search" })
|
||||
public String actionSearch(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
@ -382,7 +461,8 @@ public class Controller {
|
|||
clientCodeJsonWriter.write("action", "search");
|
||||
clientCodeJsonWriter.write("base", (String) theModel.get("base"));
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
IUntypedQuery search = client.search();
|
||||
IQuery query;
|
||||
|
@ -463,7 +543,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription, interceptor);
|
||||
|
||||
clientCodeJsonWriter.writeEnd();
|
||||
clientCodeJsonWriter.close();
|
||||
|
@ -477,7 +557,8 @@ public class Controller {
|
|||
public String actionTransaction(final TransactionRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
String body = preProcessMessageBody(theRequest.getTransactionBody());
|
||||
|
||||
|
@ -507,7 +588,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Transaction");
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, "Transaction", interceptor);
|
||||
|
||||
return "result";
|
||||
}
|
||||
|
@ -561,7 +642,8 @@ public class Controller {
|
|||
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
Class<? extends IResource> type = null; // def.getImplementingClass();
|
||||
if ("history-type".equals(theMethod)) {
|
||||
|
@ -623,7 +705,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription, interceptor);
|
||||
|
||||
try {
|
||||
if (validate) {
|
||||
|
@ -642,7 +724,8 @@ public class Controller {
|
|||
private void doActionHistory(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel, String theMethod, String theMethodDescription) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
CaptureInterceptor interceptor = new CaptureInterceptor();
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig, interceptor);
|
||||
|
||||
String id = null;
|
||||
Class<? extends IResource> type = null; // def.getImplementingClass();
|
||||
|
@ -675,7 +758,7 @@ public class Controller {
|
|||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, theMethodDescription);
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, theMethodDescription, interceptor);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1011,14 +1094,16 @@ public class Controller {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
private void processAndAddLastClientInvocation(GenericClient theClient, ResultType theResultType, ModelMap theModelMap, long theLatency, String outcomeDescription) {
|
||||
private void processAndAddLastClientInvocation(GenericClient theClient, ResultType theResultType, ModelMap theModelMap, long theLatency, String outcomeDescription,
|
||||
CaptureInterceptor theInterceptor) {
|
||||
try {
|
||||
HttpRequestBase lastRequest = theClient.getLastRequest();
|
||||
HttpRequestBase lastRequest = theInterceptor.getLastRequest();
|
||||
HttpResponse lastResponse = theInterceptor.getLastResponse();
|
||||
String requestBody = null;
|
||||
String requestUrl = lastRequest != null ? lastRequest.getURI().toASCIIString() : null;
|
||||
String action = theClient.getLastRequest() != null ? theClient.getLastRequest().getMethod() : null;
|
||||
String resultStatus = theClient.getLastResponse() != null ? theClient.getLastResponse().getStatusLine().toString() : null;
|
||||
String resultBody = StringUtils.defaultString(theClient.getLastResponseBody());
|
||||
String action = lastRequest != null ? lastRequest.getMethod() : null;
|
||||
String resultStatus = lastResponse != null ? lastResponse.getStatusLine().toString() : null;
|
||||
String resultBody = StringUtils.defaultString(theInterceptor.getLastResponseBody());
|
||||
|
||||
if (lastRequest instanceof HttpEntityEnclosingRequest) {
|
||||
HttpEntity entity = ((HttpEntityEnclosingRequest) lastRequest).getEntity();
|
||||
|
@ -1027,7 +1112,6 @@ public class Controller {
|
|||
}
|
||||
}
|
||||
|
||||
HttpResponse lastResponse = theClient.getLastResponse();
|
||||
ContentType ct = lastResponse != null ? ContentType.get(lastResponse.getEntity()) : null;
|
||||
String mimeType = ct != null ? ct.getMimeType() : null;
|
||||
EncodingEnum ctEnum = EncodingEnum.forContentType(mimeType);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.to.model;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
|
@ -11,6 +12,7 @@ import ca.uhn.fhir.parser.IParser;
|
|||
import ca.uhn.fhir.rest.client.GenericClient;
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.to.Controller;
|
||||
import ca.uhn.fhir.to.TesterConfig;
|
||||
|
||||
public class HomeRequest {
|
||||
|
@ -80,7 +82,7 @@ public class HomeRequest {
|
|||
myServerId = theServerId;
|
||||
}
|
||||
|
||||
public GenericClient newClient(FhirContext theContext, TesterConfig theConfig) {
|
||||
public GenericClient newClient(FhirContext theContext, TesterConfig theConfig, Controller.CaptureInterceptor theInterceptor) {
|
||||
GenericClient retVal = (GenericClient) theContext.newRestfulGenericClient(getServerBase(theConfig));
|
||||
retVal.setKeepResponses(true);
|
||||
|
||||
|
@ -96,6 +98,8 @@ public class HomeRequest {
|
|||
retVal.setEncoding( EncodingEnum.JSON);
|
||||
}
|
||||
|
||||
retVal.registerInterceptor(theInterceptor);
|
||||
|
||||
final String remoteAddr = org.slf4j.MDC.get("req.remoteAddr");
|
||||
retVal.registerInterceptor(new IClientInterceptor() {
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
<property name="prefix" value="/WEB-INF/templates/" />
|
||||
<property name="suffix" value=".html" />
|
||||
<property name="templateMode" value="HTML5" />
|
||||
<property name="characterEncoding" value="UTF-8" />
|
||||
</bean>
|
||||
|
||||
<bean id="templateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
|
||||
|
@ -29,6 +30,7 @@
|
|||
|
||||
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
|
||||
<property name="templateEngine" ref="templateEngine" />
|
||||
<property name="characterEncoding" value="UTF-8" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
2
pom.xml
2
pom.xml
|
@ -142,6 +142,7 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
|
@ -172,6 +173,7 @@
|
|||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
-->
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<dependent-module archiveName="hapi-fhir-base-0.6-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-tester-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-testpage-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
<dependency-type>consumes</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/slf/?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
|
|
Loading…
Reference in New Issue