From fb998a6a328bfa1e18d556108d878215e4d0b901 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Fri, 9 May 2014 17:54:55 -0400 Subject: [PATCH] Fix some bugs on the generic client --- .../java/ca/uhn/fhir/parser/JsonParser.java | 368 ++++++++--------- .../ca/uhn/fhir/rest/client/BaseClient.java | 67 ++-- .../rest/client/ClientInvocationHandler.java | 6 +- .../uhn/fhir/rest/client/GenericClient.java | 174 ++++---- .../rest/client/HttpBasicAuthInterceptor.java | 3 +- .../fhir/rest/gclient/StringCriterion.java | 2 +- .../uhn/fhir/rest/gclient/TokenCriterion.java | 2 +- .../BaseAddOrDeleteTagsMethodBinding.java | 4 +- .../fhir/rest/method/BaseMethodBinding.java | 4 +- .../BaseOutcomeReturningMethodBinding.java | 4 +- .../BaseResourceReturningMethodBinding.java | 2 +- .../rest/method/GetTagsMethodBinding.java | 4 +- .../rest/method/IClientResponseHandler.java | 4 +- ...t.java => RestfulServerTesterServlet.java} | 372 ++++++++++-------- .../ca/uhn/fhir/parser/JsonParserTest.java | 9 + .../ca/uhn/fhir/rest/client/ClientTest.java | 25 ++ .../fhir/rest/client/GenericClientTest.java | 58 ++- .../ca/uhn/fhir/rest/server/TesterTest.java | 4 +- 18 files changed, 606 insertions(+), 506 deletions(-) rename hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/{PublicTesterServlet.java => RestfulServerTesterServlet.java} (54%) diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index 1c8b0046712..1f52495b405 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -20,7 +20,9 @@ package ca.uhn.fhir.parser; * #L% */ -import static org.apache.commons.lang3.StringUtils.*; +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.IOException; import java.io.Reader; @@ -45,13 +47,10 @@ import javax.json.JsonValue; import javax.json.JsonValue.ValueType; import javax.json.stream.JsonGenerator; import javax.json.stream.JsonGeneratorFactory; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; -import ch.qos.logback.core.boolex.EventEvaluator; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; import ca.uhn.fhir.context.BaseRuntimeElementDefinition; @@ -64,7 +63,6 @@ import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.model.api.BaseBundle; import ca.uhn.fhir.model.api.Bundle; -import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.BundleEntry; import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.IElement; @@ -72,6 +70,7 @@ import ca.uhn.fhir.model.api.IIdentifiableElement; import ca.uhn.fhir.model.api.IPrimitiveDatatype; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions; +import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.annotation.Child; import ca.uhn.fhir.model.dstu.composite.ContainedDt; @@ -88,6 +87,8 @@ import ca.uhn.fhir.narrative.INarrativeGenerator; public class JsonParser extends BaseParser implements IParser { private static final Set BUNDLE_TEXTNODE_CHILDREN; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParser.HeldExtension.class); + static { HashSet hashSet = new HashSet(); hashSet.add("title"); @@ -105,6 +106,48 @@ public class JsonParser extends BaseParser implements IParser { myContext = theContext; } + private void addToHeldExtensions(int valueIdx, ArrayList> list, RuntimeChildDeclaredExtensionDefinition theDef, IElement theValue) { + list.ensureCapacity(valueIdx); + while (list.size() <= valueIdx) { + list.add(null); + } + if (list.get(valueIdx) == null) { + list.set(valueIdx, new ArrayList()); + } + list.get(valueIdx).add(new HeldExtension(theDef, theValue)); + } + + private void addToHeldExtensions(int valueIdx, List ext, ArrayList> list) { + if (ext.size() > 0) { + list.ensureCapacity(valueIdx); + while (list.size() <= valueIdx) { + list.add(null); + } + if (list.get(valueIdx) == null) { + list.set(valueIdx, new ArrayList()); + } + for (ExtensionDt next : ext) { + list.get(valueIdx).add(new HeldExtension(next)); + } + } + } + + private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) { + if (theResourceTypeObj.getValueType() != theValueType) { + throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType); + } + } + + private JsonGenerator createJsonGenerator(Writer theWriter) { + Map properties = new HashMap(1); + if (myPrettyPrint) { + properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint); + } + JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties); + JsonGenerator eventWriter = jgf.createGenerator(theWriter); + return eventWriter; + } + @Override public void encodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException { JsonGenerator eventWriter = createJsonGenerator(theWriter); @@ -170,173 +213,8 @@ public class JsonParser extends BaseParser implements IParser { eventWriter.close(); } - @Override - public void encodeResourceToWriter(IResource theResource, Writer theWriter) throws IOException { - Validate.notNull(theResource, "Resource can not be null"); - - JsonGenerator eventWriter = createJsonGenerator(theWriter); - - RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource); - encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null); - eventWriter.flush(); - } - - @Override - public void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException { - JsonGenerator eventWriter = createJsonGenerator(theWriter); - - eventWriter.writeStartObject(); - - eventWriter.write("resourceType", TagList.ELEMENT_NAME); - - eventWriter.writeStartArray(TagList.ATTR_CATEGORY); - for (Tag next : theTagList) { - eventWriter.writeStartObject(); - - if (isNotBlank(next.getTerm())) { - eventWriter.write(Tag.ATTR_TERM, next.getTerm()); - } - if (isNotBlank(next.getLabel())) { - eventWriter.write(Tag.ATTR_LABEL, next.getLabel()); - } - if (isNotBlank(next.getScheme())) { - eventWriter.write(Tag.ATTR_SCHEME, next.getScheme()); - } - - eventWriter.writeEnd(); - } - eventWriter.writeEnd(); - - eventWriter.writeEnd(); - eventWriter.flush(); - } - - @Override - public Bundle parseBundle(Class theResourceType, Reader theReader) { - JsonReader reader = Json.createReader(theReader); - JsonObject object = reader.readObject(); - - JsonValue resourceTypeObj = object.get("resourceType"); - assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType"); - String resourceType = ((JsonString) resourceTypeObj).getString(); - if (!"Bundle".equals(resourceType)) { - throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'"); - } - - ParserState state = ParserState.getPreAtomInstance(myContext, theResourceType, true); - state.enteringNewElement(null, "feed"); - - parseBundleChildren(object, state); - - state.endingElement(); - - Bundle retVal = state.getObject(); - - return retVal; - } - - @Override - public T parseResource(Class theResourceType, Reader theReader) { - JsonReader reader = Json.createReader(theReader); - JsonObject object = reader.readObject(); - - JsonValue resourceTypeObj = object.get("resourceType"); - assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType"); - String resourceType = ((JsonString) resourceTypeObj).getString(); - - RuntimeResourceDefinition def; - if (theResourceType != null) { - def = myContext.getResourceDefinition(theResourceType); - } else { - def = myContext.getResourceDefinition(resourceType); - } - - ParserState state = ParserState.getPreResourceInstance(def.getImplementingClass(), myContext, true); - state.enteringNewElement(null, def.getName()); - - parseChildren(object, state); - - state.endingElement(); - - @SuppressWarnings("unchecked") - T retVal = (T) state.getObject(); - - return retVal; - } - - @Override - public T parseResource(Class theResourceType, String theMessageString) { - return parseResource(theResourceType, new StringReader(theMessageString)); - } - - @Override - public TagList parseTagList(Reader theReader) { - JsonReader reader = Json.createReader(theReader); - JsonObject object = reader.readObject(); - - JsonValue resourceTypeObj = object.get("resourceType"); - assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType"); - String resourceType = ((JsonString) resourceTypeObj).getString(); - - ParserState state = ParserState.getPreTagListInstance(myContext, true); - state.enteringNewElement(null, resourceType); - - parseChildren(object, state); - - state.endingElement(); - - return state.getObject(); - } - - @Override - public IParser setPrettyPrint(boolean thePrettyPrint) { - myPrettyPrint = thePrettyPrint; - return this; - } - - private void addToHeldExtensions(int valueIdx, ArrayList> list, RuntimeChildDeclaredExtensionDefinition theDef, IElement theValue) { - list.ensureCapacity(valueIdx); - while (list.size() <= valueIdx) { - list.add(null); - } - if (list.get(valueIdx) == null) { - list.set(valueIdx, new ArrayList()); - } - list.get(valueIdx).add(new HeldExtension(theDef, theValue)); - } - - private void addToHeldExtensions(int valueIdx, List ext, ArrayList> list) { - if (ext.size() > 0) { - list.ensureCapacity(valueIdx); - while (list.size() <= valueIdx) { - list.add(null); - } - if (list.get(valueIdx) == null) { - list.set(valueIdx, new ArrayList()); - } - for (ExtensionDt next : ext) { - list.get(valueIdx).add(new HeldExtension(next)); - } - } - } - - private void assertObjectOfType(JsonValue theResourceTypeObj, ValueType theValueType, String thePosition) { - if (theResourceTypeObj.getValueType() != theValueType) { - throw new DataFormatException("Invalid content of element " + thePosition + ", expected " + theValueType); - } - } - - private JsonGenerator createJsonGenerator(Writer theWriter) { - Map properties = new HashMap(1); - if (myPrettyPrint) { - properties.put(JsonGenerator.PRETTY_PRINTING, myPrettyPrint); - } - JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties); - JsonGenerator eventWriter = jgf.createGenerator(theWriter); - return eventWriter; - } - - private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition theChildDef, String theChildName) throws IOException { + private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theWriter, IElement theValue, BaseRuntimeElementDefinition theChildDef, + String theChildName) throws IOException { switch (theChildDef.getChildType()) { case PRIMITIVE_DATATYPE: { @@ -438,7 +316,8 @@ public class JsonParser extends BaseParser implements IParser { } - private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, List theChildren) throws IOException { + private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, + List theChildren) throws IOException { for (BaseRuntimeChildDefinition nextChild : theChildren) { if (nextChild instanceof RuntimeChildNarrativeDefinition) { INarrativeGenerator gen = myContext.getNarrativeGenerator(); @@ -570,7 +449,8 @@ public class JsonParser extends BaseParser implements IParser { } } - private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, BaseRuntimeElementCompositeDefinition resDef) throws IOException, DataFormatException { + private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IResource theResource, IElement theElement, JsonGenerator theEventWriter, + BaseRuntimeElementCompositeDefinition resDef) throws IOException, DataFormatException { encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions()); encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren()); } @@ -598,12 +478,52 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeEnd(); } + @Override + public void encodeResourceToWriter(IResource theResource, Writer theWriter) throws IOException { + Validate.notNull(theResource, "Resource can not be null"); + + JsonGenerator eventWriter = createJsonGenerator(theWriter); + + RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource); + encodeResourceToJsonStreamWriter(resDef, theResource, eventWriter, null); + eventWriter.flush(); + } + + @Override + public void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException { + JsonGenerator eventWriter = createJsonGenerator(theWriter); + + eventWriter.writeStartObject(); + + eventWriter.write("resourceType", TagList.ELEMENT_NAME); + + eventWriter.writeStartArray(TagList.ATTR_CATEGORY); + for (Tag next : theTagList) { + eventWriter.writeStartObject(); + + if (isNotBlank(next.getTerm())) { + eventWriter.write(Tag.ATTR_TERM, next.getTerm()); + } + if (isNotBlank(next.getLabel())) { + eventWriter.write(Tag.ATTR_LABEL, next.getLabel()); + } + if (isNotBlank(next.getScheme())) { + eventWriter.write(Tag.ATTR_SCHEME, next.getScheme()); + } + + eventWriter.writeEnd(); + } + eventWriter.writeEnd(); + + eventWriter.writeEnd(); + eventWriter.flush(); + } + /** - * 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 extensions = new ArrayList(0); List modifierExtensions = new ArrayList(0); @@ -678,6 +598,30 @@ public class JsonParser extends BaseParser implements IParser { } } + @Override + public Bundle parseBundle(Class theResourceType, Reader theReader) { + JsonReader reader = Json.createReader(theReader); + JsonObject object = reader.readObject(); + + JsonValue resourceTypeObj = object.get("resourceType"); + assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType"); + String resourceType = ((JsonString) resourceTypeObj).getString(); + if (!"Bundle".equals(resourceType)) { + throw new DataFormatException("Trying to parse bundle but found resourceType other than 'Bundle'. Found: '" + resourceType + "'"); + } + + ParserState state = ParserState.getPreAtomInstance(myContext, theResourceType, true); + state.enteringNewElement(null, "feed"); + + parseBundleChildren(object, state); + + state.endingElement(); + + Bundle retVal = state.getObject(); + + return retVal; + } + private void parseBundleChildren(JsonObject theObject, ParserState theState) { for (String nextName : theObject.keySet()) { if ("resourceType".equals(nextName)) { @@ -830,6 +774,65 @@ public class JsonParser extends BaseParser implements IParser { } } + @Override + public T parseResource(Class theResourceType, Reader theReader) { + JsonReader reader = Json.createReader(theReader); + JsonObject object = reader.readObject(); + + JsonValue resourceTypeObj = object.get("resourceType"); + assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType"); + String resourceType = ((JsonString) resourceTypeObj).getString(); + + RuntimeResourceDefinition def; + if (theResourceType != null) { + def = myContext.getResourceDefinition(theResourceType); + } else { + def = myContext.getResourceDefinition(resourceType); + } + + ParserState state = ParserState.getPreResourceInstance(def.getImplementingClass(), myContext, true); + state.enteringNewElement(null, def.getName()); + + parseChildren(object, state); + + state.endingElement(); + + @SuppressWarnings("unchecked") + T retVal = (T) state.getObject(); + + return retVal; + } + + @Override + public T parseResource(Class theResourceType, String theMessageString) { + return parseResource(theResourceType, new StringReader(theMessageString)); + } + + @Override + public TagList parseTagList(Reader theReader) { + JsonReader reader = Json.createReader(theReader); + JsonObject object = reader.readObject(); + + JsonValue resourceTypeObj = object.get("resourceType"); + assertObjectOfType(resourceTypeObj, JsonValue.ValueType.STRING, "resourceType"); + String resourceType = ((JsonString) resourceTypeObj).getString(); + + ParserState state = ParserState.getPreTagListInstance(myContext, true); + state.enteringNewElement(null, resourceType); + + parseChildren(object, state); + + state.endingElement(); + + return state.getObject(); + } + + @Override + public IParser setPrettyPrint(boolean thePrettyPrint) { + myPrettyPrint = thePrettyPrint; + return this; + } + private void writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink) { if (isNotBlank(theLink.getValue())) { theEventWriter.writeStartObject(); @@ -850,7 +853,8 @@ public class JsonParser extends BaseParser implements IParser { } } - private void writeExtensionsAsDirectChild(IResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List extensions, List modifierExtensions) throws IOException { + private void writeExtensionsAsDirectChild(IResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List extensions, + List modifierExtensions) throws IOException { if (extensions.isEmpty() == false) { theEventWriter.writeStartArray("extension"); for (HeldExtension next : extensions) { @@ -933,12 +937,13 @@ public class JsonParser extends BaseParser implements IParser { } private void writeUndeclaredExt(RuntimeResourceDefinition theResDef, IResource theResource, JsonGenerator theEventWriter, ExtensionDt ext) throws IOException { + IElement value = ext.getValue(); + theEventWriter.writeStartObject(); theEventWriter.write("url", ext.getUrl().getValue()); - IElement value = ext.getValue(); if (value == null && ext.getAllUndeclaredExtensions().isEmpty()) { - theEventWriter.writeNull(); + ourLog.debug("Extension with URL[{}] has no value", ext.getUrl().getValue()); } else if (value == null) { theEventWriter.writeStartArray("extension"); for (ExtensionDt next : ext.getUndeclaredExtensions()) { @@ -961,5 +966,4 @@ public class JsonParser extends BaseParser implements IParser { } } - } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java index 9158d2f46b7..55eb1263ac0 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/BaseClient.java @@ -60,19 +60,15 @@ public abstract class BaseClient { private boolean myPrettyPrint = false; /** - * Returns the encoding that will be used on requests. Default is - * null, which means the client will not explicitly request an - * encoding. (This is standard behaviour according to the FHIR - * specification) + * Returns the encoding that will be used on requests. Default is null, which means the client will not explicitly request an encoding. (This is standard behaviour according to the + * FHIR specification) */ public EncodingEnum getEncoding() { return myEncoding; } /** - * Sets the encoding that will be used on requests. Default is - * null, which means the client will not explicitly request an - * encoding. (This is standard behaviour according to the FHIR + * Sets the encoding that will be used on requests. Default is null, which means the client will not explicitly request an encoding. (This is standard behaviour according to the FHIR * specification) */ public BaseClient setEncoding(EncodingEnum theEncoding) { @@ -87,16 +83,14 @@ public abstract class BaseClient { } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public HttpResponse getLastResponse() { return myLastResponse; } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public String getLastResponseBody() { return myLastResponseBody; @@ -106,22 +100,22 @@ public abstract class BaseClient { return myUrlBase; } - Object invokeClient(IClientResponseHandler binding, BaseClientInvocation clientInvocation) { + T invokeClient(IClientResponseHandler binding, BaseClientInvocation clientInvocation) { return invokeClient(binding, clientInvocation, false); } - - Object invokeClient(IClientResponseHandler binding, BaseClientInvocation clientInvocation, boolean theLogRequestAndResponse) { + + T invokeClient(IClientResponseHandler binding, BaseClientInvocation clientInvocation, boolean theLogRequestAndResponse) { // TODO: handle non 2xx status codes by throwing the correct exception, // and ensure it's passed upwards HttpRequestBase httpRequest; HttpResponse response; try { httpRequest = clientInvocation.asHttpRequest(myUrlBase, createExtraParams(), getEncoding()); - + if (theLogRequestAndResponse) { ourLog.info("Client invoking: {}", httpRequest); } - + response = myClient.execute(httpRequest); } catch (DataFormatException e) { throw new FhirClientConnectionException(e); @@ -160,13 +154,24 @@ public abstract class BaseClient { } if (response.getStatusLine().getStatusCode() < 200 || response.getStatusLine().getStatusCode() > 299) { - throw BaseServerResponseException.newInstance(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()); + BaseServerResponseException exception = BaseServerResponseException.newInstance(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase()); + + try { + String body = IOUtils.toString(reader); + exception.setResponseBody(body); + } catch (Exception e) { + ourLog.debug("Failed to read input stream", e); + } finally { + IOUtils.closeQuietly(reader); + } + + throw exception; } try { return binding.invokeClient(mimeType, reader, response.getStatusLine().getStatusCode(), headers); } finally { - reader.close(); + IOUtils.closeQuietly(reader); } } catch (IllegalStateException e) { @@ -201,32 +206,28 @@ public abstract class BaseClient { } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public boolean isKeepResponses() { return myKeepResponses; } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public void setKeepResponses(boolean theKeepResponses) { myKeepResponses = theKeepResponses; } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public void setLastResponse(HttpResponse theLastResponse) { myLastResponse = theLastResponse; } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public void setLastResponseBody(String theLastResponseBody) { myLastResponseBody = theLastResponseBody; @@ -238,7 +239,7 @@ public abstract class BaseClient { return new StringReader(""); } Charset charset = null; - if (entity.getContentType() != null && entity.getContentType().getElements() != null && entity.getContentType().getElements().length>0) { + if (entity.getContentType() != null && entity.getContentType().getElements() != null && entity.getContentType().getElements().length > 0) { ContentType ct = ContentType.get(entity); charset = ct.getCharset(); } @@ -252,20 +253,16 @@ public abstract class BaseClient { } /** - * Returns the pretty print flag, which is a request to the server for it to - * return "pretty printed" responses. Note that this is currently a - * non-standard flag (_pretty) which is supported only by HAPI based servers - * (and any other servers which might implement it). + * Returns the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note that this is currently a non-standard flag (_pretty) which is supported only by + * HAPI based servers (and any other servers which might implement it). */ public boolean isPrettyPrint() { return myPrettyPrint; } /** - * Sets the pretty print flag, which is a request to the server for it to - * return "pretty printed" responses. Note that this is currently a - * non-standard flag (_pretty) which is supported only by HAPI based servers - * (and any other servers which might implement it). + * Sets the pretty print flag, which is a request to the server for it to return "pretty printed" responses. Note that this is currently a non-standard flag (_pretty) which is supported only by + * HAPI based servers (and any other servers which might implement it). */ public BaseClient setPrettyPrint(boolean thePrettyPrint) { myPrettyPrint = thePrettyPrint; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java index 9942049ac52..6e6f60de042 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/ClientInvocationHandler.java @@ -35,7 +35,7 @@ import ca.uhn.fhir.rest.server.EncodingEnum; public class ClientInvocationHandler extends BaseClient implements InvocationHandler { - private final Map myBindings = new HashMap(); + private final Map> myBindings = new HashMap>(); private final Map myMethodToLambda = new HashMap(); @@ -59,7 +59,7 @@ public class ClientInvocationHandler extends BaseClient implements InvocationHan } } - public void addBinding(Method theMethod, BaseMethodBinding theBinding) { + public void addBinding(Method theMethod, BaseMethodBinding theBinding) { myBindings.put(theMethod, theBinding); } @@ -70,7 +70,7 @@ public class ClientInvocationHandler extends BaseClient implements InvocationHan return directRetVal; } - BaseMethodBinding binding = myBindings.get(theMethod); + BaseMethodBinding binding = myBindings.get(theMethod); if (binding != null) { BaseClientInvocation clientInvocation = binding.invokeClient(theArgs); return invokeClient(binding, clientInvocation); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java index dc39bf60b1d..c8b65373ab0 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/GenericClient.java @@ -40,6 +40,7 @@ import ca.uhn.fhir.model.dstu.resource.Conformance; 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.ICriterion; import ca.uhn.fhir.rest.gclient.ICriterionInternal; import ca.uhn.fhir.rest.gclient.IQuery; @@ -68,8 +69,7 @@ public class GenericClient extends BaseClient implements IGenericClient { private HttpRequestBase myLastRequest; /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public GenericClient(FhirContext theContext, HttpClient theHttpClient, String theServerBase) { super(theHttpClient, theServerBase); @@ -83,16 +83,8 @@ public class GenericClient extends BaseClient implements IGenericClient { myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding()); } - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); - IParser parser = respType.newParser(myContext); - return parser.parseResource(Conformance.class, theResponseReader); - } - }; - - Conformance resp = (Conformance) invokeClient(binding, invocation); + ResourceResponseHandler binding = new ResourceResponseHandler(Conformance.class); + Conformance resp = invokeClient(binding, invocation); return resp; } @@ -106,15 +98,9 @@ public class GenericClient extends BaseClient implements IGenericClient { RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); final String resourceName = def.getName(); - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, resourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders); - return response; - } - }; + OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName); - MethodOutcome resp = (MethodOutcome) invokeClient(binding, invocation); + MethodOutcome resp = invokeClient(binding, invocation); return resp; } @@ -127,15 +113,8 @@ public class GenericClient extends BaseClient implements IGenericClient { } final String resourceName = myContext.getResourceDefinition(theType).getName(); - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, resourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders); - return response; - } - }; - - MethodOutcome resp = (MethodOutcome) invokeClient(binding, invocation); + OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName); + MethodOutcome resp = invokeClient(binding, invocation); return resp; } @@ -155,16 +134,8 @@ public class GenericClient extends BaseClient implements IGenericClient { myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding()); } - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); - IParser parser = respType.newParser(myContext); - return parser.parseBundle(theType, theResponseReader); - } - }; - - Bundle resp = (Bundle) invokeClient(binding, invocation); + BundleResponseHandler binding = new BundleResponseHandler(theType); + Bundle resp = invokeClient(binding, invocation); return resp; } @@ -181,17 +152,8 @@ public class GenericClient extends BaseClient implements IGenericClient { myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding()); } - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); - IParser parser = respType.newParser(myContext); - return parser.parseResource(theType, theResponseReader); - } - }; - - @SuppressWarnings("unchecked") - T resp = (T) invokeClient(binding, invocation); + ResourceResponseHandler binding = new ResourceResponseHandler(theType); + T resp = invokeClient(binding, invocation); return resp; } @@ -221,22 +183,13 @@ public class GenericClient extends BaseClient implements IGenericClient { myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding()); } - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); - IParser parser = respType.newParser(myContext); - return parser.parseBundle(theType, theResponseReader); - } - }; - - Bundle resp = (Bundle) invokeClient(binding, invocation); + BundleResponseHandler binding = new BundleResponseHandler(theType); + Bundle resp = invokeClient(binding, invocation); return resp; } /** - * For now, this is a part of the internal API of HAPI - Use with caution as - * this method may change! + * For now, this is a part of the internal API of HAPI - Use with caution as this method may change! */ public void setLastRequest(HttpRequestBase theLastRequest) { myLastRequest = theLastRequest; @@ -252,15 +205,8 @@ public class GenericClient extends BaseClient implements IGenericClient { RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); final String resourceName = def.getName(); - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, resourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders); - return response; - } - }; - - MethodOutcome resp = (MethodOutcome) invokeClient(binding, invocation); + OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName); + MethodOutcome resp = invokeClient(binding, invocation); return resp; } @@ -279,15 +225,8 @@ public class GenericClient extends BaseClient implements IGenericClient { RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); final String resourceName = def.getName(); - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, resourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders); - return response; - } - }; - - MethodOutcome resp = (MethodOutcome) invokeClient(binding, invocation); + OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName); + MethodOutcome resp = invokeClient(binding, invocation); return resp; } @@ -298,17 +237,8 @@ public class GenericClient extends BaseClient implements IGenericClient { myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding()); } - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); - IParser parser = respType.newParser(myContext); - return parser.parseResource(theType, theResponseReader); - } - }; - - @SuppressWarnings("unchecked") - T resp = (T) invokeClient(binding, invocation); + ResourceResponseHandler binding = new ResourceResponseHandler(theType); + T resp = invokeClient(binding, invocation); return resp; } @@ -321,6 +251,57 @@ public class GenericClient extends BaseClient implements IGenericClient { return myContext.getResourceDefinition(theType).getName(); } + private final class OutcomeResponseHandler implements IClientResponseHandler { + private final String myResourceName; + + private OutcomeResponseHandler(String theResourceName) { + myResourceName = theResourceName; + } + + @Override + public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, + BaseServerResponseException { + MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, myResourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders); + return response; + } + } + + private final class ResourceResponseHandler implements IClientResponseHandler { + + private Class myType; + + public ResourceResponseHandler(Class theType) { + myType = theType; + } + + @Override + public T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { + EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); + IParser parser = respType.newParser(myContext); + return parser.parseResource(myType, theResponseReader); + } + } + + private final class BundleResponseHandler implements IClientResponseHandler { + + private Class myType; + + public BundleResponseHandler(Class theType) { + myType = theType; + } + + @Override + public Bundle invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, + BaseServerResponseException { + EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); + if (respType == null) { + throw new NonFhirResponseException(theResponseStatusCode, ""); + } + IParser parser = respType.newParser(myContext); + return parser.parseBundle(myType, theResponseReader); + } + } + private class ForInternal implements IQuery { private List myCriterion = new ArrayList(); @@ -403,16 +384,9 @@ public class GenericClient extends BaseClient implements IGenericClient { myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding()); } - IClientResponseHandler binding = new IClientResponseHandler() { - @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { - EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType); - IParser parser = respType.newParser(myContext); - return parser.parseBundle(myResourceType, theResponseReader); - } - }; + BundleResponseHandler binding = new BundleResponseHandler(myResourceType); - Bundle resp = (Bundle) invokeClient(binding, invocation, myLogRequestAndResponse); + Bundle resp = invokeClient(binding, invocation, myLogRequestAndResponse); return resp; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/HttpBasicAuthInterceptor.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/HttpBasicAuthInterceptor.java index 31f46fb1050..56062675dd4 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/HttpBasicAuthInterceptor.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/client/HttpBasicAuthInterceptor.java @@ -36,7 +36,8 @@ import org.apache.http.protocol.HttpContext; * HTTP interceptor to be used for adding HTTP basic auth username/password tokens * to requests *

