Fix some bugs on the generic client

This commit is contained in:
jamesagnew 2014-05-09 17:54:55 -04:00
parent b937d5c2dc
commit fb998a6a32
18 changed files with 606 additions and 506 deletions

View File

@ -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<String> BUNDLE_TEXTNODE_CHILDREN;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParser.HeldExtension.class);
static {
HashSet<String> hashSet = new HashSet<String>();
hashSet.add("title");
@ -105,6 +106,48 @@ public class JsonParser extends BaseParser implements IParser {
myContext = theContext;
}
private void addToHeldExtensions(int valueIdx, ArrayList<ArrayList<HeldExtension>> 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<JsonParser.HeldExtension>());
}
list.get(valueIdx).add(new HeldExtension(theDef, theValue));
}
private void addToHeldExtensions(int valueIdx, List<ExtensionDt> ext, ArrayList<ArrayList<HeldExtension>> 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<JsonParser.HeldExtension>());
}
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<String, Object> properties = new HashMap<String, Object>(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 <T extends IResource> Bundle parseBundle(Class<T> 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<Bundle> state = ParserState.getPreAtomInstance(myContext, theResourceType, true);
state.enteringNewElement(null, "feed");
parseBundleChildren(object, state);
state.endingElement();
Bundle retVal = state.getObject();
return retVal;
}
@Override
public <T extends IResource> T parseResource(Class<T> 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<? extends IResource> 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 extends IResource> T parseResource(Class<T> 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<TagList> 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<ArrayList<HeldExtension>> 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<JsonParser.HeldExtension>());
}
list.get(valueIdx).add(new HeldExtension(theDef, theValue));
}
private void addToHeldExtensions(int valueIdx, List<ExtensionDt> ext, ArrayList<ArrayList<HeldExtension>> 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<JsonParser.HeldExtension>());
}
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<String, Object> properties = new HashMap<String, Object>(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<? 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();
@ -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<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
@ -678,6 +598,30 @@ public class JsonParser extends BaseParser implements IParser {
}
}
@Override
public <T extends IResource> Bundle parseBundle(Class<T> 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<Bundle> 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 extends IResource> T parseResource(Class<T> 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<? extends IResource> 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 extends IResource> T parseResource(Class<T> 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<TagList> 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<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) {
@ -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 {
}
}
}

View File

@ -60,19 +60,15 @@ public abstract class BaseClient {
private boolean myPrettyPrint = false;
/**
* Returns the encoding that will be used on requests. Default is
* <code>null</code>, 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 <code>null</code>, 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
* <code>null</code>, 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 <code>null</code>, 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> T invokeClient(IClientResponseHandler<T> binding, BaseClientInvocation clientInvocation) {
return invokeClient(binding, clientInvocation, false);
}
Object invokeClient(IClientResponseHandler binding, BaseClientInvocation clientInvocation, boolean theLogRequestAndResponse) {
<T> T invokeClient(IClientResponseHandler<T> 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;

View File

@ -35,7 +35,7 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
public class ClientInvocationHandler extends BaseClient implements InvocationHandler {
private final Map<Method, BaseMethodBinding> myBindings = new HashMap<Method, BaseMethodBinding>();
private final Map<Method, BaseMethodBinding<?>> myBindings = new HashMap<Method, BaseMethodBinding<?>>();
private final Map<Method, ILambda> myMethodToLambda = new HashMap<Method, ILambda>();
@ -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);

View File

@ -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<String, List<String>> 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<Conformance> binding = new ResourceResponseHandler<Conformance>(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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<T> binding = new ResourceResponseHandler<T>(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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<T> binding = new ResourceResponseHandler<T>(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<MethodOutcome> {
private final String myResourceName;
private OutcomeResponseHandler(String theResourceName) {
myResourceName = theResourceName;
}
@Override
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
BaseServerResponseException {
MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, myResourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
return response;
}
}
private final class ResourceResponseHandler<T extends IResource> implements IClientResponseHandler<T> {
private Class<T> myType;
public ResourceResponseHandler(Class<T> theType) {
myType = theType;
}
@Override
public T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
IParser parser = respType.newParser(myContext);
return parser.parseResource(myType, theResponseReader);
}
}
private final class BundleResponseHandler implements IClientResponseHandler<Bundle> {
private Class<? extends IResource> myType;
public BundleResponseHandler(Class<? extends IResource> theType) {
myType = theType;
}
@Override
public Bundle invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> 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<ICriterionInternal> myCriterion = new ArrayList<ICriterionInternal>();
@ -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<String, List<String>> 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;
}

View File

@ -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
* <p>
* See the
* See the <a href="http://hl7api.sourceforge.net/hapi-fhir/doc_rest_client.html#HTTP_Basic_Authorization">HAPI Documentation</a>
* for information on how to use this class.
* </p>
*/
public class HttpBasicAuthInterceptor implements HttpRequestInterceptor {

View File

@ -40,4 +40,4 @@ class StringCriterion implements ICriterion, ICriterionInternal {
return myValue;
}
}
}

View File

@ -46,4 +46,4 @@ class TokenCriterion implements ICriterion, ICriterionInternal {
return myName;
}
}
}

View File

@ -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<Void> {
private Class<? extends IResource> 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<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
public Void 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:

View File

@ -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<T> implements IClientResponseHandler<T> {
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);

View File

@ -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<MethodOutcome> {
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<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:

View File

@ -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<Object> {
protected static final Set<String> ALLOWED_PARAMS;
static {

View File

@ -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<TagList> {
private Class<? extends IResource> myType;
private Integer myIdParamIndex;
@ -80,7 +80,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding {
}
@Override
public Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
if (theResponseStatusCode == Constants.STATUS_HTTP_200_OK) {
IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theResponseStatusCode);
TagList retVal = parser.parseTagList(theResponseReader);

View File

@ -27,8 +27,8 @@ import java.util.Map;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
public interface IClientResponseHandler {
public interface IClientResponseHandler<T> {
Object invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException;
T invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException;
}

View File

@ -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<String, String> myStaticResources;
private TemplateEngine myTemplateEngine;
private Set<String> myFilterHeaders;
public PublicTesterServlet() {
public RestfulServerTesterServlet() {
myStaticResources = new HashMap<String, String>();
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<String, List<IQueryParameterType>> params = new HashMap<String, List<IQueryParameterType>>();
HashSet<String> hashSet = new HashSet<String>(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<IQueryParameterType>());
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<String, List<IQueryParameterType>> params = new HashMap<String, List<IQueryParameterType>>();
HashSet<String> hashSet = new HashSet<String>(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<IQueryParameterType>());
}
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<Header> retVal = new ArrayList<Header>();
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<String>();
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;

View File

@ -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() {

View File

@ -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<HttpUriRequest> 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 {

View File

@ -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<HttpUriRequest> 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<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_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"));
}
}
}

View File

@ -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();