Add interceptor framework
This commit is contained in:
parent
2285d3812e
commit
d15dbd4317
|
@ -6,6 +6,7 @@
|
|||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="bin" path="src/site/example/java"/>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
<wb-module deploy-name="hapi-fhir-base">
|
||||
<wb-resource deploy-path="/" source-path="/src/main/java"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/main/resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/site/example/java"/>
|
||||
</wb-module>
|
||||
</project-modules>
|
||||
|
|
|
@ -76,7 +76,7 @@
|
|||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.6</version>
|
||||
<version>${slf4j_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
|
|
|
@ -14,6 +14,19 @@
|
|||
Search parameters are not properly escaped and unescaped. E.g. for a token parameter such as
|
||||
"&identifier=system|codepart1\|codepart2"
|
||||
</action>
|
||||
<action type="add">
|
||||
Add support for OPTIONS verb (which returns the server conformance statement)
|
||||
</action>
|
||||
<action type="add">
|
||||
Add support for CORS headers in server
|
||||
</action>
|
||||
<action type="add">
|
||||
Bump SLF4j dependency to latest version (1.7.7)
|
||||
</action>
|
||||
<action type="add">
|
||||
Add interceptor framework for clients (annotation based and generic), and add interceptors
|
||||
for configurable logging, capturing requests and responses, and HTTP basic auth.
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.4" date="2014-Jul-13">
|
||||
<action type="add">
|
||||
|
|
|
@ -127,7 +127,7 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
*/
|
||||
@Override
|
||||
protected boolean isBaseEmpty() {
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText);
|
||||
return super.isBaseEmpty() && ElementUtil.isEmpty(myLanguage, myText, myId);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -179,7 +179,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
for (BundleEntry nextEntry : theBundle.getEntries()) {
|
||||
eventWriter.writeStartObject();
|
||||
|
||||
if (nextEntry.getDeletedAt() !=null&&nextEntry.getDeletedAt().isEmpty()==false) {
|
||||
boolean deleted = nextEntry.getDeletedAt() !=null&&nextEntry.getDeletedAt().isEmpty()==false;
|
||||
if (deleted) {
|
||||
writeTagWithTextNode(eventWriter, "deleted", nextEntry.getDeletedAt());
|
||||
}
|
||||
writeTagWithTextNode(eventWriter, "title", nextEntry.getTitle());
|
||||
|
@ -210,7 +211,7 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
writeAuthor(nextEntry, eventWriter);
|
||||
|
||||
IResource resource = nextEntry.getResource();
|
||||
if (resource != null && !resource.isEmpty()) {
|
||||
if (resource != null && !resource.isEmpty() && !deleted) {
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(resource);
|
||||
encodeResourceToJsonStreamWriter(resDef, resource, eventWriter, "content", false);
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
}
|
||||
|
||||
IResource resource = nextEntry.getResource();
|
||||
if (resource != null && !resource.isEmpty()) {
|
||||
if (resource != null && !resource.isEmpty() && !deleted) {
|
||||
eventWriter.writeStartElement("content");
|
||||
eventWriter.writeAttribute("type", "text/xml");
|
||||
encodeResourceToXmlStreamWriter(resource, eventWriter, false);
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Map;
|
|||
|
||||
import org.apache.http.client.HttpClient;
|
||||
|
||||
import ch.qos.logback.core.pattern.util.RegularEscapeUtil;
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
|
@ -51,6 +52,8 @@ public class ClientInvocationHandler extends BaseClient implements InvocationHan
|
|||
|
||||
myMethodToLambda.put(theClientType.getMethod("setEncoding", EncodingEnum.class), new SetEncodingLambda());
|
||||
myMethodToLambda.put(theClientType.getMethod("setPrettyPrint", boolean.class), new SetPrettyPrintLambda());
|
||||
myMethodToLambda.put(theClientType.getMethod("registerInterceptor", IClientInterceptor.class), new RegisterInterceptorLambda());
|
||||
myMethodToLambda.put(theClientType.getMethod("unregisterInterceptor", IClientInterceptor.class), new UnregisterInterceptorLambda());
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new ConfigurationException("Failed to find methods on client. This is a HAPI bug!", e);
|
||||
|
@ -105,5 +108,22 @@ public class ClientInvocationHandler extends BaseClient implements InvocationHan
|
|||
return null;
|
||||
}
|
||||
}
|
||||
private class UnregisterInterceptorLambda implements ILambda {
|
||||
@Override
|
||||
public Object handle(Object[] theArgs) {
|
||||
IClientInterceptor interceptor = (IClientInterceptor) theArgs[0];
|
||||
unregisterInterceptor(interceptor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private class RegisterInterceptorLambda implements ILambda {
|
||||
@Override
|
||||
public Object handle(Object[] theArgs) {
|
||||
IClientInterceptor interceptor = (IClientInterceptor) theArgs[0];
|
||||
registerInterceptor(interceptor);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,12 +26,14 @@ import java.io.IOException;
|
|||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
|
||||
|
@ -49,6 +51,8 @@ import ca.uhn.fhir.parser.IParser;
|
|||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
||||
import ca.uhn.fhir.rest.gclient.ICreate;
|
||||
import ca.uhn.fhir.rest.gclient.ICreateTyped;
|
||||
import ca.uhn.fhir.rest.gclient.ICriterion;
|
||||
import ca.uhn.fhir.rest.gclient.ICriterionInternal;
|
||||
import ca.uhn.fhir.rest.gclient.IGetPage;
|
||||
|
@ -77,6 +81,7 @@ import ca.uhn.fhir.rest.method.ValidateMethodBinding;
|
|||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class GenericClient extends BaseClient implements IGenericClient {
|
||||
|
||||
|
@ -106,6 +111,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICreate create() {
|
||||
return new CreateInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome create(IResource theResource) {
|
||||
BaseHttpClientInvocation invocation = CreateMethodBinding.createCreateInvocation(theResource, myContext);
|
||||
|
@ -150,11 +160,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return new GetTagsInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransaction transaction() {
|
||||
return new TransactionInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IResource> Bundle history(final Class<T> theType, IdDt theIdDt, DateTimeDt theSince, Integer theLimit) {
|
||||
String resourceName = theType != null ? toResourceName(theType) : null;
|
||||
|
@ -179,12 +184,17 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return myLogRequestAndResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGetPage loadPage() {
|
||||
return new LoadPageInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IResource> T read(final Class<T> theType, IdDt theId) {
|
||||
if (theId == null || theId.hasIdPart() == false) {
|
||||
throw new IllegalArgumentException("theId does not contain a valid ID, is: " + theId);
|
||||
}
|
||||
|
||||
|
||||
HttpGetClientInvocation invocation = ReadMethodBinding.createReadInvocation(theId, toResourceName(theType));
|
||||
if (isKeepResponses()) {
|
||||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding());
|
||||
|
@ -241,6 +251,15 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
myLogRequestAndResponse = theLogRequestAndResponse;
|
||||
}
|
||||
|
||||
private String toResourceName(Class<? extends IResource> theType) {
|
||||
return myContext.getResourceDefinition(theType).getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransaction transaction() {
|
||||
return new TransactionInternal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> transaction(List<IResource> theResources) {
|
||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(theResources, myContext);
|
||||
|
@ -305,15 +324,18 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return vread(theType, new IdDt(theId), new IdDt(theVersionId));
|
||||
}
|
||||
|
||||
private String toResourceName(Class<? extends IResource> theType) {
|
||||
return myContext.getResourceDefinition(theType).getName();
|
||||
}
|
||||
|
||||
private abstract class BaseClientExecutable<T extends IClientExecutable<?, ?>, Y> implements IClientExecutable<T, Y> {
|
||||
private EncodingEnum myParamEncoding;
|
||||
private Boolean myPrettyPrint;
|
||||
private boolean myQueryLogRequestAndResponse;
|
||||
|
||||
protected void addParam(Map<String, List<String>> params, String parameterName, String parameterValue) {
|
||||
if (!params.containsKey(parameterName)) {
|
||||
params.put(parameterName, new ArrayList<String>());
|
||||
}
|
||||
params.get(parameterName).add(parameterValue);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T andLogRequestAndResponse(boolean theLogRequestAndResponse) {
|
||||
|
@ -328,26 +350,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return (T) this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T encodedXml() {
|
||||
myParamEncoding = EncodingEnum.XML;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T prettyPrint() {
|
||||
myPrettyPrint = true;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
protected void addParam(Map<String, List<String>> params, String parameterName, String parameterValue) {
|
||||
if (!params.containsKey(parameterName)) {
|
||||
params.put(parameterName, new ArrayList<String>());
|
||||
}
|
||||
params.get(parameterName).add(parameterValue);
|
||||
}
|
||||
|
||||
protected <Z> Z invoke(Map<String, List<String>> theParams, IClientResponseHandler<Z> theHandler, BaseHttpClientInvocation theInvocation) {
|
||||
if (myParamEncoding != null) {
|
||||
theParams.put(Constants.PARAM_FORMAT, Collections.singletonList(myParamEncoding.getFormatContentType()));
|
||||
|
@ -365,6 +374,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return resp;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T prettyPrint() {
|
||||
myPrettyPrint = true;
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class BundleResponseHandler implements IClientResponseHandler<Bundle> {
|
||||
|
@ -376,7 +392,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Bundle invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
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 NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||
|
@ -385,19 +402,71 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return parser.parseBundle(myType, theResponseReader);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ResourceListResponseHandler implements IClientResponseHandler<List<IResource>> {
|
||||
|
||||
private Class<? extends IResource> myType;
|
||||
private class CreateInternal extends BaseClientExecutable<ICreateTyped, MethodOutcome> implements ICreate, ICreateTyped {
|
||||
|
||||
private String myId;
|
||||
private IResource myResource;
|
||||
private String myResourceBody;
|
||||
|
||||
@Override
|
||||
public MethodOutcome execute() {
|
||||
if (myResource == null) {
|
||||
EncodingEnum encoding = null;
|
||||
for (int i = 0; i < myResourceBody.length() && encoding == null; i++) {
|
||||
switch (myResourceBody.charAt(i)) {
|
||||
case '<':
|
||||
encoding = EncodingEnum.XML;
|
||||
break;
|
||||
case '{':
|
||||
encoding = EncodingEnum.JSON;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (encoding == null) {
|
||||
throw new InvalidRequestException("FHIR client can't determine resource encoding");
|
||||
}
|
||||
myResource = encoding.newParser(myContext).parseResource(myResourceBody);
|
||||
}
|
||||
|
||||
BaseHttpClientInvocation invocation = CreateMethodBinding.createCreateInvocation(myResource,myResourceBody, myId, myContext);
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
|
||||
final String resourceName = def.getName();
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
|
||||
|
||||
Map<String, List<String>> params = new HashMap<String, List<String>>();
|
||||
return invoke(params, binding, invocation);
|
||||
|
||||
public ResourceListResponseHandler(Class<? extends IResource> theType) {
|
||||
myType = theType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
return new BundleResponseHandler(myType).invokeClient(theResponseMimeType, theResponseReader, theResponseStatusCode, theHeaders).toListOfResources();
|
||||
public ICreateTyped resource(IResource theResource) {
|
||||
Validate.notNull(theResource, "Resource can not be null");
|
||||
myResource = theResource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICreateTyped resource(String theResourceBody) {
|
||||
Validate.notBlank(theResourceBody, "Body can not be null or blank");
|
||||
myResourceBody = theResourceBody;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateInternal withId(IdDt theId) {
|
||||
myId = theId.getIdPart();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreateInternal withId(String theId) {
|
||||
myId = theId;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ForInternal extends BaseClientExecutable<IQuery, Bundle> implements IQuery {
|
||||
|
@ -496,10 +565,31 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
}
|
||||
|
||||
private class GetPageInternal extends BaseClientExecutable<IGetPageTyped, Bundle> implements IGetPageTyped {
|
||||
|
||||
private String myUrl;
|
||||
|
||||
public GetPageInternal(String theUrl) {
|
||||
myUrl = theUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle execute() {
|
||||
|
||||
BundleResponseHandler binding = new BundleResponseHandler(null);
|
||||
HttpSimpleGetClientInvocation invocation = new HttpSimpleGetClientInvocation(myUrl);
|
||||
|
||||
Map<String, List<String>> params = null;
|
||||
return invoke(params, binding, invocation);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GetTagsInternal extends BaseClientExecutable<IGetTags, TagList> implements IGetTags {
|
||||
|
||||
private String myResourceName;
|
||||
private String myId;
|
||||
private String myResourceName;
|
||||
private String myVersionId;
|
||||
|
||||
@Override
|
||||
|
@ -537,14 +627,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
private void setResourceClass(Class<? extends IResource> theClass) {
|
||||
if (theClass != null) {
|
||||
myResourceName = myContext.getResourceDefinition(theClass).getName();
|
||||
} else {
|
||||
myResourceName = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGetTags forResource(Class<? extends IResource> theClass, String theId) {
|
||||
setResourceClass(theClass);
|
||||
|
@ -560,6 +642,33 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return this;
|
||||
}
|
||||
|
||||
private void setResourceClass(Class<? extends IResource> theClass) {
|
||||
if (theClass != null) {
|
||||
myResourceName = myContext.getResourceDefinition(theClass).getName();
|
||||
} else {
|
||||
myResourceName = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class LoadPageInternal implements IGetPage {
|
||||
|
||||
@Override
|
||||
public IGetPageTyped next(Bundle theBundle) {
|
||||
return new GetPageInternal(theBundle.getLinkNext().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGetPageTyped previous(Bundle theBundle) {
|
||||
return new GetPageInternal(theBundle.getLinkPrevious().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGetPageTyped url(String thePageUrl) {
|
||||
return new GetPageInternal(thePageUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class OutcomeResponseHandler implements IClientResponseHandler<MethodOutcome> {
|
||||
|
@ -570,7 +679,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
MethodOutcome response = BaseOutcomeReturningMethodBinding.process2xxResponse(myContext, myResourceName, theResponseStatusCode, theResponseMimeType, theResponseReader, theHeaders);
|
||||
return response;
|
||||
}
|
||||
|
@ -595,14 +705,29 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
}
|
||||
|
||||
private final class ResourceListResponseHandler implements IClientResponseHandler<List<IResource>> {
|
||||
|
||||
private Class<? extends IResource> myType;
|
||||
|
||||
public ResourceListResponseHandler(Class<? extends IResource> theType) {
|
||||
myType = theType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IResource> invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
return new BundleResponseHandler(myType).invokeClient(theResponseMimeType, theResponseReader, theResponseStatusCode, theHeaders).toListOfResources();
|
||||
}
|
||||
}
|
||||
|
||||
private final class ResourceResponseHandler<T extends IResource> implements IClientResponseHandler<T> {
|
||||
|
||||
private Class<T> myType;
|
||||
private IdDt myId;
|
||||
private Class<T> myType;
|
||||
|
||||
public ResourceResponseHandler(Class<T> theType, IdDt theId) {
|
||||
myType = theType;
|
||||
myId=theId;
|
||||
myId = theId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -613,11 +738,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
IParser parser = respType.newParser(myContext);
|
||||
T retVal = parser.parseResource(myType, theResponseReader);
|
||||
|
||||
|
||||
if (myId != null) {
|
||||
retVal.setId(myId);
|
||||
}
|
||||
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
@ -666,7 +791,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
private final class TagListResponseHandler implements IClientResponseHandler<TagList> {
|
||||
|
||||
@Override
|
||||
public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException {
|
||||
public TagList invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException,
|
||||
BaseServerResponseException {
|
||||
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (respType == null) {
|
||||
throw NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||
|
@ -676,94 +802,47 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGetPage loadPage() {
|
||||
return new LoadPageInternal();
|
||||
}
|
||||
private final class TransactionExecutable<T> extends BaseClientExecutable<ITransactionTyped<T>, T> implements ITransactionTyped<T> {
|
||||
|
||||
private final class LoadPageInternal implements IGetPage {
|
||||
private Bundle myBundle;
|
||||
private List<IResource> myResources;
|
||||
|
||||
@Override
|
||||
public IGetPageTyped previous(Bundle theBundle) {
|
||||
return new GetPageInternal(theBundle.getLinkPrevious().getValue());
|
||||
public TransactionExecutable(Bundle theResources) {
|
||||
myBundle = theResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IGetPageTyped next(Bundle theBundle) {
|
||||
return new GetPageInternal(theBundle.getLinkNext().getValue());
|
||||
public TransactionExecutable(List<IResource> theResources) {
|
||||
myResources = theResources;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public IGetPageTyped url(String thePageUrl) {
|
||||
return new GetPageInternal(thePageUrl);
|
||||
public T execute() {
|
||||
if (myResources != null) {
|
||||
ResourceListResponseHandler binding = new ResourceListResponseHandler(null);
|
||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myResources, myContext);
|
||||
Map<String, List<String>> params = null;
|
||||
return (T) invoke(params, binding, invocation);
|
||||
} else {
|
||||
BundleResponseHandler binding = new BundleResponseHandler(null);
|
||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBundle, myContext);
|
||||
Map<String, List<String>> params = null;
|
||||
return (T) invoke(params, binding, invocation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final class TransactionInternal implements ITransaction {
|
||||
|
||||
@Override
|
||||
public ITransactionTyped<List<IResource>> withResources(List<IResource> theResources) {
|
||||
return new TransactionExecutable<List<IResource>>(theResources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITransactionTyped<Bundle> withBundle(Bundle theResources) {
|
||||
return new TransactionExecutable<Bundle>(theResources);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private final class TransactionExecutable<T> extends BaseClientExecutable<ITransactionTyped<T>, T> implements ITransactionTyped<T>{
|
||||
|
||||
private List<IResource> myResources;
|
||||
private Bundle myBundle;
|
||||
|
||||
public TransactionExecutable(List<IResource> theResources) {
|
||||
myResources=theResources;
|
||||
}
|
||||
|
||||
public TransactionExecutable(Bundle theResources) {
|
||||
myBundle=theResources;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public T execute() {
|
||||
if (myResources!=null) {
|
||||
ResourceListResponseHandler binding = new ResourceListResponseHandler(null);
|
||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myResources, myContext);
|
||||
Map<String, List<String>> params = null;
|
||||
return (T) invoke(params, binding, invocation);
|
||||
}else {
|
||||
BundleResponseHandler binding = new BundleResponseHandler(null);
|
||||
BaseHttpClientInvocation invocation = TransactionMethodBinding.createTransactionInvocation(myBundle, myContext);
|
||||
Map<String, List<String>> params = null;
|
||||
return (T) invoke(params, binding, invocation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class GetPageInternal extends BaseClientExecutable<IGetPageTyped, Bundle> implements IGetPageTyped {
|
||||
|
||||
private String myUrl;
|
||||
|
||||
public GetPageInternal(String theUrl) {
|
||||
myUrl = theUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle execute() {
|
||||
|
||||
BundleResponseHandler binding = new BundleResponseHandler(null);
|
||||
HttpSimpleGetClientInvocation invocation = new HttpSimpleGetClientInvocation(myUrl);
|
||||
|
||||
Map<String, List<String>> params = null;
|
||||
return invoke(params, binding, invocation);
|
||||
|
||||
public ITransactionTyped<List<IResource>> withResources(List<IResource> theResources) {
|
||||
return new TransactionExecutable<List<IResource>>(theResources);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.auth.AuthState;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.impl.auth.BasicScheme;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Library
|
||||
|
@ -20,27 +34,11 @@ package ca.uhn.fhir.rest.client;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpException;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpRequestInterceptor;
|
||||
import org.apache.http.auth.AuthState;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.protocol.HttpClientContext;
|
||||
import org.apache.http.impl.auth.BasicScheme;
|
||||
import org.apache.http.protocol.HttpContext;
|
||||
|
||||
/**
|
||||
* HTTP interceptor to be used for adding HTTP basic auth username/password tokens
|
||||
* to requests
|
||||
* <p>
|
||||
* 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>
|
||||
* @deprecated Use {@link ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor} instead. Note that that class is a HAPI client interceptor instead of being a commons-httpclient interceptor, so you register it to your client instance once it's created using {@link IGenericClient#registerInterceptor(IClientInterceptor)} or {@link IBasicClient#registerInterceptor(IClientInterceptor)} instead
|
||||
*/
|
||||
public class HttpBasicAuthInterceptor implements HttpRequestInterceptor {
|
||||
public class HttpBasicAuthInterceptor implements HttpRequestInterceptor {
|
||||
|
||||
private String myUsername;
|
||||
private String myPassword;
|
||||
|
|
|
@ -20,13 +20,21 @@ package ca.uhn.fhir.rest.client;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
|
||||
public interface IClientInterceptor {
|
||||
|
||||
/**
|
||||
* Fired by the client just before invoking the HTTP client request
|
||||
*/
|
||||
void interceptRequest(HttpRequestBase theRequest);
|
||||
|
||||
void interceptResponse(HttpResponse theRequest);
|
||||
/**
|
||||
* Fired by the client upon receiving an HTTP response, prior to processing that response
|
||||
*/
|
||||
void interceptResponse(HttpResponse theResponse) throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -30,13 +30,25 @@ import ca.uhn.fhir.model.dstu.resource.Conformance;
|
|||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.gclient.ICreate;
|
||||
import ca.uhn.fhir.rest.gclient.IGetPage;
|
||||
import ca.uhn.fhir.rest.gclient.IGetTags;
|
||||
import ca.uhn.fhir.rest.gclient.ITransaction;
|
||||
import ca.uhn.fhir.rest.gclient.IUntypedQuery;
|
||||
|
||||
public interface IGenericClient {
|
||||
/**
|
||||
* Register a new interceptor for this client. An interceptor can be used to add additional
|
||||
* logging, or add security headers, or pre-process responses, etc.
|
||||
*/
|
||||
void registerInterceptor(IClientInterceptor theInterceptor);
|
||||
|
||||
/**
|
||||
* Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
|
||||
*/
|
||||
void unregisterInterceptor(IClientInterceptor theInterceptor);
|
||||
|
||||
/**
|
||||
* Retrieves and returns the server conformance statement
|
||||
*/
|
||||
|
@ -243,4 +255,9 @@ public interface IGenericClient {
|
|||
*/
|
||||
ITransaction transaction();
|
||||
|
||||
/**
|
||||
* Fluent method for the "create" operation, which creates a new resource instance on the server
|
||||
*/
|
||||
ICreate create();
|
||||
|
||||
}
|
||||
|
|
|
@ -21,9 +21,11 @@ package ca.uhn.fhir.rest.client.api;
|
|||
*/
|
||||
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.client.HttpClient;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
||||
public interface IRestfulClient {
|
||||
|
@ -64,6 +66,15 @@ public interface IRestfulClient {
|
|||
*/
|
||||
String getServerBase();
|
||||
|
||||
|
||||
/**
|
||||
* Register a new interceptor for this client. An interceptor can be used to add additional
|
||||
* logging, or add security headers, or pre-process responses, etc.
|
||||
*/
|
||||
void registerInterceptor(IClientInterceptor theInterceptor);
|
||||
|
||||
/**
|
||||
* Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
|
||||
*/
|
||||
void unregisterInterceptor(IClientInterceptor theInterceptor);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Library
|
||||
* %%
|
||||
* Copyright (C) 2014 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
/**
|
||||
* HTTP interceptor to be used for adding HTTP basic auth username/password tokens
|
||||
* to requests
|
||||
* <p>
|
||||
* 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 BasicAuthInterceptor implements IClientInterceptor {
|
||||
|
||||
private String myUsername;
|
||||
private String myPassword;
|
||||
|
||||
public BasicAuthInterceptor(String theUsername, String thePassword) {
|
||||
super();
|
||||
myUsername = theUsername;
|
||||
myPassword = thePassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptRequest(HttpRequestBase theRequest) {
|
||||
String authorizationUnescaped = StringUtils.defaultString(myUsername) + ":" + StringUtils.defaultString(myPassword);
|
||||
String encoded;
|
||||
try {
|
||||
encoded = Base64.encodeBase64String(authorizationUnescaped.getBytes("ISO-8859-1"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new InternalErrorException("Could not find US-ASCII encoding. This shouldn't happen!");
|
||||
}
|
||||
theRequest.addHeader(Constants.HEADER_AUTHORIZATION, ("Basic " + encoded));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(HttpResponse theResponse) throws IOException {
|
||||
// nothing
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
|
||||
/**
|
||||
* Client interceptor which simply captures request and response objects and stored them so that they can be inspected after a client
|
||||
* call has returned
|
||||
*/
|
||||
public class CapturingInterceptor implements IClientInterceptor {
|
||||
|
||||
private HttpRequestBase myLastRequest;
|
||||
private HttpResponse myLastResponse;
|
||||
|
||||
/**
|
||||
* Clear the last request and response values
|
||||
*/
|
||||
public void clear() {
|
||||
myLastRequest = null;
|
||||
myLastResponse = null;
|
||||
}
|
||||
|
||||
public HttpRequestBase getLastRequest() {
|
||||
return myLastRequest;
|
||||
}
|
||||
|
||||
public HttpResponse getLastResponse() {
|
||||
return myLastResponse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptRequest(HttpRequestBase theRequest) {
|
||||
myLastRequest = theRequest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(HttpResponse theRequest) {
|
||||
myLastResponse = theRequest;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.HttpEntityWrapper;
|
||||
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
public class LoggingInterceptor implements IClientInterceptor {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoggingInterceptor.class);
|
||||
private boolean myLogRequestSummary = true;
|
||||
private boolean myLogResponseSummary = true;
|
||||
private boolean myLogResponseBody = false;
|
||||
private boolean myLogRequestBody = false;
|
||||
private boolean myLogResponseHeaders=false;
|
||||
private boolean myLogRequestHeaders=false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public LoggingInterceptor() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theVerbose If set to true, all logging is enabled
|
||||
*/
|
||||
public LoggingInterceptor(boolean theVerbose) {
|
||||
if (theVerbose) {
|
||||
setLogRequestBody(true);
|
||||
setLogRequestSummary(true);
|
||||
setLogResponseBody(true);
|
||||
setLogResponseSummary(true);
|
||||
setLogRequestHeaders(true);
|
||||
setLogResponseHeaders(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptRequest(HttpRequestBase theRequest) {
|
||||
if (myLogRequestSummary) {
|
||||
ourLog.info("Client request: {}", theRequest);
|
||||
}
|
||||
|
||||
if (myLogRequestHeaders) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (int i = 0;i < theRequest.getAllHeaders().length;i++) {
|
||||
Header next = theRequest.getAllHeaders()[i];
|
||||
b.append(next.getName() + ": " + next.getValue());
|
||||
if(i+1 < theRequest.getAllHeaders().length) {
|
||||
b.append('\n');
|
||||
}
|
||||
}
|
||||
ourLog.info("Client request headers:\n{}", b.toString());
|
||||
}
|
||||
|
||||
if (myLogRequestBody) {
|
||||
if (theRequest instanceof HttpEntityEnclosingRequest) {
|
||||
HttpEntity entity = ((HttpEntityEnclosingRequest) theRequest).getEntity();
|
||||
if (entity.isRepeatable()) {
|
||||
try {
|
||||
String content = IOUtils.toString(entity.getContent());
|
||||
ourLog.info("Client request body:\n{}", content);
|
||||
} catch (IllegalStateException e) {
|
||||
ourLog.warn("Failed to replay request contents (during logging attempt, actual FHIR call did not fail)", e);
|
||||
} catch (IOException e) {
|
||||
ourLog.warn("Failed to replay request contents (during logging attempt, actual FHIR call did not fail)", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(HttpResponse theResponse) throws IOException {
|
||||
if (myLogResponseSummary) {
|
||||
String message = "HTTP " + theResponse.getStatusLine().getStatusCode() + " " + theResponse.getStatusLine().getReasonPhrase();
|
||||
ourLog.info("Client response: {}", message);
|
||||
}
|
||||
|
||||
if (myLogRequestHeaders) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
for (int i = 0;i < theResponse.getAllHeaders().length;i++) {
|
||||
Header next = theResponse.getAllHeaders()[i];
|
||||
b.append(next.getName() + ": " + next.getValue());
|
||||
if(i+1 < theResponse.getAllHeaders().length) {
|
||||
b.append('\n');
|
||||
}
|
||||
}
|
||||
ourLog.info("Client response headers:\n{}", b.toString());
|
||||
}
|
||||
|
||||
if (myLogResponseBody) {
|
||||
HttpEntity respEntity = theResponse.getEntity();
|
||||
final byte[] bytes;
|
||||
try {
|
||||
bytes = IOUtils.toByteArray(respEntity.getContent());
|
||||
} catch (IllegalStateException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
ourLog.info("Client response body:\n{}", new String(bytes));
|
||||
|
||||
theResponse.setEntity(new MyEntityWrapper(respEntity, bytes));
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyEntityWrapper extends HttpEntityWrapper {
|
||||
|
||||
private byte[] myBytes;
|
||||
|
||||
public MyEntityWrapper(HttpEntity theWrappedEntity, byte[] theBytes) {
|
||||
super(theWrappedEntity);
|
||||
myBytes = theBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getContent() throws IOException {
|
||||
return new ByteArrayInputStream(myBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTo(OutputStream theOutstream) throws IOException {
|
||||
theOutstream.write(myBytes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Should a summary (one line) for each request be logged, containing the URL and other information
|
||||
*/
|
||||
public void setLogRequestSummary(boolean theValue) {
|
||||
myLogRequestSummary = theValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should a summary (one line) for each request be logged, containing the URL and other information
|
||||
*/
|
||||
public void setLogResponseSummary(boolean theValue) {
|
||||
myLogResponseSummary = theValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should headers for each request be logged, containing the URL and other information
|
||||
*/
|
||||
public void setLogRequestHeaders(boolean theValue) {
|
||||
myLogRequestHeaders = theValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should headers for each request be logged, containing the URL and other information
|
||||
*/
|
||||
public void setLogResponseHeaders(boolean theValue) {
|
||||
myLogResponseHeaders = theValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should a summary (one line) for each request be logged, containing the URL and other information
|
||||
*/
|
||||
public void setLogRequestBody(boolean theValue) {
|
||||
myLogRequestBody = theValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should a summary (one line) for each request be logged, containing the URL and other information
|
||||
*/
|
||||
public void setLogResponseBody(boolean theValue) {
|
||||
myLogResponseBody = theValue;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package ca.uhn.fhir.rest.gclient;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Library
|
||||
* %%
|
||||
* Copyright (C) 2014 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
||||
public interface ICreate {
|
||||
|
||||
ICreateTyped resource(IResource theResource);
|
||||
|
||||
ICreateTyped resource(String theResourceAsText);
|
||||
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package ca.uhn.fhir.rest.gclient;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Library
|
||||
* %%
|
||||
* Copyright (C) 2014 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
|
||||
public interface ICreateTyped extends IClientExecutable<ICreateTyped, MethodOutcome> {
|
||||
|
||||
/**
|
||||
* If you want the explicitly state an ID for your created resource, put that ID here. You generally do not
|
||||
* need to invoke this method, so that the server will assign the ID itself.
|
||||
*/
|
||||
ICreateTyped withId(String theId);
|
||||
|
||||
/**
|
||||
* If you want the explicitly state an ID for your created resource, put that ID here. You generally do not
|
||||
* need to invoke this method, so that the server will assign the ID itself.
|
||||
*/
|
||||
ICreateTyped withId(IdDt theId);
|
||||
|
||||
}
|
|
@ -50,7 +50,8 @@ public abstract class BaseHttpClientInvocationWithContents extends BaseHttpClien
|
|||
private final TagList myTagList;
|
||||
private final List<IResource> myResources;
|
||||
private final Bundle myBundle;
|
||||
|
||||
private final String myContents;
|
||||
|
||||
public BaseHttpClientInvocationWithContents(FhirContext theContext, IResource theResource, String theUrlExtension) {
|
||||
super();
|
||||
myContext = theContext;
|
||||
|
@ -59,6 +60,7 @@ public abstract class BaseHttpClientInvocationWithContents extends BaseHttpClien
|
|||
myTagList = null;
|
||||
myResources = null;
|
||||
myBundle = null;
|
||||
myContents = null;
|
||||
}
|
||||
|
||||
public BaseHttpClientInvocationWithContents(FhirContext theContext, TagList theTagList, String... theUrlExtension) {
|
||||
|
@ -72,6 +74,7 @@ public abstract class BaseHttpClientInvocationWithContents extends BaseHttpClien
|
|||
myTagList = theTagList;
|
||||
myResources = null;
|
||||
myBundle = null;
|
||||
myContents = null;
|
||||
|
||||
myUrlExtension = StringUtils.join(theUrlExtension, '/');
|
||||
}
|
||||
|
@ -83,6 +86,7 @@ public abstract class BaseHttpClientInvocationWithContents extends BaseHttpClien
|
|||
myUrlExtension = null;
|
||||
myResources = theResources;
|
||||
myBundle = null;
|
||||
myContents = null;
|
||||
}
|
||||
|
||||
public BaseHttpClientInvocationWithContents(FhirContext theContext, Bundle theBundle) {
|
||||
|
@ -92,8 +96,20 @@ public abstract class BaseHttpClientInvocationWithContents extends BaseHttpClien
|
|||
myUrlExtension = null;
|
||||
myResources = null;
|
||||
myBundle = theBundle;
|
||||
myContents = null;
|
||||
}
|
||||
|
||||
public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, String theUrlExtension) {
|
||||
myContext = theContext;
|
||||
myResource = null;
|
||||
myTagList = null;
|
||||
myUrlExtension = theUrlExtension;
|
||||
myResources = null;
|
||||
myBundle = null;
|
||||
myContents = theContents;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) throws DataFormatException {
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
@ -131,6 +147,8 @@ public abstract class BaseHttpClientInvocationWithContents extends BaseHttpClien
|
|||
} else if (myResources != null) {
|
||||
Bundle bundle = RestfulServer.createBundleFromResourceList(myContext, "", myResources, "", "", myResources.size());
|
||||
contents = parser.encodeBundleToString(bundle);
|
||||
} else if (myContents != null) {
|
||||
contents = myContents;
|
||||
} else {
|
||||
contents = parser.encodeResourceToString(myResource);
|
||||
}
|
||||
|
|
|
@ -20,10 +20,13 @@ package ca.uhn.fhir.rest.method;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
@ -55,12 +58,24 @@ public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
|
|||
return Collections.singleton(RequestType.POST);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IResource parseIncomingServerResource(Request theRequest) throws IOException {
|
||||
IResource retVal = super.parseIncomingServerResource(theRequest);
|
||||
|
||||
if (theRequest.getId() != null && theRequest.getId().hasIdPart()) {
|
||||
retVal.setId(theRequest.getId());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected BaseHttpClientInvocation createClientInvocation(Object[] theArgs, IResource theResource) {
|
||||
FhirContext context = getContext();
|
||||
|
||||
BaseHttpClientInvocation retVal = createCreateInvocation(theResource, context);
|
||||
|
||||
|
||||
if (theArgs != null) {
|
||||
for (int idx = 0; idx < theArgs.length; idx++) {
|
||||
IParameter nextParam = getParameters().get(idx);
|
||||
|
@ -72,16 +87,28 @@ public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
|
|||
}
|
||||
|
||||
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, FhirContext theContext) {
|
||||
return createCreateInvocation(theResource, null,null, theContext);
|
||||
}
|
||||
|
||||
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, String theResourceBody, String theId, FhirContext theContext) {
|
||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
|
||||
String resourceName = def.getName();
|
||||
|
||||
|
||||
StringBuilder urlExtension = new StringBuilder();
|
||||
urlExtension.append(resourceName);
|
||||
if (StringUtils.isNotBlank(theId)) {
|
||||
urlExtension.append('/');
|
||||
urlExtension.append(theId);
|
||||
}
|
||||
|
||||
HttpPostClientInvocation retVal = new HttpPostClientInvocation(theContext, theResource, urlExtension.toString());
|
||||
HttpPostClientInvocation retVal;
|
||||
if (StringUtils.isBlank(theResourceBody)) {
|
||||
retVal = new HttpPostClientInvocation(theContext, theResource, urlExtension.toString());
|
||||
}else {
|
||||
retVal = new HttpPostClientInvocation(theContext, theResourceBody, urlExtension.toString());
|
||||
}
|
||||
addTagsToPostOrPut(theResource, retVal);
|
||||
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,10 @@ public class HttpPostClientInvocation extends BaseHttpClientInvocationWithConten
|
|||
super(theContext,theBundle);
|
||||
}
|
||||
|
||||
public HttpPostClientInvocation(FhirContext theContext, String theContents, String theUrlExtension) {
|
||||
super(theContext,theContents, theUrlExtension);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected HttpPost createRequest(String url, AbstractHttpEntity theEntity) {
|
||||
|
|
|
@ -28,6 +28,10 @@ import java.util.Set;
|
|||
|
||||
public class Constants {
|
||||
|
||||
public static final String HEADER_CORS_EXPOSE_HEADERS = "Access-Control-Expose-Headers";
|
||||
public static final String HEADER_CORS_ALLOW_METHODS = "Access-Control-Allow-Methods";
|
||||
public static final String HEADER_CORS_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
|
||||
|
||||
public static final String CHARSET_UTF_8 = "UTF-8";
|
||||
public static final String CT_ATOM_XML = "application/atom+xml";
|
||||
public static final String CT_FHIR_JSON = "application/json+fhir";
|
||||
|
@ -88,6 +92,8 @@ public class Constants {
|
|||
public static final String ENCODING_GZIP = "gzip";
|
||||
public static final String HEADER_LOCATION = "Location";
|
||||
public static final String HEADER_LOCATION_LC = HEADER_LOCATION.toLowerCase();
|
||||
public static final String HEADERVALUE_CORS_ALLOW_METHODS_ALL = "GET, POST, PUT, DELETE";
|
||||
public static final String HEADER_AUTHORIZATION = "Authorization";
|
||||
|
||||
|
||||
static {
|
||||
|
|
|
@ -79,6 +79,7 @@ import ca.uhn.fhir.util.VersionUtil;
|
|||
|
||||
public class RestfulServer extends HttpServlet {
|
||||
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServer.class);
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -99,6 +100,20 @@ public class RestfulServer extends HttpServlet {
|
|||
private String myServerVersion = VersionUtil.getVersion();
|
||||
private boolean myStarted;
|
||||
private boolean myUseBrowserFriendlyContentTypes;
|
||||
private String myCorsAllowDomain;
|
||||
|
||||
public String getCorsAllowDomain() {
|
||||
return myCorsAllowDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to anything other than <code>null</code> (which is the default), the server will return CORS (Cross Origin Resource Sharing) headers with the given domain string.
|
||||
* <p>
|
||||
* A value of "*" indicates that the server allows access to all domains (which may be appropriate in development situations but is generally not appropriate in production)
|
||||
*/
|
||||
public void setCorsAllowDomain(String theCorsAllowDomain) {
|
||||
myCorsAllowDomain = theCorsAllowDomain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -120,6 +135,13 @@ public class RestfulServer extends HttpServlet {
|
|||
*/
|
||||
public void addHeadersToResponse(HttpServletResponse theHttpResponse) {
|
||||
theHttpResponse.addHeader("X-Powered-By", "HAPI FHIR " + VersionUtil.getVersion() + " RESTful Server");
|
||||
|
||||
if (isNotBlank(myCorsAllowDomain)) {
|
||||
theHttpResponse.addHeader(Constants.HEADER_CORS_ALLOW_ORIGIN, myCorsAllowDomain);
|
||||
theHttpResponse.addHeader(Constants.HEADER_CORS_ALLOW_METHODS, Constants.HEADERVALUE_CORS_ALLOW_METHODS_ALL);
|
||||
theHttpResponse.addHeader(Constants.HEADER_CORS_EXPOSE_HEADERS, Constants.HEADER_CONTENT_LOCATION);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void assertProviderIsValid(Object theNext) throws ConfigurationException {
|
||||
|
@ -352,7 +374,7 @@ public class RestfulServer extends HttpServlet {
|
|||
|
||||
int start = Math.min(offsetI, resultList.size() - 1);
|
||||
|
||||
EncodingEnum responseEncoding = determineRequestEncoding(theRequest);
|
||||
EncodingEnum responseEncoding = determineResponseEncoding(theRequest.getServletRequest());
|
||||
boolean prettyPrint = prettyPrintResponse(theRequest);
|
||||
boolean requestIsBrowser = requestIsBrowser(theRequest.getServletRequest());
|
||||
NarrativeModeEnum narrativeMode = determineNarrativeMode(theRequest);
|
||||
|
@ -418,7 +440,7 @@ public class RestfulServer extends HttpServlet {
|
|||
|
||||
ResourceBinding resourceBinding = null;
|
||||
BaseMethodBinding<?> resourceMethod = null;
|
||||
if ("metadata".equals(resourceName)) {
|
||||
if ("metadata".equals(resourceName) || theRequestType == RequestType.OPTIONS) {
|
||||
resourceMethod = myServerConformanceMethod;
|
||||
} else if (resourceName == null) {
|
||||
resourceBinding = myNullResourceBinding;
|
||||
|
|
|
@ -3,10 +3,11 @@ package example;
|
|||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.HttpBasicAuthInterceptor;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.IRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
||||
public class ClientExamples {
|
||||
|
@ -17,29 +18,50 @@ public class ClientExamples {
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
public void createSecurity() {
|
||||
{
|
||||
//START SNIPPET: security
|
||||
// Create a context and get the client factory so it can be configured
|
||||
FhirContext ctx = new FhirContext();
|
||||
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
|
||||
|
||||
// Create an HTTP Client Builder
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
|
||||
// This interceptor adds HTTP username/password to every request
|
||||
//Create an HTTP basic auth interceptor
|
||||
String username = "foobar";
|
||||
String password = "boobear";
|
||||
builder.addInterceptorFirst(new HttpBasicAuthInterceptor(username, password));
|
||||
BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(username, password);
|
||||
|
||||
// Use the new HTTP client builder
|
||||
clientFactory.setHttpClient(builder.build());
|
||||
|
||||
// This factory is applied to both styles of client
|
||||
// Register the interceptor with your client (either style)
|
||||
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
|
||||
annotationClient.registerInterceptor(authInterceptor);
|
||||
|
||||
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
|
||||
annotationClient.registerInterceptor(authInterceptor);
|
||||
//END SNIPPET: security
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void createLogging() {
|
||||
{
|
||||
//START SNIPPET: logging
|
||||
//Create a context and get the client factory so it can be configured
|
||||
FhirContext ctx = new FhirContext();
|
||||
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
|
||||
|
||||
//Create a logging interceptor
|
||||
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
|
||||
|
||||
// Optionally you may configure the interceptor (by default only summary info is logged)
|
||||
loggingInterceptor.setLogRequestSummary(true);
|
||||
loggingInterceptor.setLogRequestBody(true);
|
||||
|
||||
//Register the interceptor with your client (either style)
|
||||
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
|
||||
annotationClient.registerInterceptor(loggingInterceptor);
|
||||
|
||||
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
|
||||
annotationClient.registerInterceptor(loggingInterceptor);
|
||||
//END SNIPPET: logging
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************/
|
||||
{
|
||||
|
|
|
@ -165,6 +165,28 @@
|
|||
|
||||
</subsection>
|
||||
|
||||
<subsection name="Configuring Encoding (JSON/XML)">
|
||||
|
||||
<p>
|
||||
Restful client interfaces that you create will also extend
|
||||
the interface
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/client/api/IRestfulClient.html">IRestfulClient</a>,
|
||||
which comes with some helpful methods for configuring the way that
|
||||
the client will interact with the server.
|
||||
</p>
|
||||
<p>
|
||||
The following snippet shows how to configure the cliet to explicitly
|
||||
request JSON or XML responses, and how to request "pretty printed" responses
|
||||
on servers that support this (HAPI based servers currently).
|
||||
</p>
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="clientConfig" />
|
||||
<param name="file" value="src/site/example/java/example/ClientExamples.java" />
|
||||
</macro>
|
||||
|
||||
</subsection>
|
||||
|
||||
<subsection name="A Complete Example">
|
||||
|
||||
<p>
|
||||
|
@ -205,6 +227,21 @@
|
|||
on the RestfulClientFactory.
|
||||
</p>
|
||||
|
||||
<subsection name="Interceptors">
|
||||
|
||||
<p>
|
||||
Both generic clients and annotation-driven clients support
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/client/IClientInterceptor.html">Client Interceptors</a>,
|
||||
which may be registered in order to provide specific behaviour to each
|
||||
client request.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The following section shows some sample interceptors which may be used.
|
||||
</p>
|
||||
|
||||
</subsection>
|
||||
|
||||
<subsection name="HTTP Basic Authorization">
|
||||
|
||||
<p>
|
||||
|
@ -219,23 +256,15 @@
|
|||
|
||||
</subsection>
|
||||
|
||||
<subsection name="Configuring Encoding (JSON/XML)">
|
||||
<subsection name="Logging Requests and Responses">
|
||||
|
||||
<p>
|
||||
Restful client interfaces that you create will also extend
|
||||
the interface
|
||||
<a href="./apidocs/ca/uhn/fhir/rest/client/api/IRestfulClient.html">IRestfulClient</a>,
|
||||
which comes with some helpful methods for configuring the way that
|
||||
the client will interact with the server.
|
||||
The following example shows how to configure your client to
|
||||
use a specific username and password in every request.
|
||||
</p>
|
||||
<p>
|
||||
The following snippet shows how to configure the cliet to explicitly
|
||||
request JSON or XML responses, and how to request "pretty printed" responses
|
||||
on servers that support this (HAPI based servers currently).
|
||||
</p>
|
||||
|
||||
|
||||
<macro name="snippet">
|
||||
<param name="id" value="clientConfig" />
|
||||
<param name="id" value="logging" />
|
||||
<param name="file" value="src/site/example/java/example/ClientExamples.java" />
|
||||
</macro>
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.apache.http.client.methods.HttpPost;
|
|||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicHttpResponse;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hamcrest.core.StringEndsWith;
|
||||
|
@ -57,6 +58,8 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
|
|||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.param.CodingListParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.QualifiedDateParam;
|
||||
|
@ -73,8 +76,6 @@ public class ClientTest {
|
|||
private HttpClient httpClient;
|
||||
private HttpResponse httpResponse;
|
||||
|
||||
// atom-document-large.xml
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ctx = new FhirContext(Patient.class, Conformance.class);
|
||||
|
@ -85,6 +86,36 @@ public class ClientTest {
|
|||
httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
}
|
||||
|
||||
// atom-document-large.xml
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
//@formatter:off
|
||||
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
|
||||
"<title/>\n" +
|
||||
"<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" +
|
||||
"<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" +
|
||||
"<published>2014-03-11T16:35:07-04:00</published>\n" +
|
||||
"<author>\n" +
|
||||
"<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" +
|
||||
"</author>\n" +
|
||||
"<entry>\n" +
|
||||
"<content type=\"text/xml\">"
|
||||
+ "<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||
+ "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>"
|
||||
+ "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>"
|
||||
+ "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>"
|
||||
+ "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>"
|
||||
+ "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>"
|
||||
+ "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
|
||||
+ "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
|
||||
+ "</Patient>"
|
||||
+ "</content>\n"
|
||||
+ " </entry>\n"
|
||||
+ "</feed>";
|
||||
//@formatter:on
|
||||
return msg;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate() throws Exception {
|
||||
|
||||
|
@ -99,8 +130,13 @@ public class ClientTest {
|
|||
when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200"));
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
client.registerInterceptor(interceptor);
|
||||
|
||||
MethodOutcome response = client.createPatient(patient);
|
||||
|
||||
assertEquals(interceptor.getLastRequest().getURI().toASCIIString(), "http://foo/Patient");
|
||||
|
||||
assertEquals(HttpPost.class, capt.getValue().getClass());
|
||||
HttpPost post = (HttpPost) capt.getValue();
|
||||
assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString("<Patient"));
|
||||
|
@ -129,8 +165,7 @@ public class ClientTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Some servers (older ones?) return the resourcde you created instead of an
|
||||
* OperationOutcome. We just need to ignore it.
|
||||
* Some servers (older ones?) return the resourcde you created instead of an OperationOutcome. We just need to ignore it.
|
||||
*/
|
||||
@Test
|
||||
public void testCreateWithResourceResponse() throws Exception {
|
||||
|
@ -562,6 +597,29 @@ 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 testReadFailureNoCharset() throws Exception {
|
||||
|
||||
|
@ -588,30 +646,6 @@ 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 {
|
||||
|
||||
|
@ -676,6 +710,28 @@ public class ClientTest {
|
|||
|
||||
String msg = getPatientFeedWithOneResult();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
|
||||
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
|
||||
// httpResponse = new BasicHttpResponse(statusline, catalog, locale)
|
||||
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
List<Patient> response = client.getPatientByDob(new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
|
||||
|
||||
assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString());
|
||||
assertEquals("PRP1660", response.get(0).getIdentifier().get(0).getValue().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByQuantity() throws Exception {
|
||||
|
||||
String msg = getPatientFeedWithOneResult();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
|
@ -683,10 +739,10 @@ public class ClientTest {
|
|||
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
List<Patient> response = client.getPatientByDob(new QualifiedDateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02"));
|
||||
Patient response = client.findPatientQuantity(new QuantityDt(QuantityCompararatorEnum.GREATERTHAN, 123L, "foo", "bar"));
|
||||
|
||||
assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString());
|
||||
assertEquals("PRP1660", response.get(0).getIdentifier().get(0).getValue().getValue());
|
||||
assertEquals("http://foo/Patient?quantityParam=%3E123%7Cfoo%7Cbar", capt.getValue().getURI().toString());
|
||||
assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue());
|
||||
|
||||
}
|
||||
|
||||
|
@ -709,25 +765,6 @@ public class ClientTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByQuantity() throws Exception {
|
||||
|
||||
String msg = getPatientFeedWithOneResult();
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(httpClient.execute(capt.capture())).thenReturn(httpResponse);
|
||||
when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
|
||||
Patient response = client.findPatientQuantity(new QuantityDt(QuantityCompararatorEnum.GREATERTHAN,123L,"foo","bar"));
|
||||
|
||||
assertEquals("http://foo/Patient?quantityParam=%3E123%7Cfoo%7Cbar", capt.getValue().getURI().toString());
|
||||
assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchComposite() throws Exception {
|
||||
|
||||
|
@ -946,8 +983,7 @@ public class ClientTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Return a FHIR content type, but no content and make sure we handle this
|
||||
* without crashing
|
||||
* Return a FHIR content type, but no content and make sure we handle this without crashing
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateWithEmptyResponse() throws Exception {
|
||||
|
@ -1063,38 +1099,14 @@ public class ClientTest {
|
|||
|
||||
}
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
//@formatter:off
|
||||
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
|
||||
"<title/>\n" +
|
||||
"<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" +
|
||||
"<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" +
|
||||
"<published>2014-03-11T16:35:07-04:00</published>\n" +
|
||||
"<author>\n" +
|
||||
"<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" +
|
||||
"</author>\n" +
|
||||
"<entry>\n" +
|
||||
"<content type=\"text/xml\">"
|
||||
+ "<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||
+ "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>"
|
||||
+ "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>"
|
||||
+ "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>"
|
||||
+ "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>"
|
||||
+ "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>"
|
||||
+ "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
|
||||
+ "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
|
||||
+ "</Patient>"
|
||||
+ "</content>\n"
|
||||
+ " </entry>\n"
|
||||
+ "</feed>";
|
||||
//@formatter:on
|
||||
return msg;
|
||||
}
|
||||
|
||||
private Header[] toHeaderArray(String theName, String theValue) {
|
||||
return new Header[] { new BasicHeader(theName, theValue) };
|
||||
}
|
||||
|
||||
private interface ClientWithoutAnnotation extends IBasicClient {
|
||||
Patient read(@IdParam IdDt theId);
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient")
|
||||
public static class CustomPatient extends Patient {
|
||||
// nothing
|
||||
|
@ -1114,8 +1126,4 @@ public class ClientTest {
|
|||
@Search()
|
||||
public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString, @IncludeParam String theInclude);
|
||||
}
|
||||
|
||||
private interface ClientWithoutAnnotation extends IBasicClient {
|
||||
Patient read(@IdParam IdDt theId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.apache.http.Header;
|
|||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
|
@ -59,7 +60,7 @@ public class GenericClientTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithTag() throws Exception {
|
||||
public void testCreateWithTagNonFluent() throws Exception {
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier("foo:bar", "12345");
|
||||
|
@ -88,6 +89,52 @@ public class GenericClientTest {
|
|||
assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateWithTag() throws Exception {
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier("foo:bar", "12345");
|
||||
p1.addName().addFamily("Smith").addGiven("John");
|
||||
TagList list = new TagList();
|
||||
list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource");
|
||||
ResourceMetadataKeyEnum.TAG_LIST.put(p1, list);
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") });
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
|
||||
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
MethodOutcome outcome = client.create().resource(p1).execute();
|
||||
assertEquals("44", outcome.getId().getIdPart());
|
||||
assertEquals("22", outcome.getId().getVersionIdPart());
|
||||
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getValue().getURI().toString());
|
||||
assertEquals("POST", capt.getValue().getMethod());
|
||||
Header catH = capt.getValue().getFirstHeader("Category");
|
||||
assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH);
|
||||
assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue());
|
||||
|
||||
/*
|
||||
* Try fluent options
|
||||
*/
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
client.create().resource(p1).withId("123").execute();
|
||||
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toString());
|
||||
|
||||
String resourceText = "<Patient xmlns=\"http://hl7.org/fhir\"> </Patient>";
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
client.create().resource(resourceText).withId("123").execute();
|
||||
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(2).getURI().toString());
|
||||
assertEquals(resourceText, IOUtils.toString(((HttpPost)capt.getAllValues().get(2)).getEntity().getContent()));
|
||||
|
||||
}
|
||||
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
//@formatter:off
|
||||
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class InterceptorTest {
|
||||
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
@Test
|
||||
public void testLogger() throws Exception {
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort);
|
||||
client.registerInterceptor(new LoggingInterceptor(true));
|
||||
Patient patient = client.read(Patient.class, "1");
|
||||
assertFalse(patient.getIdentifierFirstRep().isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyProvider patientProvider = new DummyProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
ourCtx = servlet.getFhirContext();
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyProvider implements IResourceProvider {
|
||||
|
||||
@Read(version = true)
|
||||
public Patient findPatient(@IdParam IdDt theId) {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier(theId.getIdPart(), theId.getVersionIdPart());
|
||||
patient.setId("Patient/1/_history/1");
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.Tag;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.dstu.resource.AdverseReaction;
|
||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticOrder;
|
||||
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
|
||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.annotation.VersionIdParam;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class CreateTest {
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateTest.class);
|
||||
private static int ourPort;
|
||||
private static DiagnosticReportProvider ourReportProvider;
|
||||
private static Server ourServer;
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreate() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateById() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/1234");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/1234/_history/002", status.getFirstHeader("location").getValue());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateJson() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithUnprocessableEntity() throws Exception {
|
||||
|
||||
DiagnosticReport report = new DiagnosticReport();
|
||||
report.getIdentifier().setValue("001");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/DiagnosticReport");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(report), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(422, status.getStatusLine().getStatusCode());
|
||||
|
||||
OperationOutcome outcome = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, new StringReader(responseContent));
|
||||
assertEquals("FOOBAR", outcome.getIssueFirstRep().getDetails().getValue());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
PatientProvider patientProvider = new PatientProvider();
|
||||
|
||||
ourReportProvider = new DiagnosticReportProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
servlet.setResourceProviders(patientProvider, ourReportProvider, new DummyAdverseReactionResourceProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DiagnosticReportProvider implements IResourceProvider {
|
||||
private TagList myLastTags;
|
||||
private IdDt myLastVersion;
|
||||
|
||||
public TagList getLastTags() {
|
||||
return myLastTags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return DiagnosticReport.class;
|
||||
}
|
||||
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) {
|
||||
OperationOutcome outcome = new OperationOutcome();
|
||||
outcome.addIssue().setDetails("FOOBAR");
|
||||
throw new UnprocessableEntityException(outcome);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyAdverseReactionResourceProvider implements IResourceProvider {
|
||||
|
||||
/*
|
||||
* *********************
|
||||
* NO NEW METHODS *********************
|
||||
*/
|
||||
|
||||
@Create()
|
||||
public MethodOutcome create(@ResourceParam AdverseReaction thePatient) {
|
||||
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||
IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue());
|
||||
return new MethodOutcome(id, version);
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Collection<AdverseReaction> getAllResources() {
|
||||
ArrayList<AdverseReaction> retVal = new ArrayList<AdverseReaction>();
|
||||
|
||||
AdverseReaction ar1 = new AdverseReaction();
|
||||
ar1.setId("1");
|
||||
retVal.add(ar1);
|
||||
|
||||
AdverseReaction ar2 = new AdverseReaction();
|
||||
ar2.setId("2");
|
||||
retVal.add(ar2);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return AdverseReaction.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class PatientProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
||||
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||
if (thePatient.getId().isEmpty()==false) {
|
||||
id=thePatient.getId();
|
||||
}
|
||||
return new MethodOutcome(id.withVersion("002"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -52,35 +52,38 @@ public class PagingTest {
|
|||
String link;
|
||||
String base = "http://localhost:" + ourPort;
|
||||
{
|
||||
HttpGet httpGet = new HttpGet(base+ "/Patient?_format=xml&_pretty=true");
|
||||
HttpGet httpGet = new HttpGet(base + "/Patient?_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(5, bundle.getEntries().size());
|
||||
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart());
|
||||
assertEquals("4", bundle.getEntries().get(4).getId().getIdPart());
|
||||
assertEquals(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkNext()
|
||||
.getValue());
|
||||
assertNull(bundle.getLinkPrevious().getValue());
|
||||
link=bundle.getLinkNext().getValue();
|
||||
link = bundle.getLinkNext().getValue();
|
||||
}
|
||||
{
|
||||
HttpGet httpGet = new HttpGet(link);
|
||||
HttpGet httpGet = new HttpGet(link.replace("=xml", "=json"));
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
|
||||
Bundle bundle = ourContext.newJsonParser().parseBundle(responseContent);
|
||||
assertEquals(5, bundle.getEntries().size());
|
||||
assertEquals("5", bundle.getEntries().get(0).getId().getIdPart());
|
||||
assertEquals("9", bundle.getEntries().get(4).getId().getIdPart());
|
||||
assertNull(bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true", bundle.getLinkPrevious()
|
||||
.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchInexactOffset() throws Exception {
|
||||
when(myPagingProvider.getDefaultPageSize()).thenReturn(5);
|
||||
|
@ -90,9 +93,10 @@ public class PagingTest {
|
|||
|
||||
String base = "http://localhost:" + ourPort;
|
||||
{
|
||||
HttpGet httpGet = new HttpGet(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=8&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true");
|
||||
HttpGet httpGet = new HttpGet(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=8&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
|
||||
|
@ -100,7 +104,8 @@ public class PagingTest {
|
|||
assertEquals("8", bundle.getEntries().get(0).getId().getIdPart());
|
||||
assertEquals("9", bundle.getEntries().get(1).getId().getIdPart());
|
||||
assertNull(bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=3&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=3&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious()
|
||||
.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -115,37 +120,38 @@ public class PagingTest {
|
|||
String link;
|
||||
String base = "http://localhost:" + ourPort;
|
||||
{
|
||||
HttpGet httpGet = new HttpGet(base+ "/Patient?_count=2");
|
||||
HttpGet httpGet = new HttpGet(base + "/Patient?_count=2");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(2, bundle.getEntries().size());
|
||||
assertEquals("0", bundle.getEntries().get(0).getId().getIdPart());
|
||||
assertEquals("1", bundle.getEntries().get(1).getId().getIdPart());
|
||||
assertEquals(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
|
||||
assertNull(bundle.getLinkPrevious().getValue());
|
||||
link=bundle.getLinkNext().getValue();
|
||||
link = bundle.getLinkNext().getValue();
|
||||
}
|
||||
{
|
||||
HttpGet httpGet = new HttpGet(link);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(2, bundle.getEntries().size());
|
||||
assertEquals("2", bundle.getEntries().get(0).getId().getIdPart());
|
||||
assertEquals("3", bundle.getEntries().get(1).getId().getIdPart());
|
||||
assertEquals(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '/'+'?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkSelf().getValue());
|
||||
assertEquals(base + '?'+Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkPrevious().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue());
|
||||
assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkSelf().getValue());
|
||||
assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkPrevious().getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
|
|
|
@ -109,71 +109,6 @@ public class ResfulServerMethodTest {
|
|||
assertThat(responseContent, StringContains.containsString("AAAABBBB"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreate() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateJson() throws Exception {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setValue("001");
|
||||
patient.addIdentifier().setValue("002");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(201, status.getStatusLine().getStatusCode());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithUnprocessableEntity() throws Exception {
|
||||
|
||||
DiagnosticReport report = new DiagnosticReport();
|
||||
report.getIdentifier().setValue("001");
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/DiagnosticReport");
|
||||
httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(report), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
ourLog.info("Response was:\n{}", responseContent);
|
||||
|
||||
assertEquals(422, status.getStatusLine().getStatusCode());
|
||||
|
||||
OperationOutcome outcome = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, new StringReader(responseContent));
|
||||
assertEquals("FOOBAR", outcome.getIssueFirstRep().getDetails().getValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateRangeParam() throws Exception {
|
||||
|
@ -1102,18 +1037,6 @@ public class ResfulServerMethodTest {
|
|||
*/
|
||||
public static class DummyAdverseReactionResourceProvider implements IResourceProvider {
|
||||
|
||||
/*
|
||||
* *********************
|
||||
* NO NEW METHODS *********************
|
||||
*/
|
||||
|
||||
@Create()
|
||||
public MethodOutcome create(@ResourceParam AdverseReaction thePatient) {
|
||||
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||
IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue());
|
||||
return new MethodOutcome(id, version);
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Collection<AdverseReaction> getAllResources() {
|
||||
ArrayList<AdverseReaction> retVal = new ArrayList<AdverseReaction>();
|
||||
|
@ -1148,12 +1071,6 @@ public class ResfulServerMethodTest {
|
|||
throw new ResourceNotFoundException("AAAABBBB");
|
||||
}
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) {
|
||||
OperationOutcome outcome = new OperationOutcome();
|
||||
outcome.addIssue().setDetails("FOOBAR");
|
||||
throw new UnprocessableEntityException(outcome);
|
||||
}
|
||||
|
||||
@Delete()
|
||||
public void deleteDiagnosticReport(@IdParam IdDt theId) {
|
||||
|
@ -1176,12 +1093,6 @@ public class ResfulServerMethodTest {
|
|||
*/
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Create()
|
||||
public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
|
||||
IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue());
|
||||
IdDt version = new IdDt(thePatient.getIdentifier().get(1).getValue().getValue());
|
||||
return new MethodOutcome(id, version);
|
||||
}
|
||||
|
||||
@Delete()
|
||||
public MethodOutcome deletePatient(@IdParam IdDt theId) {
|
||||
|
|
|
@ -10,9 +10,11 @@ import java.util.Map;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpOptions;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
|
@ -114,6 +116,39 @@ public class ServerFeaturesTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCors() throws Exception {
|
||||
servlet.setCorsAllowDomain("http://foo.com");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_FHIR_XML);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
Header origin = status.getFirstHeader(Constants.HEADER_CORS_ALLOW_ORIGIN);
|
||||
assertEquals("http://foo.com", origin.getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOptions() throws Exception {
|
||||
servlet.setCorsAllowDomain("http://foo.com");
|
||||
|
||||
HttpOptions httpGet = new HttpOptions("http://localhost:" + ourPort + "/");
|
||||
httpGet.addHeader("Accept", Constants.CT_FHIR_XML);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
|
||||
Header origin = status.getFirstHeader(Constants.HEADER_CORS_ALLOW_ORIGIN);
|
||||
assertEquals("http://foo.com", origin.getValue());
|
||||
|
||||
assertThat(responseContent,StringContains.containsString("<Conformance"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAcceptHeaderWithMultiple() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
|
@ -235,8 +270,10 @@ public class ServerFeaturesTest {
|
|||
@Before
|
||||
public void before() {
|
||||
servlet.setServerAddressStrategy(new IncomingRequestAddressStrategy());
|
||||
servlet.setCorsAllowDomain(null);
|
||||
}
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
|
|
|
@ -1053,6 +1053,11 @@ public abstract class BaseFhirDao implements IDao {
|
|||
|
||||
if (entity.getId() == null) {
|
||||
myEntityManager.persist(entity);
|
||||
|
||||
if (entity.getForcedId() != null) {
|
||||
myEntityManager.persist(entity.getForcedId());
|
||||
}
|
||||
|
||||
} else {
|
||||
entity = myEntityManager.merge(entity);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.persistence.criteria.CriteriaQuery;
|
|||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -42,6 +43,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||
import ca.uhn.fhir.jpa.entity.BaseTag;
|
||||
import ca.uhn.fhir.jpa.entity.ForcedId;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||
|
@ -403,7 +405,8 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
}
|
||||
|
||||
if (rawSearchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm);
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has length (" + rawSearchTerm.length() + ") that is longer than maximum allowed ("
|
||||
+ ResourceIndexedSearchParamString.MAX_LENGTH + "): " + rawSearchTerm);
|
||||
}
|
||||
|
||||
String likeExpression = normalizeString(rawSearchTerm);
|
||||
|
@ -461,10 +464,12 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
}
|
||||
|
||||
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system);
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has system (" + system.length() + ") that is longer than maximum allowed ("
|
||||
+ ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + system);
|
||||
}
|
||||
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH + "): " + code);
|
||||
throw new InvalidRequestException("Parameter[" + theParamName + "] has code (" + code.length() + ") that is longer than maximum allowed (" + ResourceIndexedSearchParamToken.MAX_LENGTH
|
||||
+ "): " + code);
|
||||
}
|
||||
|
||||
ArrayList<Predicate> singleCodePredicates = (new ArrayList<Predicate>());
|
||||
|
@ -533,9 +538,20 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
|
||||
if (theResource.getId().isEmpty() == false) {
|
||||
if (isValidPid(theResource.getId())) {
|
||||
throw new UnprocessableEntityException("This server cannot create an entity with a numeric ID - Numeric IDs are server assigned");
|
||||
throw new UnprocessableEntityException(
|
||||
"This server cannot create an entity with a user-specified numeric ID - Client should not specify an ID when creating a new resource, or should include at least one letter in the ID to force a client-defined ID");
|
||||
}
|
||||
createForcedIdIfNeeded(entity, theResource.getId());
|
||||
|
||||
if (entity.getForcedId() != null) {
|
||||
try {
|
||||
translateForcedIdToPid(theResource.getId());
|
||||
throw new UnprocessableEntityException("Can not create entity with ID[" + theResource.getId().getValue() + "], constraint violation occurred");
|
||||
} catch (ResourceNotFoundException e) {
|
||||
// good, this ID doesn't exist so we can create it
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
updateEntity(theResource, entity, false, false);
|
||||
|
@ -608,7 +624,8 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
|
||||
final T current = currentTmp;
|
||||
|
||||
String querySring = "SELECT count(h) FROM ResourceHistoryTable h " + "WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE" + " AND h.myUpdated < :END" + (theSince != null ? " AND h.myUpdated >= :SINCE" : "");
|
||||
String querySring = "SELECT count(h) FROM ResourceHistoryTable h " + "WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE" + " AND h.myUpdated < :END"
|
||||
+ (theSince != null ? " AND h.myUpdated >= :SINCE" : "");
|
||||
TypedQuery<Long> countQuery = myEntityManager.createQuery(querySring, Long.class);
|
||||
countQuery.setParameter("PID", theId.getIdPartAsLong());
|
||||
countQuery.setParameter("RESTYPE", resourceType);
|
||||
|
@ -646,8 +663,9 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
retVal.add(current);
|
||||
}
|
||||
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT h FROM ResourceHistoryTable h WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE AND h.myUpdated < :END " + (theSince != null ? " AND h.myUpdated >= :SINCE" : "")
|
||||
+ " ORDER BY h.myUpdated ASC", ResourceHistoryTable.class);
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery(
|
||||
"SELECT h FROM ResourceHistoryTable h WHERE h.myResourceId = :PID AND h.myResourceType = :RESTYPE AND h.myUpdated < :END "
|
||||
+ (theSince != null ? " AND h.myUpdated >= :SINCE" : "") + " ORDER BY h.myUpdated ASC", ResourceHistoryTable.class);
|
||||
q.setParameter("PID", theId.getIdPartAsLong());
|
||||
q.setParameter("RESTYPE", resourceType);
|
||||
q.setParameter("END", end.getValue(), TemporalType.TIMESTAMP);
|
||||
|
@ -716,7 +734,8 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
throw new ConfigurationException("Unknown search param on resource[" + myResourceName + "] for secondary key[" + mySecondaryPrimaryKeyParamName + "]");
|
||||
}
|
||||
if (sp.getParamType() != SearchParamTypeEnum.TOKEN) {
|
||||
throw new ConfigurationException("Search param on resource[" + myResourceName + "] for secondary key[" + mySecondaryPrimaryKeyParamName + "] is not a token type, only token is supported");
|
||||
throw new ConfigurationException("Search param on resource[" + myResourceName + "] for secondary key[" + mySecondaryPrimaryKeyParamName
|
||||
+ "] is not a token type, only token is supported");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -743,7 +762,8 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
|
||||
private void validateResourceType(BaseHasResource entity) {
|
||||
if (!myResourceName.equals(entity.getResourceType())) {
|
||||
throw new ResourceNotFoundException("Resource with ID " + entity.getIdDt().getIdPart() + " exists but it is not of type " + myResourceName + ", found resource of type " + entity.getResourceType());
|
||||
throw new ResourceNotFoundException("Resource with ID " + entity.getIdDt().getIdPart() + " exists but it is not of type " + myResourceName + ", found resource of type "
|
||||
+ entity.getResourceType());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,7 +787,8 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
|
||||
if (entity == null) {
|
||||
if (theId.hasVersionIdPart()) {
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery(
|
||||
"SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||
q.setParameter("RID", theId.getIdPartAsLong());
|
||||
q.setParameter("RTYP", myResourceName);
|
||||
q.setParameter("RVER", theId.getVersionIdPartAsLong());
|
||||
|
@ -1048,8 +1069,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
|
|||
}
|
||||
|
||||
/**
|
||||
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to
|
||||
* share the same value.
|
||||
* If set, the given param will be treated as a secondary primary key, and multiple resources will not be able to share the same value.
|
||||
*/
|
||||
public void setSecondaryPrimaryKeyParamName(String theSecondaryPrimaryKeyParamName) {
|
||||
mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName;
|
||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.entity;
|
|||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
|
@ -14,6 +15,8 @@ import javax.persistence.OneToOne;
|
|||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.validator.cfg.context.Cascadable;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProvider;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||
|
@ -36,6 +38,7 @@ import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
|||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
import ca.uhn.test.jpasrv.ObservationResourceProvider;
|
||||
import ca.uhn.test.jpasrv.OrganizationResourceProvider;
|
||||
|
@ -51,7 +54,8 @@ public class CompleteResourceProviderTest {
|
|||
private static IFhirResourceDao<Questionnaire> questionnaireDao;
|
||||
private static IGenericClient ourClient;
|
||||
private static IFhirResourceDao<Observation> observationDao;
|
||||
// private static JpaConformanceProvider ourConfProvider;
|
||||
|
||||
// private static JpaConformanceProvider ourConfProvider;
|
||||
|
||||
// @Test
|
||||
// public void test01UploadTestResources() throws Exception {
|
||||
|
@ -92,20 +96,46 @@ public class CompleteResourceProviderTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateWithId() {
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier().setSystem("urn:system").setValue("testCreateWithId01");
|
||||
IdDt p1Id = ourClient.create().resource(p1).withId("testCreateWithId").execute().getId();
|
||||
|
||||
assertThat(p1Id.getValue(), containsString("Patient/testCreateWithId/_history"));
|
||||
|
||||
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testCreateWithId01")).encodedJson().prettyPrint().execute();
|
||||
assertEquals(1, actual.size());
|
||||
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart());
|
||||
|
||||
/*
|
||||
* ensure that trying to create the same ID again fails appropriately
|
||||
*/
|
||||
try {
|
||||
ourClient.create().resource(p1).withId("testCreateWithId").execute().getId();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
Bundle history = ourClient.history(null, (String)null, null, null);
|
||||
assertEquals(p1Id.getIdPart(), history.getEntries().get(0).getId().getIdPart());
|
||||
assertNotNull(history.getEntries().get(0).getResource());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByIdentifierWithoutSystem() {
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier().setValue("testSearchByIdentifierWithoutSystem01");
|
||||
IdDt p1Id = ourClient.create(p1).getId();
|
||||
|
||||
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint().execute();
|
||||
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode(null, "testSearchByIdentifierWithoutSystem01")).encodedJson().prettyPrint()
|
||||
.execute();
|
||||
assertEquals(1, actual.size());
|
||||
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchByResourceChain() {
|
||||
Organization o1 = new Organization();
|
||||
|
@ -137,48 +167,48 @@ public class CompleteResourceProviderTest {
|
|||
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getId().getIdPart());
|
||||
|
||||
}
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompleteResourceProviderTest.class);
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompleteResourceProviderTest.class);
|
||||
|
||||
@Test
|
||||
public void testInsertUpdatesConformance() {
|
||||
// Conformance conf = ourConfProvider.getServerConformance();
|
||||
// ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conf));
|
||||
//
|
||||
// RestResource res=null;
|
||||
// for (Rest nextRest : conf.getRest()) {
|
||||
// for (RestResource nextRes : nextRest.getResource()) {
|
||||
// if (nextRes.getType().getValueAsEnum()==ResourceTypeEnum.PATIENT) {
|
||||
// res = nextRes;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// List<ExtensionDt> resCounts = res.getUndeclaredExtensionsByUrl(ExtensionConstants.CONF_RESOURCE_COUNT);
|
||||
//
|
||||
// int initial = 0;
|
||||
|
||||
// Conformance conf = ourConfProvider.getServerConformance();
|
||||
// ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conf));
|
||||
//
|
||||
// RestResource res=null;
|
||||
// for (Rest nextRest : conf.getRest()) {
|
||||
// for (RestResource nextRes : nextRest.getResource()) {
|
||||
// if (nextRes.getType().getValueAsEnum()==ResourceTypeEnum.PATIENT) {
|
||||
// res = nextRes;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// List<ExtensionDt> resCounts = res.getUndeclaredExtensionsByUrl(ExtensionConstants.CONF_RESOURCE_COUNT);
|
||||
//
|
||||
// int initial = 0;
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addIdentifier().setSystem("urn:system").setValue("testSearchByResourceChain01");
|
||||
p1.addName().addFamily("testSearchByResourceChainFamily01").addGiven("testSearchByResourceChainGiven01");
|
||||
|
||||
ourClient.create(p1).getId();
|
||||
|
||||
// conf = ourConfProvider.getServerConformance();
|
||||
// res=null;
|
||||
// for (Rest nextRest : conf.getRest()) {
|
||||
// for (RestResource nextRes : nextRest.getResource()) {
|
||||
// if (nextRes.getType().getValueAsEnum()==ResourceTypeEnum.PATIENT) {
|
||||
// res = nextRes;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// resCounts = res.getUndeclaredExtensionsByUrl(ExtensionConstants.CONF_RESOURCE_COUNT);
|
||||
// assertNotNull(resCounts);
|
||||
// assertEquals(1, resCounts.size());
|
||||
// DecimalDt number = (DecimalDt) resCounts.get(0).getValue();
|
||||
// assertEquals(initial+1, number.getValueAsInteger());
|
||||
// conf = ourConfProvider.getServerConformance();
|
||||
// res=null;
|
||||
// for (Rest nextRest : conf.getRest()) {
|
||||
// for (RestResource nextRes : nextRest.getResource()) {
|
||||
// if (nextRes.getType().getValueAsEnum()==ResourceTypeEnum.PATIENT) {
|
||||
// res = nextRes;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// resCounts = res.getUndeclaredExtensionsByUrl(ExtensionConstants.CONF_RESOURCE_COUNT);
|
||||
// assertNotNull(resCounts);
|
||||
// assertEquals(1, resCounts.size());
|
||||
// DecimalDt number = (DecimalDt) resCounts.get(0).getValue();
|
||||
// assertEquals(initial+1, number.getValueAsInteger());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testInsertBadReference() {
|
||||
Patient p1 = new Patient();
|
||||
|
@ -195,7 +225,6 @@ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSaveAndRetrieveExistingNarrative() {
|
||||
Patient p1 = new Patient();
|
||||
|
@ -218,7 +247,7 @@ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger
|
|||
Patient actual = ourClient.read(Patient.class, newId);
|
||||
assertThat(actual.getText().getDiv().getValueAsString(), containsString("<td>Identifier</td><td>testSearchByResourceChain01</td>"));
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
|
@ -251,9 +280,11 @@ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger
|
|||
restServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
IFhirSystemDao systemDao = (IFhirSystemDao) ourAppCtx.getBean("mySystemDao", IFhirSystemDao.class);
|
||||
|
||||
// ourConfProvider = new JpaConformanceProvider(restServer, systemDao, Collections.singletonList((IFhirResourceDao)patientDao));
|
||||
JpaSystemProvider systemProv = new JpaSystemProvider(systemDao);
|
||||
restServer.setPlainProviders(systemProv);
|
||||
|
||||
// ourConfProvider = new JpaConformanceProvider(restServer, systemDao, Collections.singletonList((IFhirResourceDao)patientDao));
|
||||
|
||||
int myPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(myPort);
|
||||
|
||||
|
|
|
@ -6,7 +6,13 @@
|
|||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-tester-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
<dependent-module archiveName="hapi-fhir-jpaserver-base-0.5-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-jpaserver-base/hapi-fhir-jpaserver-base">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module archiveName="hapi-fhir-base-0.5-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-testpage-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
<dependency-type>consumes</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/slf/?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
|
|
|
@ -77,7 +77,12 @@
|
|||
<artifactId>jcl-over-slf4j</artifactId>
|
||||
<version>${slf4j_version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>${slf4j_version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.web.context.ContextLoaderListener;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProvider;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
|
||||
|
@ -69,6 +68,7 @@ public class TestRestfulServer extends RestfulServer {
|
|||
setServerConformanceProvider(confProvider);
|
||||
|
||||
setUseBrowserFriendlyContentTypes(true);
|
||||
setCorsAllowDomain("*");
|
||||
|
||||
String baseUrl = System.getProperty("fhir.baseurl");
|
||||
if (StringUtils.isBlank(baseUrl)) {
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package ca.uhn.fhirtest;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.resource.Profile;
|
||||
import ca.uhn.fhir.model.dstu.resource.Profile.ExtensionDefn;
|
||||
import ca.uhn.fhir.model.dstu.valueset.DataTypeEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ExtensionContextEnum;
|
||||
|
||||
public class PopulateProfiles {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Profile hapiExtensions = new Profile();
|
||||
|
||||
ExtensionDefn ext = hapiExtensions.addExtensionDefn();
|
||||
ext.addContext("Conformance.rest.resource");
|
||||
ext.getCode().setValue("resourceCount");
|
||||
ext.getContextType().setValueAsEnum(ExtensionContextEnum.RESOURCE);
|
||||
ext.getDisplay().setValue("Resource count on server");
|
||||
ext.getDefinition().addType().setCode(DataTypeEnum.DECIMAL);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -53,6 +53,7 @@ import ca.uhn.fhir.model.primitive.StringDt;
|
|||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.client.GenericClient;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.gclient.ICreateTyped;
|
||||
import ca.uhn.fhir.rest.gclient.IQuery;
|
||||
import ca.uhn.fhir.rest.gclient.IUntypedQuery;
|
||||
import ca.uhn.fhir.rest.gclient.StringParam;
|
||||
|
@ -91,10 +92,6 @@ public class Controller {
|
|||
return "about";
|
||||
}
|
||||
|
||||
private String logPrefix(ModelMap theModel) {
|
||||
return "[server=" + theModel.get("serverId") + "] - ";
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/conformance" })
|
||||
public String actionConformance(final HomeRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
@ -160,18 +157,6 @@ public class Controller {
|
|||
return "result";
|
||||
}
|
||||
|
||||
private ResultType handleClientException(GenericClient theClient, Exception e, ModelMap theModel) {
|
||||
ResultType returnsResource;
|
||||
returnsResource = ResultType.NONE;
|
||||
ourLog.warn("Failed to invoke server", e);
|
||||
|
||||
if (theClient.getLastResponse() == null) {
|
||||
theModel.put("errorMsg", "Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
return returnsResource;
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/get-tags" })
|
||||
public String actionGetTags(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
@ -527,6 +512,12 @@ public class Controller {
|
|||
return "result";
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/update" })
|
||||
public String actionUpdate(final HttpServletRequest theReq, final HomeRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
doActionCreateOrValidate(theReq, theRequest, theBindingResult, theModel, "update");
|
||||
return "result";
|
||||
}
|
||||
|
||||
@RequestMapping(value = { "/validate" })
|
||||
public String actionValidate(final HttpServletRequest theReq, final HomeRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
doActionCreateOrValidate(theReq, theRequest, theBindingResult, theModel, "validate");
|
||||
|
@ -614,13 +605,17 @@ public class Controller {
|
|||
client.validate(resource);
|
||||
} else {
|
||||
String id = theReq.getParameter("resource-create-id");
|
||||
if (isNotBlank(id)) {
|
||||
if ("update".equals(theMethod)) {
|
||||
outcomeDescription = "Update Resource";
|
||||
client.update(id, resource);
|
||||
update = true;
|
||||
} else {
|
||||
outcomeDescription = "Create Resource";
|
||||
client.create(resource);
|
||||
ICreateTyped create = client.create().resource(body);
|
||||
if (isNotBlank(id)) {
|
||||
create.withId(id);
|
||||
}
|
||||
create.execute();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
@ -802,19 +797,19 @@ public class Controller {
|
|||
}
|
||||
|
||||
try {
|
||||
str=URLDecoder.decode(str, "UTF-8");
|
||||
str = URLDecoder.decode(str, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
ourLog.error("Should not happen",e);
|
||||
ourLog.error("Should not happen", e);
|
||||
}
|
||||
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<span class='hlUrlBase'>");
|
||||
|
||||
boolean inParams = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char nextChar = str.charAt(i);
|
||||
// char nextChar2 = i < str.length()-2 ? str.charAt(i+1):' ';
|
||||
// char nextChar3 = i < str.length()-2 ? str.charAt(i+2):' ';
|
||||
// char nextChar2 = i < str.length()-2 ? str.charAt(i+1):' ';
|
||||
// char nextChar3 = i < str.length()-2 ? str.charAt(i+2):' ';
|
||||
if (!inParams) {
|
||||
if (nextChar == '?') {
|
||||
inParams = true;
|
||||
|
@ -830,8 +825,8 @@ public class Controller {
|
|||
b.append("</span><wbr /><span class='hlControl'>&</span><span class='hlTagName'>");
|
||||
} else if (nextChar == '=') {
|
||||
b.append("</span><span class='hlControl'>=</span><span class='hlAttr'>");
|
||||
// }else if (nextChar=='%' && Character.isLetterOrDigit(nextChar2)&& Character.isLetterOrDigit(nextChar3)) {
|
||||
// URLDecoder.decode(s, enc)
|
||||
// }else if (nextChar=='%' && Character.isLetterOrDigit(nextChar2)&& Character.isLetterOrDigit(nextChar3)) {
|
||||
// URLDecoder.decode(s, enc)
|
||||
} else {
|
||||
b.append(nextChar);
|
||||
}
|
||||
|
@ -853,6 +848,18 @@ public class Controller {
|
|||
return def;
|
||||
}
|
||||
|
||||
private ResultType handleClientException(GenericClient theClient, Exception e, ModelMap theModel) {
|
||||
ResultType returnsResource;
|
||||
returnsResource = ResultType.NONE;
|
||||
ourLog.warn("Failed to invoke server", e);
|
||||
|
||||
if (theClient.getLastResponse() == null) {
|
||||
theModel.put("errorMsg", "Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
return returnsResource;
|
||||
}
|
||||
|
||||
private boolean handleSearchParam(String paramIdxString, HttpServletRequest theReq, IQuery theQuery, JsonGenerator theClientCodeJsonWriter) {
|
||||
String nextName = theReq.getParameter("param." + paramIdxString + ".name");
|
||||
if (isBlank(nextName)) {
|
||||
|
@ -970,6 +977,10 @@ public class Controller {
|
|||
return conformance;
|
||||
}
|
||||
|
||||
private String logPrefix(ModelMap theModel) {
|
||||
return "[server=" + theModel.get("serverId") + "] - ";
|
||||
}
|
||||
|
||||
private String parseNarrative(EncodingEnum theCtEnum, String theResultBody) {
|
||||
try {
|
||||
IResource resource = theCtEnum.newParser(myCtx).parseResource(theResultBody);
|
||||
|
|
|
@ -337,12 +337,11 @@
|
|||
</div>
|
||||
<br clear="all"/>
|
||||
|
||||
<!-- Create/Update -->
|
||||
<!-- Create -->
|
||||
|
||||
<div class="row-fluid">
|
||||
<b>Create/Update</b> an instance of the resource. If no ID is specified,
|
||||
a new resource will be created. If an ID is specified, the existing
|
||||
resource with that ID will be updated.
|
||||
<b>Create</b> an instance of the resource. Generally you do not need to specify an ID
|
||||
but you may force the server to use a specific ID by including one.
|
||||
</div>
|
||||
<div class="row-fluid top-buffer">
|
||||
<div class="col-sm-2">
|
||||
|
@ -358,7 +357,7 @@
|
|||
<div class="input-group-addon">
|
||||
ID
|
||||
</div>
|
||||
<input type="text" class="form-control" id="resource-create-id" placeholder="(add for update)" th:value="${updateResourceId}"/>
|
||||
<input type="text" class="form-control" id="resource-create-id" placeholder="(optional)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -370,37 +369,16 @@
|
|||
<span class="loadingStar">*</span>
|
||||
</div>
|
||||
<textarea class="form-control" id="resource-create-body" style="white-space: nowrap; overflow: auto;" placeholder="(place resource body here)" rows="1">
|
||||
<th:block th:if="${updateResource} != null" th:text="${updateResource}"/>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var buttonChanger = function() {
|
||||
var val = $('#resource-create-id').val();
|
||||
if (val != "") {
|
||||
//$('#resource-create-btn').text("Update");
|
||||
$("#resource-create-btn").fadeOut(function() {
|
||||
$(this).html('<i class="fa fa-pencil"></i> Update').fadeIn();
|
||||
});
|
||||
} else {
|
||||
$("#resource-create-btn").fadeOut(function() {
|
||||
$(this).html('<i class="fa fa-send"></i> Create').fadeIn();
|
||||
});
|
||||
//$('#resource-create-btn').text("Create");
|
||||
}
|
||||
};
|
||||
var textAreaChanger = function() {
|
||||
createBodyOriginalHeight = $('#resource-create-body').height();
|
||||
$('#resource-create-body').animate({height: "200px"}, 500);
|
||||
}
|
||||
$('#resource-create-id').change(buttonChanger);
|
||||
$('#resource-create-id').keyup(buttonChanger);
|
||||
$('#resource-create-body').focus(textAreaChanger);
|
||||
/*$('#resource-create-body').blur(
|
||||
function() {
|
||||
$('#resource-create-body').animate({height: "34px"}, 500);
|
||||
});*/
|
||||
$('#resource-create-btn').click(
|
||||
function() {
|
||||
var btn = $(this);
|
||||
|
@ -422,6 +400,72 @@
|
|||
</div>
|
||||
<br clear="all"/>
|
||||
|
||||
<!-- Update -->
|
||||
|
||||
<div class="row-fluid">
|
||||
<b>Update</b> an existing instance of the resource by ID.
|
||||
</div>
|
||||
<div class="row-fluid top-buffer">
|
||||
<div class="col-sm-2">
|
||||
<button type="button" id="resource-update-btn"
|
||||
data-loading-text="Loading <i class='fa fa-spinner fa-spin'/>" class="btn btn-primary btn-block">
|
||||
<i class="fa fa-send"></i>
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
<div class='col-sm-3'>
|
||||
<div class="form-group">
|
||||
<div class='input-group date'>
|
||||
<div class="input-group-addon">
|
||||
ID
|
||||
<span class="loadingStar">*</span>
|
||||
</div>
|
||||
<input type="text" class="form-control" id="resource-update-id" placeholder="(resource ID)" th:value="${updateResourceId}"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='col-sm-7'>
|
||||
<div class="form-group">
|
||||
<div class='input-group date'>
|
||||
<div class="input-group-addon">
|
||||
Contents
|
||||
<span class="loadingStar">*</span>
|
||||
</div>
|
||||
<textarea class="form-control" id="resource-update-body" style="white-space: nowrap; overflow: auto;" placeholder="(place resource body here)" rows="1">
|
||||
<th:block th:if="${updateResource} != null" th:text="${updateResource}"/>
|
||||
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var textAreaChanger = function() {
|
||||
updateBodyOriginalHeight = $('#resource-update-body').height();
|
||||
$('#resource-update-body').animate({height: "200px"}, 500);
|
||||
}
|
||||
$('#resource-update-body').focus(textAreaChanger);
|
||||
$('#resource-update-btn').click(
|
||||
function() {
|
||||
var btn = $(this);
|
||||
btn.button('loading');
|
||||
var id = $('#resource-update-id').val();
|
||||
// Note we're using resource-create-id even though this is an update because
|
||||
// the controller expects that...
|
||||
if (id != null) btn.append($('<input />', { type: 'hidden', name: 'resource-create-id', value: id }));
|
||||
var body = $('#resource-update-body').val();
|
||||
btn.append($('<input />', { type: 'hidden', name: 'resource-create-body', value: body }));
|
||||
$("#outerForm").attr("action", "update").submit();
|
||||
});
|
||||
$( document ).ready(function() {
|
||||
if ($('#resource-update-id').val() != "") {
|
||||
buttonChanger();
|
||||
textAreaChanger();
|
||||
$('#resource-update-body').focus();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<br clear="all"/>
|
||||
|
||||
<!-- Validate -->
|
||||
|
||||
<div class="row-fluid">
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -81,7 +81,7 @@
|
|||
<maven_site_plugin_version>3.3</maven_site_plugin_version>
|
||||
<mockito_version>1.9.5</mockito_version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<slf4j_version>1.7.2</slf4j_version>
|
||||
<slf4j_version>1.7.7</slf4j_version>
|
||||
<spring_version>4.0.1.RELEASE</spring_version>
|
||||
<thymeleaf-version>2.1.3.RELEASE</thymeleaf-version>
|
||||
</properties>
|
||||
|
|
Loading…
Reference in New Issue