- * See the + * See the HAPI Documentation + * for information on how to use this class. *

*/ public class HttpBasicAuthInterceptor implements HttpRequestInterceptor { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java index 2c8c63c6a08..6aadb7e974c 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/StringCriterion.java @@ -40,4 +40,4 @@ class StringCriterion implements ICriterion, ICriterionInternal { return myValue; } -} \ No newline at end of file +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/TokenCriterion.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/TokenCriterion.java index 07b85ca56eb..7128ff558b2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/TokenCriterion.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/TokenCriterion.java @@ -46,4 +46,4 @@ class TokenCriterion implements ICriterion, ICriterionInternal { return myName; } -} \ No newline at end of file +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseAddOrDeleteTagsMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseAddOrDeleteTagsMethodBinding.java index 733d8483cc7..36fa235c07f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseAddOrDeleteTagsMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseAddOrDeleteTagsMethodBinding.java @@ -52,7 +52,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -public abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding { +public abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding { private Class myType; private Integer myIdParamIndex; @@ -89,7 +89,7 @@ public abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding } @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { + public Void invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { switch (theResponseStatusCode) { case Constants.STATUS_HTTP_200_OK: case Constants.STATUS_HTTP_201_CREATED: diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java index 89c057467a5..c3d3ba1e245 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseMethodBinding.java @@ -78,7 +78,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.util.ReflectionUtil; -public abstract class BaseMethodBinding implements IClientResponseHandler { +public abstract class BaseMethodBinding implements IClientResponseHandler { private FhirContext myContext; private Method myMethod; @@ -160,7 +160,7 @@ public abstract class BaseMethodBinding implements IClientResponseHandler { } @SuppressWarnings("unchecked") - public static BaseMethodBinding bindMethod(Method theMethod, FhirContext theContext, Object theProvider) { + public static BaseMethodBinding bindMethod(Method theMethod, FhirContext theContext, Object theProvider) { Read read = theMethod.getAnnotation(Read.class); Search search = theMethod.getAnnotation(Search.class); Metadata conformance = theMethod.getAnnotation(Metadata.class); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java index f87afd91035..d6adde2ba4a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBinding.java @@ -55,7 +55,7 @@ import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding { +public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding { private static final String LABEL = "label=\""; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseOutcomeReturningMethodBinding.class); private static final String SCHEME = "scheme=\""; @@ -94,7 +94,7 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin } @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { + public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { switch (theResponseStatusCode) { case Constants.STATUS_HTTP_200_OK: case Constants.STATUS_HTTP_201_CREATED: diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java index bfe18a84608..f06b9644aff 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/BaseResourceReturningMethodBinding.java @@ -65,7 +65,7 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; -abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding { +abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding { protected static final Set ALLOWED_PARAMS; static { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java index 0121777b119..19f8c1d2120 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/GetTagsMethodBinding.java @@ -51,7 +51,7 @@ import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -public class GetTagsMethodBinding extends BaseMethodBinding { +public class GetTagsMethodBinding extends BaseMethodBinding { private Class myType; private Integer myIdParamIndex; @@ -80,7 +80,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding { } @Override - public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { + public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException { if (theResponseStatusCode == Constants.STATUS_HTTP_200_OK) { IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theResponseStatusCode); TagList retVal = parser.parseTagList(theResponseReader); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java index 0998eec318a..3c4a6d861ad 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/IClientResponseHandler.java @@ -27,8 +27,8 @@ import java.util.Map; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; -public interface IClientResponseHandler { +public interface IClientResponseHandler { - Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException; + T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map> theHeaders) throws IOException, BaseServerResponseException; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/RestfulServerTesterServlet.java similarity index 54% rename from hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java rename to hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/RestfulServerTesterServlet.java index 39925f9f1b1..722be19a481 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/PublicTesterServlet.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/tester/RestfulServerTesterServlet.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -39,6 +40,7 @@ import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.WriterOutputStream; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpResponse; @@ -66,10 +68,10 @@ import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; -public class PublicTesterServlet extends HttpServlet { +public class RestfulServerTesterServlet extends HttpServlet { private static final boolean DEBUGMODE = true; - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PublicTesterServlet.class); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServerTesterServlet.class); private static final String PUBLIC_TESTER_RESULT_HTML = "/PublicTesterResult.html"; private static final long serialVersionUID = 1L; private FhirContext myCtx; @@ -77,8 +79,9 @@ public class PublicTesterServlet extends HttpServlet { private HashMap myStaticResources; private TemplateEngine myTemplateEngine; + private Set myFilterHeaders; - public PublicTesterServlet() { + public RestfulServerTesterServlet() { myStaticResources = new HashMap(); myStaticResources.put("jquery-2.1.0.min.js", "text/javascript"); myStaticResources.put("PublicTester.js", "text/javascript"); @@ -95,6 +98,10 @@ public class PublicTesterServlet extends HttpServlet { myCtx = new FhirContext(); } + public FhirContext getFhirContext() { + return myCtx; + } + @Override public void init(ServletConfig theConfig) throws ServletException { myTemplateEngine = new TemplateEngine(); @@ -120,7 +127,7 @@ public class PublicTesterServlet extends HttpServlet { } private void streamResponse(String theResourceName, String theContentType, HttpServletResponse theResp) throws IOException { - InputStream res = PublicTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/" + theResourceName); + InputStream res = RestfulServerTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/" + theResourceName); theResp.setContentType(theContentType); IOUtils.copy(res, theResp.getOutputStream()); } @@ -132,22 +139,22 @@ public class PublicTesterServlet extends HttpServlet { } try { - ourLog.info("RequestURI: {}", theReq.getPathInfo()); + ourLog.info("RequestURI: {}", theReq.getPathInfo()); - String resName = theReq.getPathInfo().substring(1); - if (myStaticResources.containsKey(resName)) { - streamResponse(resName, myStaticResources.get(resName), theResp); - return; - } + String resName = theReq.getPathInfo().substring(1); + if (myStaticResources.containsKey(resName)) { + streamResponse(resName, myStaticResources.get(resName), theResp); + return; + } - ConformanceClient client = myCtx.newRestfulClient(ConformanceClient.class, myServerBase); - Conformance conformance = client.getConformance(); + ConformanceClient client = myCtx.newRestfulClient(ConformanceClient.class, myServerBase); + Conformance conformance = client.getConformance(); - WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale()); - ctx.setVariable("conf", conformance); - ctx.setVariable("base", myServerBase); - ctx.setVariable("jsonEncodedConf", myCtx.newJsonParser().encodeResourceToString(conformance)); - myTemplateEngine.process(theReq.getPathInfo(), ctx, theResp.getWriter()); + WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale()); + ctx.setVariable("conf", conformance); + ctx.setVariable("base", myServerBase); + ctx.setVariable("jsonEncodedConf", myCtx.newJsonParser().encodeResourceToString(conformance)); + myTemplateEngine.process(theReq.getPathInfo(), ctx, theResp.getWriter()); } catch (Exception e) { ourLog.error("Failed to respond", e); theResp.sendError(500, e.getMessage()); @@ -183,164 +190,164 @@ public class PublicTesterServlet extends HttpServlet { boolean returnsResource; try { - if ("conformance".equals(method)) { - returnsResource = true; - client.conformance(); - } else if ("read".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String id = StringUtils.defaultString(theReq.getParameter("id")); - if (StringUtils.isBlank(id)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); - } - returnsResource = true; + if ("conformance".equals(method)) { + returnsResource = true; + client.conformance(); + } else if ("read".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); + } + returnsResource = true; - client.read(def.getImplementingClass(), new IdDt(id)); + client.read(def.getImplementingClass(), new IdDt(id)); - } else if ("vread".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String id = StringUtils.defaultString(theReq.getParameter("id")); - if (StringUtils.isBlank(id)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); - } - - String versionId = StringUtils.defaultString(theReq.getParameter("versionid")); - if (StringUtils.isBlank(versionId)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No Version ID specified"); - } - returnsResource = true; - - client.vread(def.getImplementingClass(), new IdDt(id), new IdDt(versionId)); - - } else if ("delete".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String id = StringUtils.defaultString(theReq.getParameter("id")); - if (StringUtils.isBlank(id)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); - } - - returnsResource = false; - - client.delete(def.getImplementingClass(), new IdDt(id)); - - } else if ("history-instance".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String id = StringUtils.defaultString(theReq.getParameter("id")); - if (StringUtils.isBlank(id)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); - } - - returnsResource = false; - - client.history(def.getImplementingClass(), new IdDt(id)); - - } else if ("create".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String resourceText = StringUtils.defaultString(theReq.getParameter("resource")); - if (StringUtils.isBlank(resourceText)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No resource content specified"); - } - - IResource resource; - if (client.getEncoding() == null || client.getEncoding() == EncodingEnum.XML) { - resource = myCtx.newXmlParser().parseResource(def.getImplementingClass(), resourceText); - } else { - resource = myCtx.newJsonParser().parseResource(def.getImplementingClass(), resourceText); - } - returnsResource = false; - - client.create(resource); - - } else if ("validate".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String resourceText = StringUtils.defaultString(theReq.getParameter("resource")); - if (StringUtils.isBlank(resourceText)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No resource content specified"); - } - - IResource resource; - if (client.getEncoding() == null || client.getEncoding() == EncodingEnum.XML) { - resource = myCtx.newXmlParser().parseResource(def.getImplementingClass(), resourceText); - } else { - resource = myCtx.newJsonParser().parseResource(def.getImplementingClass(), resourceText); - } - returnsResource = false; - - client.validate(resource); - - } else if ("update".equals(method)) { - RuntimeResourceDefinition def = getResourceType(theReq); - String resourceText = StringUtils.defaultString(theReq.getParameter("resource")); - if (StringUtils.isBlank(resourceText)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No resource content specified"); - } - - String id = StringUtils.defaultString(theReq.getParameter("id")); - if (StringUtils.isBlank(id)) { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); - } - - IResource resource; - if (client.getEncoding() == null || client.getEncoding() == EncodingEnum.XML) { - resource = myCtx.newXmlParser().parseResource(def.getImplementingClass(), resourceText); - } else { - resource = myCtx.newJsonParser().parseResource(def.getImplementingClass(), resourceText); - } - returnsResource = false; - - client.update(new IdDt(id), resource); - - } else if ("searchType".equals(method)) { - Map> params = new HashMap>(); - - HashSet hashSet = new HashSet(theReq.getParameterMap().keySet()); - String paramName = null; - IQueryParameterType paramValue = null; - while (hashSet.isEmpty() == false) { - - String nextKey = hashSet.iterator().next(); - String nextValue = theReq.getParameter(nextKey); - paramName = null; - paramValue = null; - - if (nextKey.startsWith("param.token.")) { - int prefixLength = "param.token.".length(); - paramName = nextKey.substring(prefixLength + 2); - String systemKey = "param.token." + "1." + paramName; - String valueKey = "param.token." + "2." + paramName; - String system = theReq.getParameter(systemKey); - String value = theReq.getParameter(valueKey); - paramValue = new IdentifierDt(system, value); - hashSet.remove(systemKey); - hashSet.remove(valueKey); - } else if (nextKey.startsWith("param.string.")) { - paramName = nextKey.substring("param.string.".length()); - paramValue = new StringDt(nextValue); + } else if ("vread".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); } - if (paramName != null) { - if (params.containsKey(paramName) == false) { - params.put(paramName, new ArrayList()); + String versionId = StringUtils.defaultString(theReq.getParameter("versionid")); + if (StringUtils.isBlank(versionId)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No Version ID specified"); + } + returnsResource = true; + + client.vread(def.getImplementingClass(), new IdDt(id), new IdDt(versionId)); + + } else if ("delete".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); + } + + returnsResource = false; + + client.delete(def.getImplementingClass(), new IdDt(id)); + + } else if ("history-instance".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); + } + + returnsResource = false; + + client.history(def.getImplementingClass(), new IdDt(id)); + + } else if ("create".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String resourceText = StringUtils.defaultString(theReq.getParameter("resource")); + if (StringUtils.isBlank(resourceText)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No resource content specified"); + } + + IResource resource; + if (client.getEncoding() == null || client.getEncoding() == EncodingEnum.XML) { + resource = myCtx.newXmlParser().parseResource(def.getImplementingClass(), resourceText); + } else { + resource = myCtx.newJsonParser().parseResource(def.getImplementingClass(), resourceText); + } + returnsResource = false; + + client.create(resource); + + } else if ("validate".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String resourceText = StringUtils.defaultString(theReq.getParameter("resource")); + if (StringUtils.isBlank(resourceText)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No resource content specified"); + } + + IResource resource; + if (client.getEncoding() == null || client.getEncoding() == EncodingEnum.XML) { + resource = myCtx.newXmlParser().parseResource(def.getImplementingClass(), resourceText); + } else { + resource = myCtx.newJsonParser().parseResource(def.getImplementingClass(), resourceText); + } + returnsResource = false; + + client.validate(resource); + + } else if ("update".equals(method)) { + RuntimeResourceDefinition def = getResourceType(theReq); + String resourceText = StringUtils.defaultString(theReq.getParameter("resource")); + if (StringUtils.isBlank(resourceText)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No resource content specified"); + } + + String id = StringUtils.defaultString(theReq.getParameter("id")); + if (StringUtils.isBlank(id)) { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "No ID specified"); + } + + IResource resource; + if (client.getEncoding() == null || client.getEncoding() == EncodingEnum.XML) { + resource = myCtx.newXmlParser().parseResource(def.getImplementingClass(), resourceText); + } else { + resource = myCtx.newJsonParser().parseResource(def.getImplementingClass(), resourceText); + } + returnsResource = false; + + client.update(new IdDt(id), resource); + + } else if ("searchType".equals(method)) { + Map> params = new HashMap>(); + + HashSet hashSet = new HashSet(theReq.getParameterMap().keySet()); + String paramName = null; + IQueryParameterType paramValue = null; + while (hashSet.isEmpty() == false) { + + String nextKey = hashSet.iterator().next(); + String nextValue = theReq.getParameter(nextKey); + paramName = null; + paramValue = null; + + if (nextKey.startsWith("param.token.")) { + int prefixLength = "param.token.".length(); + paramName = nextKey.substring(prefixLength + 2); + String systemKey = "param.token." + "1." + paramName; + String valueKey = "param.token." + "2." + paramName; + String system = theReq.getParameter(systemKey); + String value = theReq.getParameter(valueKey); + paramValue = new IdentifierDt(system, value); + hashSet.remove(systemKey); + hashSet.remove(valueKey); + } else if (nextKey.startsWith("param.string.")) { + paramName = nextKey.substring("param.string.".length()); + paramValue = new StringDt(nextValue); } - params.get(paramName).add(paramValue); + + if (paramName != null) { + if (params.containsKey(paramName) == false) { + params.put(paramName, new ArrayList()); + } + params.get(paramName).add(paramValue); + } + + hashSet.remove(nextKey); } - hashSet.remove(nextKey); + RuntimeResourceDefinition def = getResourceType(theReq); + + returnsResource = false; + client.search(def.getImplementingClass(), params); + + } else { + theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid method: " + method); + return; } - - RuntimeResourceDefinition def = getResourceType(theReq); - - returnsResource = false; - client.search(def.getImplementingClass(), params); - - } else { - theResp.sendError(Constants.STATUS_HTTP_400_BAD_REQUEST, "Invalid method: " + method); - return; - } } catch (BaseServerResponseException e) { ourLog.error("Failed to invoke method", e); - returnsResource=false; + returnsResource = false; } - + HttpRequestBase lastRequest = client.getLastRequest(); String requestBody = null; String requestSyntaxHighlighterClass = null; @@ -401,6 +408,9 @@ public class PublicTesterServlet extends HttpServlet { } } + Header[] requestHeaders = applyHeaderFilters(lastRequest.getAllHeaders()); + Header[] responseHeaders = applyHeaderFilters(lastResponse.getAllHeaders()); + WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale()); ctx.setVariable("base", myServerBase); ctx.setVariable("requestUrl", requestUrl); @@ -410,8 +420,8 @@ public class PublicTesterServlet extends HttpServlet { ctx.setVariable("requestSyntaxHighlighterClass", requestSyntaxHighlighterClass); ctx.setVariable("resultBody", StringEscapeUtils.escapeHtml4(resultBody)); ctx.setVariable("resultSyntaxHighlighterClass", resultSyntaxHighlighterClass); - ctx.setVariable("requestHeaders", lastRequest.getAllHeaders()); - ctx.setVariable("responseHeaders", lastResponse.getAllHeaders()); + ctx.setVariable("requestHeaders", requestHeaders); + ctx.setVariable("responseHeaders", responseHeaders); ctx.setVariable("narrative", narrativeString); myTemplateEngine.process(PUBLIC_TESTER_RESULT_HTML, ctx, theResp.getWriter()); @@ -421,6 +431,32 @@ public class PublicTesterServlet extends HttpServlet { } } + private Header[] applyHeaderFilters(Header[] theAllHeaders) { + if (myFilterHeaders == null || myFilterHeaders.isEmpty()) { + return theAllHeaders; + } + ArrayList
retVal = new ArrayList
(); + for (Header next : theAllHeaders) { + if (!myFilterHeaders.contains(next.getName().toLowerCase())) { + retVal.add(next); + } + } + return retVal.toArray(new Header[retVal.size()]); + } + + /** + * If set, the headers named here will be stripped from requests/responses before they are displayed to the user. This can be used, for instance, to filter out "Authorization" headers. Note that + * names are not case sensitive. + */ + public void setFilterHeaders(String... theHeaderNames) { + myFilterHeaders = new HashSet(); + if (theHeaderNames != null) { + for (String next : theHeaderNames) { + myFilterHeaders.add(next.toLowerCase()); + } + } + } + private String parseNarrative(EncodingEnum theCtEnum, String theResultBody) { try { IResource resource = theCtEnum.newParser(myCtx).parseResource(theResultBody); @@ -448,10 +484,10 @@ public class PublicTesterServlet extends HttpServlet { public InputStream getResourceAsStream(TemplateProcessingParameters theTemplateProcessingParameters, String theName) { ourLog.debug("Loading template: {}", theName); if ("/".equals(theName)) { - return PublicTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/PublicTester.html"); + return RestfulServerTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/PublicTester.html"); } if (PUBLIC_TESTER_RESULT_HTML.equals(theName)) { - return PublicTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/PublicTesterResult.html"); + return RestfulServerTesterServlet.class.getResourceAsStream("/ca/uhn/fhir/rest/server/tester/PublicTesterResult.html"); } return null; diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java index e31c5f5d1b4..debb5d2e5ea 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -51,6 +51,15 @@ import ca.uhn.fhir.narrative.INarrativeGenerator; public class JsonParserTest { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserTest.class); + @Test + public void testEncodingNullExtension() { + Patient p = new Patient(); + p.addUndeclaredExtension(new ExtensionDt(false, "http://foo#bar")); + String str = new FhirContext().newJsonParser().encodeResourceToString(p); + + assertEquals("{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://foo#bar\"}]}", str); + } + @Test public void testTagList() { diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java index c4bfe306e34..abe316a774d 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java @@ -61,6 +61,7 @@ import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.QualifiedDateParam; 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; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; @@ -585,6 +586,30 @@ public class ClientTest { } + @Test + public void testReadFailureInternalError() throws Exception { + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "INTERNAL")); + Header[] headers = new Header[1]; + headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "2011-01-02T22:01:02"); + when(httpResponse.getAllHeaders()).thenReturn(headers); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT)); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Internal Failure"), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + try { + client.getPatientById(new IdDt("111")); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), containsString("INTERNAL")); + assertThat(e.getResponseBody(), containsString("Internal Failure")); + } + + } + + @Test public void testReadNoCharset() throws Exception { diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java index aa301d05e45..b5d6505922a 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java @@ -1,7 +1,10 @@ package ca.uhn.fhir.rest.client; -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.io.StringReader; import java.nio.charset.Charset; @@ -13,6 +16,7 @@ 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.Test; import org.mockito.ArgumentCaptor; @@ -24,7 +28,9 @@ import ca.uhn.fhir.model.dstu.resource.Encounter; import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.Organization; import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; public class GenericClientTest { @@ -278,4 +284,52 @@ public class GenericClientTest { } + + @SuppressWarnings("unused") + @Test + public void testSearchWithInternalServerError() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.search().forResource(Patient.class).execute(); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), StringContains.containsString("AAA")); + } + + } + + + @SuppressWarnings("unused") + @Test + public void testSearchWithNonFhirResponse() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor 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_TEXT + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.search().forResource(Patient.class).execute(); + fail(); + } catch (NonFhirResponseException e) { + assertThat(e.getMessage(), StringContains.containsString("AAA")); + } + + } + } diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java index 40170a183ba..96b5feaf60c 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/rest/server/TesterTest.java @@ -40,7 +40,7 @@ import ca.uhn.fhir.rest.annotation.Update; import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; -import ca.uhn.fhir.rest.server.tester.PublicTesterServlet; +import ca.uhn.fhir.rest.server.tester.RestfulServerTesterServlet; import ca.uhn.fhir.testutil.RandomServerPortProvider; public class TesterTest { @@ -62,7 +62,7 @@ public class TesterTest { ServletContextHandler proxyHandler = new ServletContextHandler(); proxyHandler.setContextPath("/"); - PublicTesterServlet testerServlet = new PublicTesterServlet(); + RestfulServerTesterServlet testerServlet = new RestfulServerTesterServlet(); testerServlet.setServerBase("http://localhost:" + myPort + "/fhir/context"); // testerServlet.setServerBase("http://fhir.healthintersections.com.au/open"); ServletHolder handler = new ServletHolder();