More work to get transactions working
This commit is contained in:
parent
de3fbc9023
commit
245533773f
|
@ -36,6 +36,7 @@ public class BundleEntry extends BaseBundle {
|
|||
//@formatter:on
|
||||
private TagList myCategories;
|
||||
private InstantDt myDeletedAt;
|
||||
private StringDt myLinkAlternate;
|
||||
private StringDt myLinkSelf;
|
||||
private InstantDt myPublished;
|
||||
private IResource myResource;
|
||||
|
@ -70,6 +71,13 @@ public class BundleEntry extends BaseBundle {
|
|||
return myDeletedAt;
|
||||
}
|
||||
|
||||
public StringDt getLinkAlternate() {
|
||||
if (myLinkAlternate == null) {
|
||||
myLinkAlternate = new StringDt();
|
||||
}
|
||||
return myLinkAlternate;
|
||||
}
|
||||
|
||||
public StringDt getLinkSelf() {
|
||||
if (myLinkSelf == null) {
|
||||
myLinkSelf = new StringDt();
|
||||
|
@ -113,7 +121,7 @@ public class BundleEntry extends BaseBundle {
|
|||
public boolean isEmpty() {
|
||||
//@formatter:off
|
||||
return super.isEmpty() &&
|
||||
ElementUtil.isEmpty(myCategories, myDeletedAt, myLinkSelf, myPublished, myResource, mySummary, myTitle, myUpdated);
|
||||
ElementUtil.isEmpty(myCategories, myDeletedAt, myLinkAlternate, myLinkSelf, myPublished, myResource, mySummary, myTitle, myUpdated);
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
|
@ -124,6 +132,10 @@ public class BundleEntry extends BaseBundle {
|
|||
myDeletedAt = theDeletedAt;
|
||||
}
|
||||
|
||||
public void setLinkAlternate(StringDt theLinkAlternate) {
|
||||
myLinkAlternate = theLinkAlternate;
|
||||
}
|
||||
|
||||
public void setLinkSelf(StringDt theLinkSelf) {
|
||||
if (myLinkSelf == null) {
|
||||
myLinkSelf = new StringDt();
|
||||
|
|
|
@ -25,6 +25,27 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
|
||||
public enum ResourceMetadataKeyEnum {
|
||||
|
||||
/**
|
||||
* If present and populated with a date/time (as an instance of {@link InstantDt}),
|
||||
* this value is an indication that the resource is in the deleted state. This key
|
||||
* is only used in a limited number of scenarios, such as POSTing transaction bundles
|
||||
* to a server, or returning resource history.
|
||||
* <p>
|
||||
* Values for this key are of type <b>{@link InstantDt}</b>
|
||||
* </p>
|
||||
*/
|
||||
DELETED_AT,
|
||||
|
||||
/**
|
||||
* The value for this key represents a previous ID used to identify
|
||||
* this resource. This key is currently only used internally during
|
||||
* transaction method processing.
|
||||
* <p>
|
||||
* Values for this key are of type <b>{@link IdDt}</b>
|
||||
* </p>
|
||||
*/
|
||||
PREVIOUS_ID,
|
||||
|
||||
/**
|
||||
* The value for this key is the bundle entry <b>Published</b> time. This is
|
||||
* defined by FHIR as "Time resource copied into the feed", which is
|
||||
|
@ -50,8 +71,9 @@ public enum ResourceMetadataKeyEnum {
|
|||
*
|
||||
* @see TagList
|
||||
*/
|
||||
TAG_LIST,
|
||||
|
||||
TAG_LIST,
|
||||
|
||||
|
||||
/**
|
||||
* The value for this key is the bundle entry <b>Updated</b> time. This is
|
||||
* defined by FHIR as "Last Updated for resource". This value is also used
|
||||
|
@ -63,8 +85,8 @@ public enum ResourceMetadataKeyEnum {
|
|||
*
|
||||
* @see InstantDt
|
||||
*/
|
||||
UPDATED,
|
||||
|
||||
UPDATED,
|
||||
|
||||
/**
|
||||
* The value for this key is the version ID of the resource object.
|
||||
* <p>
|
||||
|
@ -74,18 +96,6 @@ public enum ResourceMetadataKeyEnum {
|
|||
* @deprecated The {@link IResource#getId()} resource ID will now be populated with the version ID via the {@link IdDt#getUnqualifiedVersionId()} method
|
||||
*/
|
||||
@Deprecated
|
||||
VERSION_ID,
|
||||
|
||||
|
||||
/**
|
||||
* If present and populated with a date/time (as an instance of {@link InstantDt}),
|
||||
* this value is an indication that the resource is in the deleted state. This key
|
||||
* is only used in a limited number of scenarios, such as POSTing transaction bundles
|
||||
* to a server, or returning resource history.
|
||||
* <p>
|
||||
* Values for this key are of type <b>{@link InstantDt}</b>
|
||||
* </p>
|
||||
*/
|
||||
DELETED_AT;
|
||||
VERSION_ID;
|
||||
|
||||
}
|
||||
|
|
|
@ -25,11 +25,13 @@ import static org.apache.commons.lang3.StringUtils.*;
|
|||
import java.math.BigDecimal;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.model.api.BasePrimitive;
|
||||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
/**
|
||||
* Represents the FHIR ID type. This is the actual resource ID, meaning the ID that will be used in RESTful URLs,
|
||||
|
@ -94,6 +96,27 @@ public class IdDt extends BasePrimitive<String> {
|
|||
setValue(theValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theResourceType The resource type (e.g. "Patient")
|
||||
* @param theId The ID (e.g. "123")
|
||||
* @param theVersionId The version ID ("e.g. "456")
|
||||
*/
|
||||
public IdDt(String theResourceType, String theId, String theVersionId) {
|
||||
Validate.notBlank(theResourceType, "Resource type must not be blank");
|
||||
Validate.notBlank(theId, "ID must not be blank");
|
||||
|
||||
myResourceType = theResourceType;
|
||||
myUnqualifiedId = theId;
|
||||
myUnqualifiedVersionId = StringUtils.defaultIfBlank(theVersionId, null);
|
||||
if (myUnqualifiedVersionId != null) {
|
||||
myValue = myResourceType + '/' + myUnqualifiedId + '/' + Constants.PARAM_HISTORY + '/' + myUnqualifiedVersionId;
|
||||
} else {
|
||||
myValue = myResourceType + '/' + myUnqualifiedId;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unqualified portion of this ID as a big decimal, or <code>null</code> if the value is null
|
||||
*
|
||||
|
@ -144,8 +167,8 @@ public class IdDt extends BasePrimitive<String> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this ID. Note that this value may be a fully qualified URL, a relative/partial URL, or
|
||||
* a simple ID. Use {@link #getUnqualifiedId()} to get just the ID portion.
|
||||
* Returns the value of this ID. Note that this value may be a fully qualified URL, a relative/partial URL, or a
|
||||
* simple ID. Use {@link #getUnqualifiedId()} to get just the ID portion.
|
||||
*
|
||||
* @see #getUnqualifiedId()
|
||||
*/
|
||||
|
@ -200,15 +223,15 @@ public class IdDt extends BasePrimitive<String> {
|
|||
myUnqualifiedId = theValue.substring(idIndex + 1);
|
||||
myUnqualifiedVersionId = null;
|
||||
}
|
||||
|
||||
|
||||
if (idIndex <= 0) {
|
||||
myResourceType = null;
|
||||
}else {
|
||||
} else {
|
||||
int typeIndex = theValue.lastIndexOf('/', idIndex - 1);
|
||||
if (typeIndex == -1) {
|
||||
myResourceType = theValue.substring(0,idIndex);
|
||||
myResourceType = theValue.substring(0, idIndex);
|
||||
} else {
|
||||
myResourceType = theValue.substring(typeIndex+1, idIndex);
|
||||
myResourceType = theValue.substring(typeIndex + 1, idIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,8 +260,8 @@ public class IdDt extends BasePrimitive<String> {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if the unqualified ID is a valid {@link Long} value (in other
|
||||
* words, it consists only of digits)
|
||||
* Returns <code>true</code> if the unqualified ID is a valid {@link Long} value (in other words, it consists only
|
||||
* of digits)
|
||||
*/
|
||||
public boolean isValidLong() {
|
||||
String id = getUnqualifiedId();
|
||||
|
@ -253,4 +276,33 @@ public class IdDt extends BasePrimitive<String> {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a view of this ID as a fully qualified URL, given a server base and resource name
|
||||
* (which will only be used if the ID does not already contain those respective parts). Essentially,
|
||||
* because IdDt can contain either a complete URL or a partial one (or even jut a simple ID), this
|
||||
* method may be used to translate into a complete URL.
|
||||
*
|
||||
* @param theServerBase The server base (e.g. "http://example.com/fhir")
|
||||
* @param theResourceType The resource name (e.g. "Patient")
|
||||
* @return A fully qualified URL for this ID (e.g. "http://example.com/fhir/Patient/1")
|
||||
*/
|
||||
public String toQualifiedUrl(String theServerBase, String theResourceType) {
|
||||
if (getValue().startsWith("http")) {
|
||||
return getValue();
|
||||
}
|
||||
StringBuilder retVal = new StringBuilder();
|
||||
retVal.append(theServerBase);
|
||||
if (retVal.charAt(retVal.length()-1) != '/') {
|
||||
retVal.append('/');
|
||||
}
|
||||
if (isNotBlank(getResourceType())) {
|
||||
retVal.append(getResourceType());
|
||||
}else {
|
||||
retVal.append(theResourceType);
|
||||
}
|
||||
retVal.append('/');
|
||||
retVal.append(getUnqualifiedId());
|
||||
return retVal.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -168,7 +168,8 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
linkStarted = writeAtomLink(eventWriter, "last", theBundle.getLinkLast(), linkStarted);
|
||||
linkStarted = writeAtomLink(eventWriter, "fhir-base", theBundle.getLinkBase(), linkStarted);
|
||||
if (linkStarted) {
|
||||
eventWriter.writeEnd();}
|
||||
eventWriter.writeEnd();
|
||||
}
|
||||
|
||||
writeOptionalTagWithTextNode(eventWriter, "totalResults", theBundle.getTotalResults());
|
||||
|
||||
|
@ -181,11 +182,13 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
writeTagWithTextNode(eventWriter, "deleted", nextEntry.getDeletedAt());
|
||||
writeTagWithTextNode(eventWriter, "title", nextEntry.getTitle());
|
||||
writeTagWithTextNode(eventWriter, "id", nextEntry.getId());
|
||||
|
||||
|
||||
linkStarted = false;
|
||||
linkStarted=writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf(), linkStarted);
|
||||
linkStarted = writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf(), linkStarted);
|
||||
linkStarted = writeAtomLink(eventWriter, "alternate", nextEntry.getLinkAlternate(), linkStarted);
|
||||
if (linkStarted) {
|
||||
eventWriter.writeEnd();}
|
||||
eventWriter.writeEnd();
|
||||
}
|
||||
|
||||
writeOptionalTagWithTextNode(eventWriter, "updated", nextEntry.getUpdated());
|
||||
writeOptionalTagWithTextNode(eventWriter, "published", nextEntry.getPublished());
|
||||
|
@ -839,11 +842,11 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
private boolean writeAtomLink(JsonGenerator theEventWriter, String theRel, StringDt theLink, boolean theStarted) {
|
||||
boolean retVal = theStarted;
|
||||
if (isNotBlank(theLink.getValue())) {
|
||||
if (theStarted==false) {
|
||||
if (theStarted == false) {
|
||||
theEventWriter.writeStartArray("link");
|
||||
retVal=true;
|
||||
retVal = true;
|
||||
}
|
||||
|
||||
|
||||
theEventWriter.writeStartObject();
|
||||
theEventWriter.write("rel", theRel);
|
||||
theEventWriter.write("href", theLink.getValue());
|
||||
|
@ -898,10 +901,10 @@ public class JsonParser extends BaseParser implements IParser {
|
|||
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
|
||||
if (StringUtils.isNotBlank(theStringDt.getValue())) {
|
||||
theEventWriter.write(theElementName, theStringDt.getValue());
|
||||
}
|
||||
// else {
|
||||
// theEventWriter.writeNull(theElementName);
|
||||
// }
|
||||
}
|
||||
// else {
|
||||
// theEventWriter.writeNull(theElementName);
|
||||
// }
|
||||
}
|
||||
|
||||
private class HeldExtension {
|
||||
|
|
|
@ -345,6 +345,11 @@ class ParserState<T> {
|
|||
return;
|
||||
}
|
||||
|
||||
IdDt id = myEntry.getId();
|
||||
if(id!=null && id.isEmpty()==false) {
|
||||
myEntry.getResource().setId(id);
|
||||
}
|
||||
|
||||
Map<ResourceMetadataKeyEnum, Object> metadata = myEntry.getResource().getResourceMetadata();
|
||||
if (myEntry.getPublished().isEmpty() == false) {
|
||||
metadata.put(ResourceMetadataKeyEnum.PUBLISHED, myEntry.getPublished());
|
||||
|
@ -361,10 +366,10 @@ class ParserState<T> {
|
|||
}
|
||||
if (!myEntry.getLinkSelf().isEmpty()) {
|
||||
String linkSelfValue = myEntry.getLinkSelf().getValue();
|
||||
IdDt id = new IdDt(linkSelfValue);
|
||||
myEntry.getResource().setId(id);
|
||||
if (isNotBlank(id.getUnqualifiedVersionId())) {
|
||||
metadata.put(ResourceMetadataKeyEnum.VERSION_ID, id);
|
||||
IdDt linkSelf = new IdDt(linkSelfValue);
|
||||
myEntry.getResource().setId(linkSelf);
|
||||
if (isNotBlank(linkSelf.getUnqualifiedVersionId())) {
|
||||
metadata.put(ResourceMetadataKeyEnum.VERSION_ID, linkSelf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -438,7 +443,11 @@ class ParserState<T> {
|
|||
myInstance.getLinkBase().setValueAsString(myHref);
|
||||
}
|
||||
} else {
|
||||
myEntry.getLinkSelf().setValueAsString(myHref);
|
||||
if ("self".equals(myRel)) {
|
||||
myEntry.getLinkSelf().setValueAsString(myHref);
|
||||
} else if ("alternate".equals(myRel)) {
|
||||
myEntry.getLinkAlternate().setValueAsString(myHref);
|
||||
}
|
||||
}
|
||||
pop();
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper;
|
||||
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
|
||||
|
||||
public class XmlParser extends BaseParser implements IParser {
|
||||
|
@ -149,7 +150,7 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
eventWriter.writeNamespace("at", TOMBSTONES_NS);
|
||||
eventWriter.writeAttribute("ref", nextEntry.getId().getValueAsString());
|
||||
eventWriter.writeAttribute("when", nextEntry.getDeletedAt().getValueAsString());
|
||||
}else {
|
||||
} else {
|
||||
eventWriter.writeStartElement("entry");
|
||||
}
|
||||
|
||||
|
@ -174,6 +175,9 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
writeAtomLink(eventWriter, "self", nextEntry.getLinkSelf());
|
||||
}
|
||||
|
||||
if (!nextEntry.getLinkAlternate().isEmpty()) {
|
||||
writeAtomLink(eventWriter, "alternate", nextEntry.getLinkAlternate());
|
||||
}
|
||||
|
||||
IResource resource = nextEntry.getResource();
|
||||
if (resource != null && !resource.isEmpty()) {
|
||||
|
@ -302,7 +306,8 @@ public class XmlParser extends BaseParser implements IParser {
|
|||
PrettyPrintWriterWrapper retVal = new PrettyPrintWriterWrapper(eventWriter);
|
||||
return retVal;
|
||||
} else {
|
||||
return eventWriter;
|
||||
NonPrettyPrintWriterWrapper retVal = new NonPrettyPrintWriterWrapper(eventWriter);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ public abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding
|
|||
}
|
||||
invokeServerMethod(params);
|
||||
|
||||
EncodingEnum responseEncoding = determineResponseEncoding(theRequest);
|
||||
EncodingEnum responseEncoding = RestfulServer.determineResponseEncoding(theRequest);
|
||||
|
||||
theResponse.setContentType(responseEncoding.getResourceContentType());
|
||||
theResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
||||
|
|
|
@ -20,7 +20,7 @@ package ca.uhn.fhir.rest.method;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
@ -30,9 +30,7 @@ import java.lang.reflect.Modifier;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -81,9 +79,11 @@ import ca.uhn.fhir.util.ReflectionUtil;
|
|||
|
||||
public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseMethodBinding.class);
|
||||
private FhirContext myContext;
|
||||
private Method myMethod;
|
||||
private List<IParameter> myParameters;
|
||||
|
||||
private Object myProvider;
|
||||
|
||||
public BaseMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
|
||||
|
@ -104,13 +104,17 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
return myMethod;
|
||||
}
|
||||
|
||||
public List<IParameter> getParameters() {
|
||||
return myParameters;
|
||||
}
|
||||
|
||||
public Object getProvider() {
|
||||
return myProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the resource this method handles, or
|
||||
* <code>null</code> if this method is not resource specific
|
||||
* Returns the name of the resource this method handles, or <code>null</code> if this method is not resource
|
||||
* specific
|
||||
*/
|
||||
public abstract String getResourceName();
|
||||
|
||||
|
@ -118,26 +122,60 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
|
||||
public abstract RestfulOperationSystemEnum getSystemOperationType();
|
||||
|
||||
public abstract boolean incomingServerRequestMatchesMethod(Request theRequest);
|
||||
|
||||
public abstract BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException;
|
||||
|
||||
public abstract void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException;
|
||||
|
||||
public abstract boolean incomingServerRequestMatchesMethod(Request theRequest);
|
||||
/** For unit tests only */
|
||||
public void setParameters(List<IParameter> theParameters) {
|
||||
myParameters = theParameters;
|
||||
}
|
||||
|
||||
protected IParser createAppropriateParserForParsingResponse(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode) {
|
||||
EncodingEnum encoding = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (encoding==null) {
|
||||
EncodingEnum encoding = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (encoding == null) {
|
||||
NonFhirResponseException ex = NonFhirResponseException.newInstance(theResponseStatusCode, theResponseMimeType, theResponseReader);
|
||||
populateException(ex, theResponseReader);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
IParser parser=encoding.newParser(getContext());
|
||||
|
||||
IParser parser = encoding.newParser(getContext());
|
||||
return parser;
|
||||
}
|
||||
|
||||
public List<IParameter> getParameters() {
|
||||
return myParameters;
|
||||
protected IParser createAppropriateParserForParsingServerRequest(Request theRequest) {
|
||||
String contentTypeHeader = theRequest.getServletRequest().getHeader("content-type");
|
||||
EncodingEnum encoding;
|
||||
if (isBlank(contentTypeHeader)) {
|
||||
encoding = EncodingEnum.XML;
|
||||
} else {
|
||||
int semicolon = contentTypeHeader.indexOf(';');
|
||||
if (semicolon != -1) {
|
||||
contentTypeHeader = contentTypeHeader.substring(0, semicolon);
|
||||
}
|
||||
encoding = EncodingEnum.forContentType(contentTypeHeader);
|
||||
}
|
||||
|
||||
if (encoding == null) {
|
||||
throw new InvalidRequestException("Request contins non-FHIR conent-type header value: " + contentTypeHeader);
|
||||
}
|
||||
|
||||
IParser parser = encoding.newParser(getContext());
|
||||
return parser;
|
||||
}
|
||||
|
||||
protected Object[] createParametersForServerRequest(Request theRequest, IResource theResource) {
|
||||
Object[] params = new Object[getParameters().size()];
|
||||
for (int i = 0; i < getParameters().size(); i++) {
|
||||
IParameter param = getParameters().get(i);
|
||||
if (param == null) {
|
||||
continue;
|
||||
}
|
||||
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, theResource);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
protected Object invokeServerMethod(Object[] theMethodParams) {
|
||||
|
@ -155,9 +193,36 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
}
|
||||
}
|
||||
|
||||
/** For unit tests only */
|
||||
public void setParameters(List<IParameter> theParameters) {
|
||||
myParameters = theParameters;
|
||||
protected BaseServerResponseException processNon2xxResponseAndReturnExceptionToThrow(int theStatusCode, String theResponseMimeType, Reader theResponseReader) {
|
||||
BaseServerResponseException ex;
|
||||
switch (theStatusCode) {
|
||||
case Constants.STATUS_HTTP_400_BAD_REQUEST:
|
||||
ex = new InvalidRequestException("Server responded with HTTP 400");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_404_NOT_FOUND:
|
||||
ex = new ResourceNotFoundException("Server responded with HTTP 404");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_405_METHOD_NOT_ALLOWED:
|
||||
ex = new MethodNotAllowedException("Server responded with HTTP 405");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_409_CONFLICT:
|
||||
ex = new ResourceVersionConflictException("Server responded with HTTP 409");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_412_PRECONDITION_FAILED:
|
||||
ex = new ResourceVersionNotSpecifiedException("Server responded with HTTP 412");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY:
|
||||
IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theStatusCode);
|
||||
OperationOutcome operationOutcome = parser.parseResource(OperationOutcome.class, theResponseReader);
|
||||
ex = new UnprocessableEntityException(operationOutcome);
|
||||
break;
|
||||
default:
|
||||
ex = new UnclassifiedServerFailureException(theStatusCode, "Server responded with HTTP " + theStatusCode);
|
||||
break;
|
||||
}
|
||||
|
||||
populateException(ex, theResponseReader);
|
||||
return ex;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -175,7 +240,7 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
DeleteTags deleteTags = theMethod.getAnnotation(DeleteTags.class);
|
||||
Transaction transaction = theMethod.getAnnotation(Transaction.class);
|
||||
// ** if you add another annotation above, also add it to the next line:
|
||||
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate, getTags, addTags, deleteTags,transaction)) {
|
||||
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate, getTags, addTags, deleteTags, transaction)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -313,50 +378,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
// return sm;
|
||||
}
|
||||
|
||||
public static EncodingEnum determineResponseEncoding(Request theReq) {
|
||||
String[] format = theReq.getParameters().remove(Constants.PARAM_FORMAT);
|
||||
if (format != null) {
|
||||
for (String nextFormat : format) {
|
||||
EncodingEnum retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextFormat);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration<String> acceptValues = theReq.getServletRequest().getHeaders("Accept");
|
||||
if (acceptValues != null) {
|
||||
while (acceptValues.hasMoreElements()) {
|
||||
EncodingEnum retVal = Constants.FORMAT_VAL_TO_ENCODING.get(acceptValues.nextElement());
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
return EncodingEnum.XML;
|
||||
}
|
||||
|
||||
protected IParser createAppropriateParserForParsingServerRequest(Request theRequest) {
|
||||
String contentTypeHeader = theRequest.getServletRequest().getHeader("content-type");
|
||||
EncodingEnum encoding;
|
||||
if (isBlank(contentTypeHeader)) {
|
||||
encoding = EncodingEnum.XML;
|
||||
} else {
|
||||
int semicolon = contentTypeHeader.indexOf(';');
|
||||
if (semicolon!=-1) {
|
||||
contentTypeHeader=contentTypeHeader.substring(0,semicolon);
|
||||
}
|
||||
encoding = EncodingEnum.forContentType(contentTypeHeader);
|
||||
}
|
||||
|
||||
if (encoding==null) {
|
||||
throw new InvalidRequestException("Request contins non-FHIR conent-type header value: " + contentTypeHeader);
|
||||
}
|
||||
|
||||
IParser parser=encoding.newParser(getContext());
|
||||
return parser;
|
||||
}
|
||||
|
||||
public static boolean verifyMethodHasZeroOrOneOperationAnnotation(Method theNextMethod, Object... theAnnotations) {
|
||||
Object obj1 = null;
|
||||
for (Object object : theAnnotations) {
|
||||
|
@ -380,6 +401,15 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
return true;
|
||||
}
|
||||
|
||||
private static void populateException(BaseServerResponseException theEx, Reader theResponseReader) {
|
||||
try {
|
||||
String responseText = IOUtils.toString(theResponseReader);
|
||||
theEx.setResponseBody(responseText);
|
||||
} catch (IOException e) {
|
||||
ourLog.debug("Failed to read response", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String toLogString(Class<?> theType) {
|
||||
if (theType == null) {
|
||||
return null;
|
||||
|
@ -398,18 +428,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
return retVal;
|
||||
}
|
||||
|
||||
protected Object[] createParametersForServerRequest(Request theRequest, IResource theResource) {
|
||||
Object[] params = new Object[getParameters().size()];
|
||||
for (int i = 0; i < getParameters().size(); i++) {
|
||||
IParameter param = getParameters().get(i);
|
||||
if (param == null) {
|
||||
continue;
|
||||
}
|
||||
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, theResource);
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
protected static List<IResource> toResourceList(Object response) throws InternalErrorException {
|
||||
if (response == null) {
|
||||
return Collections.emptyList();
|
||||
|
@ -426,59 +444,4 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
}
|
||||
}
|
||||
|
||||
protected static boolean prettyPrintResponse(Request theRequest) {
|
||||
Map<String, String[]> requestParams = theRequest.getParameters();
|
||||
String[] pretty = requestParams.remove(Constants.PARAM_PRETTY);
|
||||
boolean prettyPrint = false;
|
||||
if (pretty != null && pretty.length > 0) {
|
||||
if (Constants.PARAM_PRETTY_VALUE_TRUE.equals(pretty[0])) {
|
||||
prettyPrint = true;
|
||||
}
|
||||
}
|
||||
return prettyPrint;
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseMethodBinding.class);
|
||||
|
||||
protected BaseServerResponseException processNon2xxResponseAndReturnExceptionToThrow(int theStatusCode, String theResponseMimeType, Reader theResponseReader) {
|
||||
BaseServerResponseException ex;
|
||||
switch (theStatusCode) {
|
||||
case Constants.STATUS_HTTP_400_BAD_REQUEST:
|
||||
ex = new InvalidRequestException("Server responded with HTTP 400");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_404_NOT_FOUND:
|
||||
ex = new ResourceNotFoundException("Server responded with HTTP 404");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_405_METHOD_NOT_ALLOWED:
|
||||
ex = new MethodNotAllowedException("Server responded with HTTP 405");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_409_CONFLICT:
|
||||
ex = new ResourceVersionConflictException("Server responded with HTTP 409");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_412_PRECONDITION_FAILED:
|
||||
ex = new ResourceVersionNotSpecifiedException("Server responded with HTTP 412");
|
||||
break;
|
||||
case Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY:
|
||||
IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theStatusCode);
|
||||
OperationOutcome operationOutcome = parser.parseResource(OperationOutcome.class, theResponseReader);
|
||||
ex = new UnprocessableEntityException(operationOutcome);
|
||||
break;
|
||||
default:
|
||||
ex = new UnclassifiedServerFailureException(theStatusCode, "Server responded with HTTP " + theStatusCode);
|
||||
break;
|
||||
}
|
||||
|
||||
populateException(ex, theResponseReader);
|
||||
return ex;
|
||||
}
|
||||
|
||||
private static void populateException(BaseServerResponseException theEx, Reader theResponseReader) {
|
||||
try {
|
||||
String responseText = IOUtils.toString(theResponseReader);
|
||||
theEx.setResponseBody(responseText);
|
||||
} catch (IOException e) {
|
||||
ourLog.debug("Failed to read response", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -112,7 +112,7 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
|||
|
||||
@Override
|
||||
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
|
||||
EncodingEnum encoding = determineResponseEncoding(theRequest);
|
||||
EncodingEnum encoding = RestfulServer.determineResponseEncoding(theRequest);
|
||||
IParser parser = encoding.newParser(getContext());
|
||||
IResource resource;
|
||||
if (requestContainsResource()) {
|
||||
|
@ -174,7 +174,7 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
|||
if (response != null && response.getOperationOutcome() != null) {
|
||||
theResponse.setContentType(encoding.getResourceContentType());
|
||||
Writer writer = theResponse.getWriter();
|
||||
parser.setPrettyPrint(prettyPrintResponse(theRequest));
|
||||
parser.setPrettyPrint(RestfulServer.prettyPrintResponse(theRequest));
|
||||
try {
|
||||
parser.encodeResourceToWriter(response.getOperationOutcome(), writer);
|
||||
} finally {
|
||||
|
@ -361,7 +361,7 @@ public abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBindin
|
|||
if (theE.getOperationOutcome() != null) {
|
||||
theResponse.setContentType(theEncoding.getResourceContentType());
|
||||
IParser parser = theEncoding.newParser(theServer.getFhirContext());
|
||||
parser.setPrettyPrint(prettyPrintResponse(theRequest));
|
||||
parser.setPrettyPrint(RestfulServer.prettyPrintResponse(theRequest));
|
||||
Writer writer = theResponse.getWriter();
|
||||
try {
|
||||
parser.encodeResourceToWriter(theE.getOperationOutcome(), writer);
|
||||
|
|
|
@ -187,7 +187,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
public void invokeServer(RestfulServer theServer, Request theRequest, HttpServletResponse theResponse) throws BaseServerResponseException, IOException {
|
||||
|
||||
// Pretty print
|
||||
boolean prettyPrint = prettyPrintResponse(theRequest);
|
||||
boolean prettyPrint = RestfulServer.prettyPrintResponse(theRequest);
|
||||
|
||||
// Narrative mode
|
||||
Map<String, String[]> requestParams = theRequest.getParameters();
|
||||
|
@ -201,7 +201,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
}
|
||||
|
||||
// Determine response encoding
|
||||
EncodingEnum responseEncoding = determineResponseEncoding(theRequest);
|
||||
EncodingEnum responseEncoding = RestfulServer.determineResponseEncoding(theRequest);
|
||||
|
||||
// Is this request coming from a browser
|
||||
String uaHeader = theRequest.getServletRequest().getHeader("user-agent");
|
||||
|
@ -237,63 +237,6 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override
|
||||
*/
|
||||
protected Object parseRequestObject(@SuppressWarnings("unused") Request theRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static IdDt getIdFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
|
||||
Object retValObj = theResourceMetadata.get(theKey);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof String) {
|
||||
if (isNotBlank((String) retValObj)) {
|
||||
return new IdDt((String) retValObj);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (retValObj instanceof IdDt) {
|
||||
if (((IdDt) retValObj).isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (IdDt) retValObj;
|
||||
}
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + IdDt.class.getCanonicalName());
|
||||
}
|
||||
|
||||
private static InstantDt getInstantFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
|
||||
Object retValObj = theResourceMetadata.get(theKey);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof Date) {
|
||||
return new InstantDt((Date) retValObj);
|
||||
} else if (retValObj instanceof InstantDt) {
|
||||
if (((InstantDt) retValObj).isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (InstantDt) retValObj;
|
||||
}
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + InstantDt.class.getCanonicalName());
|
||||
}
|
||||
|
||||
private static TagList getTagListFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
|
||||
Object retValObj = theResourceMetadata.get(theKey);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof TagList) {
|
||||
if (((TagList) retValObj).isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (TagList) retValObj;
|
||||
}
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + TagList.class.getCanonicalName());
|
||||
}
|
||||
|
||||
private IParser getNewParser(EncodingEnum theResponseEncoding, boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode) {
|
||||
IParser parser;
|
||||
switch (theResponseEncoding) {
|
||||
|
@ -343,96 +286,6 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
}
|
||||
}
|
||||
|
||||
public static Bundle createBundleFromResourceList(FhirContext theContext, String theAuthor, List<IResource> theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.getAuthorName().setValue(theAuthor);
|
||||
bundle.getBundleId().setValue(UUID.randomUUID().toString());
|
||||
bundle.getPublished().setToCurrentTimeInLocalTimeZone();
|
||||
bundle.getLinkBase().setValue(theServerBase);
|
||||
bundle.getLinkSelf().setValue(theCompleteUrl);
|
||||
|
||||
for (IResource next : theResult) {
|
||||
BundleEntry entry = new BundleEntry();
|
||||
bundle.getEntries().add(entry);
|
||||
|
||||
entry.setResource(next);
|
||||
TagList list = (TagList) next.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
|
||||
if (list != null) {
|
||||
for (Tag tag : list) {
|
||||
if (StringUtils.isNotBlank(tag.getTerm())) {
|
||||
entry.addCategory().setTerm(tag.getTerm()).setLabel(tag.getLabel()).setScheme(tag.getScheme());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(next);
|
||||
|
||||
if (next.getId() != null && StringUtils.isNotBlank(next.getId().getValue())) {
|
||||
entry.getId().setValue(next.getId().getValue());
|
||||
entry.getTitle().setValue(def.getName() + " " + next.getId().getValue());
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(theServerBase);
|
||||
if (b.charAt(b.length()-1) != '/') {
|
||||
b.append('/');
|
||||
}
|
||||
b.append(def.getName());
|
||||
b.append('/');
|
||||
String resId = next.getId().getUnqualifiedId();
|
||||
b.append(resId);
|
||||
|
||||
IdDt versionId = getIdFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.VERSION_ID);
|
||||
if (versionId != null) {
|
||||
b.append('/');
|
||||
b.append(Constants.PARAM_HISTORY);
|
||||
b.append('/');
|
||||
b.append(versionId.getValue());
|
||||
}
|
||||
|
||||
InstantDt published = getInstantFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.PUBLISHED);
|
||||
if (published == null) {
|
||||
entry.getPublished().setToCurrentTimeInLocalTimeZone();
|
||||
} else {
|
||||
entry.setPublished(published);
|
||||
}
|
||||
|
||||
InstantDt updated = getInstantFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.UPDATED);
|
||||
if (updated != null) {
|
||||
entry.setUpdated(updated);
|
||||
}
|
||||
|
||||
TagList tagList = getTagListFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.TAG_LIST);
|
||||
if (tagList != null) {
|
||||
for (Tag nextTag : tagList) {
|
||||
entry.addCategory(nextTag);
|
||||
}
|
||||
}
|
||||
|
||||
boolean haveQ = false;
|
||||
if (thePrettyPrint) {
|
||||
b.append('?').append(Constants.PARAM_PRETTY).append("=true");
|
||||
haveQ = true;
|
||||
}
|
||||
if (theResponseEncoding == EncodingEnum.JSON) {
|
||||
if (!haveQ) {
|
||||
b.append('?');
|
||||
haveQ = true;
|
||||
} else {
|
||||
b.append('&');
|
||||
}
|
||||
b.append(Constants.PARAM_FORMAT).append("=json");
|
||||
}
|
||||
if (theNarrativeMode != NarrativeModeEnum.NORMAL) {
|
||||
b.append(Constants.PARAM_NARRATIVE).append("=").append(theNarrativeMode.name().toLowerCase());
|
||||
}
|
||||
entry.getLinkSelf().setValue(b.toString());
|
||||
}
|
||||
}
|
||||
|
||||
bundle.getTotalResults().setValue(theResult.size());
|
||||
return bundle;
|
||||
}
|
||||
|
||||
private void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode) throws IOException {
|
||||
|
||||
theHttpResponse.setStatus(200);
|
||||
|
@ -474,6 +327,171 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override
|
||||
*/
|
||||
protected Object parseRequestObject(@SuppressWarnings("unused") Request theRequest) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Bundle createBundleFromResourceList(FhirContext theContext, String theAuthor, List<IResource> theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.getAuthorName().setValue(theAuthor);
|
||||
bundle.getBundleId().setValue(UUID.randomUUID().toString());
|
||||
bundle.getPublished().setToCurrentTimeInLocalTimeZone();
|
||||
bundle.getLinkBase().setValue(theServerBase);
|
||||
bundle.getLinkSelf().setValue(theCompleteUrl);
|
||||
|
||||
for (IResource next : theResult) {
|
||||
BundleEntry entry = new BundleEntry();
|
||||
bundle.getEntries().add(entry);
|
||||
|
||||
entry.setResource(next);
|
||||
TagList list = (TagList) next.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
|
||||
if (list != null) {
|
||||
for (Tag tag : list) {
|
||||
if (StringUtils.isNotBlank(tag.getTerm())) {
|
||||
entry.addCategory().setTerm(tag.getTerm()).setLabel(tag.getLabel()).setScheme(tag.getScheme());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = theContext.getResourceDefinition(next);
|
||||
|
||||
if (next.getId() != null && StringUtils.isNotBlank(next.getId().getValue())) {
|
||||
entry.getTitle().setValue(def.getName() + " " + next.getId().getValue());
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(theServerBase);
|
||||
if (b.length() > 0 && b.charAt(b.length() - 1) != '/') {
|
||||
b.append('/');
|
||||
}
|
||||
b.append(def.getName());
|
||||
b.append('/');
|
||||
String resId = next.getId().getUnqualifiedId();
|
||||
b.append(resId);
|
||||
|
||||
entry.getId().setValue(b.toString());
|
||||
|
||||
if (isNotBlank(next.getId().getUnqualifiedVersionId())) {
|
||||
b.append('/');
|
||||
b.append(Constants.PARAM_HISTORY);
|
||||
b.append('/');
|
||||
b.append(next.getId().getUnqualifiedVersionId());
|
||||
} else {
|
||||
IdDt versionId = getIdFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.VERSION_ID);
|
||||
if (versionId != null) {
|
||||
b.append('/');
|
||||
b.append(Constants.PARAM_HISTORY);
|
||||
b.append('/');
|
||||
b.append(versionId.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
InstantDt published = getInstantFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.PUBLISHED);
|
||||
if (published == null) {
|
||||
entry.getPublished().setToCurrentTimeInLocalTimeZone();
|
||||
} else {
|
||||
entry.setPublished(published);
|
||||
}
|
||||
|
||||
InstantDt updated = getInstantFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.UPDATED);
|
||||
if (updated != null) {
|
||||
entry.setUpdated(updated);
|
||||
}
|
||||
|
||||
InstantDt deleted = getInstantFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.DELETED_AT);
|
||||
if (deleted != null) {
|
||||
entry.setDeleted(deleted);
|
||||
}
|
||||
|
||||
IdDt previous = getIdFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.PREVIOUS_ID);
|
||||
if (previous != null) {
|
||||
entry.getLinkAlternate().setValue(previous.toQualifiedUrl(theServerBase, def.getName()));
|
||||
}
|
||||
|
||||
TagList tagList = getTagListFromMetadataOrNullIfNone(next.getResourceMetadata(), ResourceMetadataKeyEnum.TAG_LIST);
|
||||
if (tagList != null) {
|
||||
for (Tag nextTag : tagList) {
|
||||
entry.addCategory(nextTag);
|
||||
}
|
||||
}
|
||||
|
||||
// boolean haveQ = false;
|
||||
// if (thePrettyPrint) {
|
||||
// b.append('?').append(Constants.PARAM_PRETTY).append("=true");
|
||||
// haveQ = true;
|
||||
// }
|
||||
// if (theResponseEncoding == EncodingEnum.JSON) {
|
||||
// if (!haveQ) {
|
||||
// b.append('?');
|
||||
// haveQ = true;
|
||||
// } else {
|
||||
// b.append('&');
|
||||
// }
|
||||
// b.append(Constants.PARAM_FORMAT).append("=json");
|
||||
// }
|
||||
// if (theNarrativeMode != NarrativeModeEnum.NORMAL) {
|
||||
// b.append(Constants.PARAM_NARRATIVE).append("=").append(theNarrativeMode.name().toLowerCase());
|
||||
// }
|
||||
entry.getLinkSelf().setValue(b.toString());
|
||||
}
|
||||
}
|
||||
|
||||
bundle.getTotalResults().setValue(theResult.size());
|
||||
return bundle;
|
||||
}
|
||||
|
||||
private static InstantDt getInstantFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
|
||||
Object retValObj = theResourceMetadata.get(theKey);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof Date) {
|
||||
return new InstantDt((Date) retValObj);
|
||||
} else if (retValObj instanceof InstantDt) {
|
||||
if (((InstantDt) retValObj).isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (InstantDt) retValObj;
|
||||
}
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + InstantDt.class.getCanonicalName());
|
||||
}
|
||||
|
||||
private static TagList getTagListFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
|
||||
Object retValObj = theResourceMetadata.get(theKey);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof TagList) {
|
||||
if (((TagList) retValObj).isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (TagList) retValObj;
|
||||
}
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + TagList.class.getCanonicalName());
|
||||
}
|
||||
|
||||
protected static IdDt getIdFromMetadataOrNullIfNone(Map<ResourceMetadataKeyEnum, Object> theResourceMetadata, ResourceMetadataKeyEnum theKey) {
|
||||
Object retValObj = theResourceMetadata.get(theKey);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof String) {
|
||||
if (isNotBlank((String) retValObj)) {
|
||||
return new IdDt((String) retValObj);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else if (retValObj instanceof IdDt) {
|
||||
if (((IdDt) retValObj).isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return (IdDt) retValObj;
|
||||
}
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName() + "' in resource metadata for key " + theKey.name() + " - Expected " + IdDt.class.getCanonicalName());
|
||||
}
|
||||
|
||||
public enum MethodReturnTypeEnum {
|
||||
BUNDLE, LIST_OF_RESOURCES, RESOURCE
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
|
|||
|
||||
TagList resp = (TagList) invokeServerMethod(params);
|
||||
|
||||
EncodingEnum responseEncoding = determineResponseEncoding(theRequest);
|
||||
EncodingEnum responseEncoding = RestfulServer.determineResponseEncoding(theRequest);
|
||||
|
||||
theResponse.setContentType(responseEncoding.getResourceContentType());
|
||||
theResponse.setStatus(Constants.STATUS_HTTP_200_OK);
|
||||
|
@ -164,7 +164,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
|
|||
theServer.addHeadersToResponse(theResponse);
|
||||
|
||||
IParser parser = responseEncoding.newParser(getContext());
|
||||
parser.setPrettyPrint(prettyPrintResponse(theRequest));
|
||||
parser.setPrettyPrint(RestfulServer.prettyPrintResponse(theRequest));
|
||||
PrintWriter writer = theResponse.getWriter();
|
||||
try {
|
||||
parser.encodeTagListToWriter(resp, writer);
|
||||
|
|
|
@ -23,42 +23,45 @@ package ca.uhn.fhir.rest.method;
|
|||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.annotation.TransactionParam;
|
||||
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
|
||||
import ca.uhn.fhir.rest.param.TransactionParameter;
|
||||
import ca.uhn.fhir.rest.param.IParameter;
|
||||
import ca.uhn.fhir.rest.param.TransactionParameter;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class TransactionMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
|
||||
private int myResourceParameterIndex;
|
||||
private int myTransactionParamIndex;
|
||||
|
||||
public TransactionMethodBinding(Method theMethod, FhirContext theConetxt, Object theProvider) {
|
||||
super(null, theMethod, theConetxt, theProvider);
|
||||
|
||||
myResourceParameterIndex = -1;
|
||||
myTransactionParamIndex = -1;
|
||||
int index=0;
|
||||
for (IParameter next : getParameters()) {
|
||||
if (next instanceof TransactionParameter) {
|
||||
myResourceParameterIndex = index;
|
||||
myTransactionParamIndex = index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
if (myResourceParameterIndex==-1) {
|
||||
if (myTransactionParamIndex==-1) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type " + theMethod.getDeclaringClass().getCanonicalName() + " does not have a parameter annotated with the @" + TransactionParam.class + " annotation");
|
||||
}
|
||||
}
|
||||
|
@ -88,16 +91,42 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
|
|||
return ReturnTypeEnum.BUNDLE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public List<IResource> invokeServer(Request theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<IResource> resources = (List<IResource>) theMethodParams[myTransactionParamIndex];
|
||||
|
||||
List<IdDt> oldIds= new ArrayList<IdDt>();
|
||||
for (IResource next : resources) {
|
||||
oldIds.add(next.getId());
|
||||
}
|
||||
|
||||
List<IResource> retVal=(List<IResource>) invokeServerMethod(theMethodParams);
|
||||
|
||||
if (retVal.size() != resources.size()) {
|
||||
throw new InternalErrorException("Transaction bundle contained " + resources.size() + " entries, but server method response contained " + retVal.size() + " entries (must be the same)");
|
||||
}
|
||||
|
||||
for (int i =0; i < resources.size(); i++) {
|
||||
IdDt oldId = oldIds.get(i);
|
||||
IResource newRes = retVal.get(i);
|
||||
if (newRes.getId() == null || newRes.getId().isEmpty()) {
|
||||
throw new InternalErrorException("Transaction method returned resource at index " + i + " with no id specified - IResource#setId(IdDt)");
|
||||
}
|
||||
|
||||
if (oldId != null && !oldId.isEmpty()) {
|
||||
if (!oldId.getId().equals(newRes.getId())) {
|
||||
newRes.getResourceMetadata().put(ResourceMetadataKeyEnum.PREVIOUS_ID, oldId.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object parseRequestObject(Request theRequest) {
|
||||
EncodingEnum encoding = determineResponseEncoding(theRequest);
|
||||
EncodingEnum encoding = RestfulServer.determineResponseEncoding(theRequest);
|
||||
IParser parser = encoding.newParser(getContext());
|
||||
Bundle bundle = parser.parseBundle(theRequest.getInputReader());
|
||||
return bundle;
|
||||
|
@ -110,7 +139,7 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
|
|||
|
||||
@Override
|
||||
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
List<IResource> resources = (List<IResource>) theArgs[myResourceParameterIndex];
|
||||
List<IResource> resources = (List<IResource>) theArgs[myTransactionParamIndex];
|
||||
FhirContext context = getContext();
|
||||
|
||||
return new HttpPostClientInvocation(context, resources);
|
||||
|
|
|
@ -75,6 +75,7 @@ public class Constants {
|
|||
public static final String FORMAT_JSON = "json";
|
||||
public static final String PARAM_INCLUDE = "_include";
|
||||
public static final String PARAMQUALIFIER_STRING_EXACT = ":exact";
|
||||
public static final String HEADER_ACCEPT = "Accept";
|
||||
|
||||
static {
|
||||
Map<String, EncodingEnum> valToEncoding = new HashMap<String, EncodingEnum>();
|
||||
|
|
|
@ -20,12 +20,15 @@ package ca.uhn.fhir.rest.server;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
@ -448,6 +451,13 @@ public class RestfulServer extends HttpServlet {
|
|||
handleRequest(SearchMethodBinding.RequestType.PUT, request, response);
|
||||
}
|
||||
|
||||
private static String getBaseUrl(HttpServletRequest request) {
|
||||
if (("http".equals(request.getScheme()) && request.getServerPort() == 80) || ("https".equals(request.getScheme()) && request.getServerPort() == 443))
|
||||
return request.getScheme() + "://" + request.getServerName() + request.getContextPath();
|
||||
else
|
||||
return request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath();
|
||||
}
|
||||
|
||||
protected void handleRequest(SearchMethodBinding.RequestType theRequestType, HttpServletRequest theRequest, HttpServletResponse theResponse) throws ServletException, IOException {
|
||||
try {
|
||||
|
||||
|
@ -457,8 +467,6 @@ public class RestfulServer extends HttpServlet {
|
|||
|
||||
String resourceName = null;
|
||||
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
|
||||
// String contextPath =
|
||||
// StringUtils.defaultString(request.getContextPath());
|
||||
String servletPath = StringUtils.defaultString(theRequest.getServletPath());
|
||||
StringBuffer requestUrl = theRequest.getRequestURL();
|
||||
String servletContextPath = "";
|
||||
|
@ -475,25 +483,30 @@ public class RestfulServer extends HttpServlet {
|
|||
ourLog.trace("Context Path: {}", servletContextPath);
|
||||
}
|
||||
|
||||
servletPath = servletContextPath;
|
||||
|
||||
IdDt id = null;
|
||||
IdDt versionId = null;
|
||||
String operation = null;
|
||||
|
||||
String requestPath = requestFullPath.substring(servletPath.length());
|
||||
String requestPath = requestFullPath.substring(servletContextPath.length() + servletPath.length());
|
||||
if (requestPath.length() > 0 && requestPath.charAt(0) == '/') {
|
||||
requestPath = requestPath.substring(1);
|
||||
}
|
||||
|
||||
int contextIndex;
|
||||
if (servletPath.length() == 0) {
|
||||
contextIndex = requestUrl.indexOf(requestPath);
|
||||
if (requestPath.length() == 0) {
|
||||
contextIndex = requestUrl.length();
|
||||
} else {
|
||||
contextIndex = requestUrl.indexOf(requestPath);
|
||||
}
|
||||
} else {
|
||||
contextIndex = requestUrl.indexOf(servletPath);
|
||||
}
|
||||
|
||||
String fhirServerBase = requestUrl.substring(0, contextIndex + servletPath.length());
|
||||
String fhirServerBase;
|
||||
int length = contextIndex + servletPath.length();
|
||||
fhirServerBase = requestUrl.substring(0, length);
|
||||
|
||||
if (fhirServerBase.endsWith("/")) {
|
||||
fhirServerBase = fhirServerBase.substring(0, fhirServerBase.length() - 1);
|
||||
}
|
||||
|
@ -640,6 +653,67 @@ public class RestfulServer extends HttpServlet {
|
|||
// nothing by default
|
||||
}
|
||||
|
||||
public static boolean prettyPrintResponse(Request theRequest) {
|
||||
Map<String, String[]> requestParams = theRequest.getParameters();
|
||||
String[] pretty = requestParams.remove(Constants.PARAM_PRETTY);
|
||||
boolean prettyPrint;
|
||||
if (pretty != null && pretty.length > 0) {
|
||||
if (Constants.PARAM_PRETTY_VALUE_TRUE.equals(pretty[0])) {
|
||||
prettyPrint = true;
|
||||
} else {
|
||||
prettyPrint = false;
|
||||
}
|
||||
} else {
|
||||
prettyPrint = false;
|
||||
Enumeration<String> acceptValues = theRequest.getServletRequest().getHeaders(Constants.HEADER_ACCEPT);
|
||||
if (acceptValues != null) {
|
||||
while (acceptValues.hasMoreElements()) {
|
||||
String nextAcceptHeaderValue = acceptValues.nextElement();
|
||||
if (nextAcceptHeaderValue.contains("pretty=true")) {
|
||||
prettyPrint = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return prettyPrint;
|
||||
}
|
||||
|
||||
public static EncodingEnum determineResponseEncoding(Request theReq) {
|
||||
String[] format = theReq.getParameters().remove(Constants.PARAM_FORMAT);
|
||||
if (format != null) {
|
||||
for (String nextFormat : format) {
|
||||
EncodingEnum retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextFormat);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Enumeration<String> acceptValues = theReq.getServletRequest().getHeaders(Constants.HEADER_ACCEPT);
|
||||
if (acceptValues != null) {
|
||||
while (acceptValues.hasMoreElements()) {
|
||||
String nextAcceptHeaderValue = acceptValues.nextElement();
|
||||
if (nextAcceptHeaderValue != null && isNotBlank(nextAcceptHeaderValue)) {
|
||||
for (String nextPart : nextAcceptHeaderValue.split(",")) {
|
||||
int scIdx = nextPart.indexOf(';');
|
||||
if (scIdx == 0) {
|
||||
continue;
|
||||
}
|
||||
if (scIdx != -1) {
|
||||
nextPart = nextPart.substring(0, scIdx);
|
||||
}
|
||||
nextPart = nextPart.trim();
|
||||
EncodingEnum retVal = Constants.FORMAT_VAL_TO_ENCODING.get(nextPart);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return EncodingEnum.XML;
|
||||
}
|
||||
|
||||
public enum NarrativeModeEnum {
|
||||
NORMAL, ONLY, SUPPRESS;
|
||||
|
||||
|
|
|
@ -0,0 +1,247 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
/*
|
||||
* #%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 javax.xml.namespace.NamespaceContext;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
|
||||
public class NonPrettyPrintWriterWrapper implements XMLStreamWriter {
|
||||
|
||||
private static final String PRE = "pre";
|
||||
private XMLStreamWriter myTarget;
|
||||
private int myInsidePre = 0;
|
||||
|
||||
public NonPrettyPrintWriterWrapper(XMLStreamWriter target) {
|
||||
myTarget = target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws XMLStreamException {
|
||||
myTarget.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws XMLStreamException {
|
||||
myTarget.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix(String theUri) throws XMLStreamException {
|
||||
return myTarget.getPrefix(theUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrefix(String thePrefix, String theUri) throws XMLStreamException {
|
||||
myTarget.setPrefix(thePrefix, theUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultNamespace(String theUri) throws XMLStreamException {
|
||||
myTarget.setDefaultNamespace(theUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNamespaceContext(NamespaceContext theContext) throws XMLStreamException {
|
||||
myTarget.setNamespaceContext(theContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceContext getNamespaceContext() {
|
||||
return myTarget.getNamespaceContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartElement(String theLocalName) throws XMLStreamException {
|
||||
if (PRE.equals(theLocalName) || myInsidePre > 0) {
|
||||
myInsidePre++;
|
||||
}
|
||||
myTarget.writeStartElement(theLocalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartElement(String theNamespaceURI, String theLocalName) throws XMLStreamException {
|
||||
if (PRE.equals(theLocalName) || myInsidePre > 0) {
|
||||
myInsidePre++;
|
||||
}
|
||||
myTarget.writeStartElement(theNamespaceURI, theLocalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
|
||||
if (PRE.equals(theLocalName) || myInsidePre > 0) {
|
||||
myInsidePre++;
|
||||
}
|
||||
myTarget.writeStartElement(thePrefix, theLocalName, theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEmptyElement(String theNamespaceURI, String theLocalName) throws XMLStreamException {
|
||||
myTarget.writeEmptyElement(theNamespaceURI, theLocalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEmptyElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
|
||||
myTarget.writeEmptyElement(thePrefix, theLocalName, theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEmptyElement(String theLocalName) throws XMLStreamException {
|
||||
myTarget.writeEmptyElement(theLocalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndElement() throws XMLStreamException {
|
||||
if (myInsidePre > 0) {
|
||||
myInsidePre--;
|
||||
}
|
||||
myTarget.writeEndElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndDocument() throws XMLStreamException {
|
||||
myTarget.writeEndDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeAttribute(String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(theLocalName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeAttribute(String thePrefix, String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(thePrefix, theNamespaceURI, theLocalName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeAttribute(String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(theNamespaceURI, theLocalName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNamespace(String thePrefix, String theNamespaceURI) throws XMLStreamException {
|
||||
myTarget.writeNamespace(thePrefix, theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDefaultNamespace(String theNamespaceURI) throws XMLStreamException {
|
||||
myTarget.writeDefaultNamespace(theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeComment(String theData) throws XMLStreamException {
|
||||
myTarget.writeComment(theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeProcessingInstruction(String theTarget) throws XMLStreamException {
|
||||
myTarget.writeProcessingInstruction(theTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeProcessingInstruction(String theTarget, String theData) throws XMLStreamException {
|
||||
myTarget.writeProcessingInstruction(theTarget, theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCData(String theData) throws XMLStreamException {
|
||||
myTarget.writeCData(theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDTD(String theDtd) throws XMLStreamException {
|
||||
myTarget.writeDTD(theDtd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEntityRef(String theName) throws XMLStreamException {
|
||||
myTarget.writeEntityRef(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartDocument() throws XMLStreamException {
|
||||
myTarget.writeStartDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartDocument(String theVersion) throws XMLStreamException {
|
||||
myTarget.writeStartDocument(theVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartDocument(String theEncoding, String theVersion) throws XMLStreamException {
|
||||
myTarget.writeStartDocument(theEncoding, theVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCharacters(String theText) throws XMLStreamException {
|
||||
if (myInsidePre > 0) {
|
||||
myTarget.writeCharacters(theText);
|
||||
} else {
|
||||
writeCharacters(theText.toCharArray(), 0, theText.length());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCharacters(char[] theText, int theStart, int theLen) throws XMLStreamException {
|
||||
writeCharacters(theText, theStart, theLen, myTarget, myInsidePre);
|
||||
}
|
||||
|
||||
static void writeCharacters(char[] theText, int theStart, int theLen, XMLStreamWriter target, int insidePre) throws XMLStreamException {
|
||||
if (theLen == 0) {
|
||||
return;
|
||||
} else {
|
||||
if (insidePre > 0) {
|
||||
target.writeCharacters(theText, theStart, theLen);
|
||||
} else {
|
||||
int initialEnd = theStart + (theLen - 1);
|
||||
int start = theStart;
|
||||
int end = initialEnd;
|
||||
while (Character.isWhitespace(theText[start]) && start < end) {
|
||||
start++;
|
||||
}
|
||||
while (Character.isWhitespace(theText[end]) && end > start) {
|
||||
end--;
|
||||
}
|
||||
if (start == end) {
|
||||
if (Character.isWhitespace(theText[start])) {
|
||||
target.writeCharacters(" ");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (start > theStart) {
|
||||
target.writeCharacters(" ");
|
||||
}
|
||||
target.writeCharacters(theText, start, (end - start) + 1);
|
||||
if (end < initialEnd) {
|
||||
target.writeCharacters(" ");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String theName) throws IllegalArgumentException {
|
||||
return myTarget.getProperty(theName);
|
||||
}
|
||||
|
||||
}
|
|
@ -31,39 +31,43 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
public class PrettyPrintWriterWrapper implements XMLStreamWriter {
|
||||
|
||||
private XMLStreamWriter myTarget;
|
||||
private static final String INDENT_CHAR = " ";
|
||||
private static final String LINEFEED_CHAR = "\n";
|
||||
private static final String PRE = "pre";
|
||||
private int depth = 0;
|
||||
private Map<Integer, Boolean> hasChildElement = new HashMap<Integer, Boolean>();
|
||||
|
||||
private static final String INDENT_CHAR = " ";
|
||||
private static final String LINEFEED_CHAR = "\n";
|
||||
private int myInsidePre = 0;
|
||||
private XMLStreamWriter myTarget;
|
||||
private boolean myFirstIndent=true;
|
||||
|
||||
public PrettyPrintWriterWrapper(XMLStreamWriter target) {
|
||||
myTarget = target;
|
||||
}
|
||||
|
||||
private String repeat(int d, String s) {
|
||||
return StringUtils.repeat(s, d * 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws XMLStreamException {
|
||||
myTarget.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws XMLStreamException {
|
||||
myTarget.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws XMLStreamException {
|
||||
myTarget.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamespaceContext getNamespaceContext() {
|
||||
return myTarget.getNamespaceContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix(String theUri) throws XMLStreamException {
|
||||
return myTarget.getPrefix(theUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPrefix(String thePrefix, String theUri) throws XMLStreamException {
|
||||
myTarget.setPrefix(thePrefix, theUri);
|
||||
public Object getProperty(String theName) throws IllegalArgumentException {
|
||||
return myTarget.getProperty(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,44 +81,63 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public NamespaceContext getNamespaceContext() {
|
||||
return myTarget.getNamespaceContext();
|
||||
public void setPrefix(String thePrefix, String theUri) throws XMLStreamException {
|
||||
myTarget.setPrefix(thePrefix, theUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartElement(String theLocalName) throws XMLStreamException {
|
||||
indentAndAdd();
|
||||
myTarget.writeStartElement(theLocalName);
|
||||
public void writeAttribute(String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(theLocalName, theValue);
|
||||
}
|
||||
|
||||
private void indentAndAdd() throws XMLStreamException {
|
||||
indent();
|
||||
@Override
|
||||
public void writeAttribute(String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(theNamespaceURI, theLocalName, theValue);
|
||||
}
|
||||
|
||||
// update state of parent node
|
||||
if (depth > 0) {
|
||||
hasChildElement.put(depth - 1, true);
|
||||
@Override
|
||||
public void writeAttribute(String thePrefix, String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(thePrefix, theNamespaceURI, theLocalName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCData(String theData) throws XMLStreamException {
|
||||
myTarget.writeCData(theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCharacters(char[] theText, int theStart, int theLen) throws XMLStreamException {
|
||||
NonPrettyPrintWriterWrapper.writeCharacters(theText, theStart, theLen, myTarget, myInsidePre);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCharacters(String theText) throws XMLStreamException {
|
||||
if (myInsidePre > 0) {
|
||||
myTarget.writeCharacters(theText);
|
||||
} else {
|
||||
writeCharacters(theText.toCharArray(), 0, theText.length());
|
||||
}
|
||||
|
||||
// reset state of current node
|
||||
hasChildElement.put(depth, false);
|
||||
|
||||
depth++;
|
||||
}
|
||||
|
||||
private void indent() throws XMLStreamException {
|
||||
myTarget.writeCharacters(LINEFEED_CHAR + repeat(depth, INDENT_CHAR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartElement(String theNamespaceURI, String theLocalName) throws XMLStreamException {
|
||||
indentAndAdd();
|
||||
myTarget.writeStartElement(theNamespaceURI, theLocalName);
|
||||
public void writeComment(String theData) throws XMLStreamException {
|
||||
myTarget.writeComment(theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
|
||||
indentAndAdd();
|
||||
myTarget.writeStartElement(thePrefix, theLocalName, theNamespaceURI);
|
||||
public void writeDefaultNamespace(String theNamespaceURI) throws XMLStreamException {
|
||||
myTarget.writeDefaultNamespace(theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDTD(String theDtd) throws XMLStreamException {
|
||||
myTarget.writeDTD(theDtd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEmptyElement(String theLocalName) throws XMLStreamException {
|
||||
indent();
|
||||
myTarget.writeEmptyElement(theLocalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -129,28 +152,6 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
|
|||
myTarget.writeEmptyElement(thePrefix, theLocalName, theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEmptyElement(String theLocalName) throws XMLStreamException {
|
||||
indent();
|
||||
myTarget.writeEmptyElement(theLocalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndElement() throws XMLStreamException {
|
||||
decrementAndIndent();
|
||||
|
||||
myTarget.writeEndElement();
|
||||
}
|
||||
|
||||
private void decrementAndIndent() throws XMLStreamException {
|
||||
depth--;
|
||||
|
||||
if (hasChildElement.get(depth) == true) {
|
||||
// indent for current depth
|
||||
myTarget.writeCharacters(LINEFEED_CHAR + repeat(depth, INDENT_CHAR));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEndDocument() throws XMLStreamException {
|
||||
decrementAndIndent();
|
||||
|
@ -158,18 +159,19 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void writeAttribute(String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(theLocalName, theValue);
|
||||
public void writeEndElement() throws XMLStreamException {
|
||||
if (myInsidePre > 0) {
|
||||
myInsidePre--;
|
||||
}
|
||||
decrementAndIndent();
|
||||
|
||||
myTarget.writeEndElement();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeAttribute(String thePrefix, String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(thePrefix, theNamespaceURI, theLocalName, theValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeAttribute(String theNamespaceURI, String theLocalName, String theValue) throws XMLStreamException {
|
||||
myTarget.writeAttribute(theNamespaceURI, theLocalName, theValue);
|
||||
public void writeEntityRef(String theName) throws XMLStreamException {
|
||||
myTarget.writeEntityRef(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -177,16 +179,6 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
|
|||
myTarget.writeNamespace(thePrefix, theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDefaultNamespace(String theNamespaceURI) throws XMLStreamException {
|
||||
myTarget.writeDefaultNamespace(theNamespaceURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeComment(String theData) throws XMLStreamException {
|
||||
myTarget.writeComment(theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeProcessingInstruction(String theTarget) throws XMLStreamException {
|
||||
myTarget.writeProcessingInstruction(theTarget);
|
||||
|
@ -197,49 +189,90 @@ public class PrettyPrintWriterWrapper implements XMLStreamWriter {
|
|||
myTarget.writeProcessingInstruction(theTarget, theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCData(String theData) throws XMLStreamException {
|
||||
myTarget.writeCData(theData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeDTD(String theDtd) throws XMLStreamException {
|
||||
myTarget.writeDTD(theDtd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeEntityRef(String theName) throws XMLStreamException {
|
||||
myTarget.writeEntityRef(theName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartDocument() throws XMLStreamException {
|
||||
myFirstIndent=true;
|
||||
myTarget.writeStartDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartDocument(String theVersion) throws XMLStreamException {
|
||||
myFirstIndent=true;
|
||||
myTarget.writeStartDocument(theVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeStartDocument(String theEncoding, String theVersion) throws XMLStreamException {
|
||||
myFirstIndent=true;
|
||||
myTarget.writeStartDocument(theEncoding, theVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCharacters(String theText) throws XMLStreamException {
|
||||
myTarget.writeCharacters(theText);
|
||||
public void writeStartElement(String theLocalName) throws XMLStreamException {
|
||||
indentAndAdd();
|
||||
myTarget.writeStartElement(theLocalName);
|
||||
if (PRE.equals(theLocalName) || myInsidePre > 0) {
|
||||
myInsidePre++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeCharacters(char[] theText, int theStart, int theLen) throws XMLStreamException {
|
||||
myTarget.writeCharacters(theText, theStart, theLen);
|
||||
public void writeStartElement(String theNamespaceURI, String theLocalName) throws XMLStreamException {
|
||||
indentAndAdd();
|
||||
myTarget.writeStartElement(theNamespaceURI, theLocalName);
|
||||
if (PRE.equals(theLocalName) || myInsidePre > 0) {
|
||||
myInsidePre++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String theName) throws IllegalArgumentException {
|
||||
return myTarget.getProperty(theName);
|
||||
public void writeStartElement(String thePrefix, String theLocalName, String theNamespaceURI) throws XMLStreamException {
|
||||
indentAndAdd();
|
||||
myTarget.writeStartElement(thePrefix, theLocalName, theNamespaceURI);
|
||||
if (PRE.equals(theLocalName) || myInsidePre > 0) {
|
||||
myInsidePre++;
|
||||
}
|
||||
}
|
||||
|
||||
private void decrementAndIndent() throws XMLStreamException {
|
||||
if (myInsidePre > 0) {
|
||||
return;
|
||||
}
|
||||
depth--;
|
||||
|
||||
if (hasChildElement.get(depth) == true) {
|
||||
// indent for current depth
|
||||
myTarget.writeCharacters(LINEFEED_CHAR + repeat(depth, INDENT_CHAR));
|
||||
}
|
||||
}
|
||||
|
||||
private void indent() throws XMLStreamException {
|
||||
if (myFirstIndent) {
|
||||
myFirstIndent = false;
|
||||
return;
|
||||
}
|
||||
myTarget.writeCharacters(LINEFEED_CHAR + repeat(depth, INDENT_CHAR));
|
||||
}
|
||||
|
||||
private void indentAndAdd() throws XMLStreamException {
|
||||
if (myInsidePre > 0) {
|
||||
return;
|
||||
}
|
||||
indent();
|
||||
|
||||
// update state of parent node
|
||||
if (depth > 0) {
|
||||
hasChildElement.put(depth - 1, true);
|
||||
}
|
||||
|
||||
// reset state of current node
|
||||
hasChildElement.put(depth, false);
|
||||
|
||||
depth++;
|
||||
}
|
||||
|
||||
private String repeat(int d, String s) {
|
||||
return StringUtils.repeat(s, d * 3);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -759,13 +759,24 @@ public List<IResource> transaction(@TransactionParam List<IResource> theResource
|
|||
}
|
||||
}
|
||||
|
||||
ArrayList<IResource> retVal = new ArrayList<IResource>();
|
||||
/*
|
||||
* According to the specification, a bundle must be returned. This bundle will contain
|
||||
* all of the created/updated/deleted resources, including their new/updated identities.
|
||||
*
|
||||
* Implementing this will depend on your specific application
|
||||
* The returned list must be the exact same size as the list of resources
|
||||
* passed in, and it is acceptable to return the same list instance that was
|
||||
* passed in.
|
||||
*/
|
||||
List<IResource> retVal = theResources;
|
||||
for (IResource next : theResources) {
|
||||
/*
|
||||
* Populate each returned resource with the new ID for that resource,
|
||||
* including the new version if the server supports versioning.
|
||||
*/
|
||||
IdDt newId = new IdDt("Patient", "1", "2");
|
||||
next.setId(newId);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
//END SNIPPET: transaction
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
package ca.uhn.fhir.model.dstu.composite;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
|
||||
public class ResourceReferenceDtTest {
|
||||
|
||||
private static FhirContext ourCtx;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceReferenceDtTest.class);
|
||||
|
||||
@Test
|
||||
public void testParseValueAbsolute() {
|
||||
}
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = new FhirContext();
|
||||
}
|
||||
|
||||
}
|
|
@ -10,6 +10,8 @@ import java.io.IOException;
|
|||
import java.io.OutputStreamWriter;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.sf.json.JSON;
|
||||
|
@ -18,6 +20,7 @@ import net.sf.json.JSONSerializer;
|
|||
import org.apache.commons.io.IOUtils;
|
||||
import org.hamcrest.core.IsNot;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hamcrest.text.StringContainsInOrder;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -47,6 +50,7 @@ import ca.uhn.fhir.model.dstu.resource.ValueSet.DefineConcept;
|
|||
import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum;
|
||||
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
|
||||
import ca.uhn.fhir.model.primitive.DecimalDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||
|
@ -541,6 +545,38 @@ public class JsonParserTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBundle() {
|
||||
Bundle b= new Bundle();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().addFamily("Family1");
|
||||
BundleEntry entry = b.addEntry();
|
||||
entry.getId().setValue("1");
|
||||
entry.setResource(p1);
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().addFamily("Family2");
|
||||
entry = b.addEntry();
|
||||
entry.getId().setValue("2");
|
||||
entry.setLinkAlternate(new StringDt("http://foo/bar"));
|
||||
entry.setResource(p2);
|
||||
|
||||
BundleEntry deletedEntry = b.addEntry();
|
||||
deletedEntry.setId(new IdDt("Patient/3"));
|
||||
InstantDt nowDt = InstantDt.withCurrentTime();
|
||||
deletedEntry.setDeleted(nowDt);
|
||||
|
||||
String bundleString = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b);
|
||||
ourLog.info(bundleString);
|
||||
|
||||
List<String> strings = new ArrayList<String>();
|
||||
strings.addAll(Arrays.asList("\"id\":\"1\""));
|
||||
strings.addAll(Arrays.asList("\"id\":\"2\"", "\"rel\":\"alternate\"", "\"href\":\"http://foo/bar\""));
|
||||
strings.addAll(Arrays.asList("\"deleted\":\""+nowDt.getValueAsString()+"\"", "\"id\":\"Patient/3\""));
|
||||
assertThat(bundleString, StringContainsInOrder.stringContainsInOrder(strings));
|
||||
|
||||
}
|
||||
@Test
|
||||
public void testSimpleBundleEncode() throws IOException {
|
||||
|
||||
|
|
|
@ -269,6 +269,7 @@ public class XmlParserTest {
|
|||
p2.addName().addFamily("Family2");
|
||||
entry = b.addEntry();
|
||||
entry.getId().setValue("2");
|
||||
entry.setLinkAlternate(new StringDt("http://foo/bar"));
|
||||
entry.setResource(p2);
|
||||
|
||||
BundleEntry deletedEntry = b.addEntry();
|
||||
|
@ -280,7 +281,7 @@ public class XmlParserTest {
|
|||
|
||||
List<String> strings = new ArrayList<String>();
|
||||
strings.addAll(Arrays.asList("<entry>", "<id>1</id>", "</entry>"));
|
||||
strings.addAll(Arrays.asList("<entry>", "<id>2</id>", "</entry>"));
|
||||
strings.addAll(Arrays.asList("<entry>", "<id>2</id>", "<link rel=\"alternate\" href=\"http://foo/bar\"/>", "</entry>"));
|
||||
strings.addAll(Arrays.asList("<at:deleted-entry", "ref=\"Patient/3", "/>"));
|
||||
assertThat(bundleString, StringContainsInOrder.stringContainsInOrder(strings));
|
||||
|
||||
|
@ -327,24 +328,31 @@ public class XmlParserTest {
|
|||
public void testEncodePrettyPrint() throws DataFormatException {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.getText().getDiv().setValueAsString("<div>\n <i> hello </i>\n</div>");
|
||||
patient.getText().getDiv().setValueAsString("<div>\n <i> hello <pre>\n LINE1\n LINE2</pre></i>\n\n\n\n</div>");
|
||||
patient.addName().addFamily("Family").addGiven("Given");
|
||||
|
||||
//@formatter:off
|
||||
String encoded = new FhirContext().newXmlParser().setPrettyPrint(false).encodeResourceToString(patient);
|
||||
ourLog.info(encoded);
|
||||
String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">\n" +
|
||||
" <i> hello </i>\n" +
|
||||
"</div></text><name><family value=\"Family\"/><given value=\"Given\"/></name></Patient>";
|
||||
/*
|
||||
* Note at least one space is placed where any whitespace was, as
|
||||
* it is hard to tell what whitespace had no purpose
|
||||
*/
|
||||
String expected = "<Patient xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">"
|
||||
+ " <i> hello "
|
||||
+ "<pre>\n LINE1\n LINE2</pre>"
|
||||
+ "</i> </div></text><name><family value=\"Family\"/><given value=\"Given\"/></name></Patient>";
|
||||
assertEquals(expected, encoded);
|
||||
|
||||
encoded = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
|
||||
ourLog.info(encoded);
|
||||
expected = "<Patient xmlns=\"http://hl7.org/fhir\">\n"
|
||||
+ " <text>\n"
|
||||
+ " <div xmlns=\"http://www.w3.org/1999/xhtml\">\n"
|
||||
+ " <i> hello </i>\n"
|
||||
+ "</div>\n"
|
||||
+ " <div xmlns=\"http://www.w3.org/1999/xhtml\"> \n"
|
||||
+ " <i> hello \n"
|
||||
+ " <pre>\n LINE1\n LINE2</pre>\n"
|
||||
+ " </i> \n"
|
||||
+ " </div>\n"
|
||||
+ " </text>\n"
|
||||
+ " <name>\n"
|
||||
+ " <family value=\"Family\"/>\n"
|
||||
|
@ -645,6 +653,7 @@ public class XmlParserTest {
|
|||
assertThat(str, StringContains.containsString("<Patient xmlns=\"http://hl7.org/fhir\">"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testParseBundle() {
|
||||
|
||||
|
@ -664,6 +673,7 @@ public class XmlParserTest {
|
|||
" <title>Valueset "256a5231-a2bb-49bd-9fea-f349d428b70d" to support automated processing</title>\n" +
|
||||
" <id>http://hl7.org/fhir/valueset/256a5231-a2bb-49bd-9fea-f349d428b70d</id>\n" +
|
||||
" <link href=\"http://hl7.org/implement/standards/fhir/valueset/256a5231-a2bb-49bd-9fea-f349d428b70d\" rel=\"self\"/>\n" +
|
||||
" <link href=\"http://hl7.org/foo\" rel=\"alternate\"/>\n" +
|
||||
" <updated>2014-02-10T04:10:46.987-00:00</updated>\n" +
|
||||
" <author>\n" +
|
||||
" <name>HL7, Inc (FHIR Project)</name>\n" +
|
||||
|
@ -718,6 +728,7 @@ public class XmlParserTest {
|
|||
BundleEntry entry = bundle.getEntries().get(0);
|
||||
assertEquals("HL7, Inc (FHIR Project)", entry.getAuthorName().getValue());
|
||||
assertEquals("http://hl7.org/fhir/valueset/256a5231-a2bb-49bd-9fea-f349d428b70d", entry.getId().getValue());
|
||||
assertEquals("http://hl7.org/foo", entry.getLinkAlternate().getValue());
|
||||
assertEquals(1, entry.getCategories().size());
|
||||
assertEquals("term", entry.getCategories().get(0).getTerm());
|
||||
assertEquals("label", entry.getCategories().get(0).getLabel());
|
||||
|
@ -744,6 +755,7 @@ public class XmlParserTest {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testParseBundleDeletedEntry() {
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
|
@ -29,7 +28,6 @@ import ca.uhn.fhir.rest.annotation.RequiredParam;
|
|||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.client.api.IBasicClient;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
public class ReferenceClientTest {
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
|
||||
public class Tester {
|
||||
|
||||
public static final void main(String[] args) throws DataFormatException, IOException {
|
||||
try {
|
||||
|
||||
FhirContext ctx = new FhirContext(Patient.class);
|
||||
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://spark.furore.com/fhir/");
|
||||
|
||||
Patient patient = client.getPatientById(new IdDt("1"));
|
||||
System.out.println(ctx.newXmlParser().encodeResourceToString(patient));
|
||||
|
||||
// Patient patient2 = client.findPatientByMrn(new IdentifierDt("http://orionhealth.com/mrn", "PRP1660"));
|
||||
// System.out.println(ctx.newXmlParser().encodeResourceToString(patient2));
|
||||
|
||||
} catch (NonFhirResponseException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println(e.getResponseBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -507,30 +507,7 @@ public class ResfulServerMethodTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrettyPrint() throws Exception {
|
||||
|
||||
// HttpPost httpPost = new HttpPost("http://localhost:" + ourPort +
|
||||
// "/Patient/1");
|
||||
// httpPost.setEntity(new StringEntity("test",
|
||||
// ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_pretty=false");
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_pretty=true");
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, IsNot.not(StringContains.containsString("<identifier><use")));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadOnTypeThatDoesntSupportRead() throws Exception {
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
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.ServletHolder;
|
||||
import org.junit.After;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
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.Search;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class ServerBaseTest {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerBaseTest.class);
|
||||
private Server myServer;
|
||||
private static FhirContext ourCtx = new FhirContext();
|
||||
|
||||
@Test
|
||||
public void testTransaction() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
if (myServer != null) {
|
||||
myServer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithContextPath() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
myServer = new Server(port);
|
||||
|
||||
DummyProvider patientProvider = new DummyProvider();
|
||||
RestfulServer server = new RestfulServer(ourCtx);
|
||||
server.setProviders(patientProvider);
|
||||
|
||||
org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler();
|
||||
proxyHandler.setContextPath("/ctx");
|
||||
|
||||
ServletHolder handler = new ServletHolder();
|
||||
handler.setServlet(server);
|
||||
proxyHandler.addServlet(handler, "/*");
|
||||
|
||||
myServer.setHandler(proxyHandler);
|
||||
myServer.start();
|
||||
|
||||
// test
|
||||
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + port + "/ctx/Patient?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
BundleEntry entry = bundle.getEntries().get(0);
|
||||
assertEquals("http://localhost:" + port + "/ctx/Patient/123", entry.getId().getValue());
|
||||
assertEquals("http://localhost:" + port + "/ctx/Patient/123/_history/456", entry.getLinkSelf().getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testWithContextAndServletPath() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
myServer = new Server(port);
|
||||
|
||||
DummyProvider patientProvider = new DummyProvider();
|
||||
RestfulServer server = new RestfulServer(ourCtx);
|
||||
server.setProviders(patientProvider);
|
||||
|
||||
org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler();
|
||||
proxyHandler.setContextPath("/ctx");
|
||||
|
||||
ServletHolder handler = new ServletHolder();
|
||||
handler.setServlet(server);
|
||||
proxyHandler.addServlet(handler, "/servlet/*");
|
||||
|
||||
myServer.setHandler(proxyHandler);
|
||||
myServer.start();
|
||||
|
||||
// test
|
||||
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + port + "/ctx/servlet/Patient?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
BundleEntry entry = bundle.getEntries().get(0);
|
||||
assertEquals("http://localhost:" + port + "/ctx/servlet/Patient/123", entry.getId().getValue());
|
||||
assertEquals("http://localhost:" + port + "/ctx/servlet/Patient/123/_history/456", entry.getLinkSelf().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithNoPath() throws Exception {
|
||||
int port = RandomServerPortProvider.findFreePort();
|
||||
myServer = new Server(port);
|
||||
|
||||
DummyProvider patientProvider = new DummyProvider();
|
||||
RestfulServer server = new RestfulServer(ourCtx);
|
||||
server.setProviders(patientProvider);
|
||||
|
||||
org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder handler = new ServletHolder();
|
||||
handler.setServlet(server);
|
||||
proxyHandler.addServlet(handler, "/*");
|
||||
|
||||
myServer.setHandler(proxyHandler);
|
||||
myServer.start();
|
||||
|
||||
// test
|
||||
|
||||
HttpGet httpPost = new HttpGet("http://localhost:" + port + "/Patient?_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent);
|
||||
BundleEntry entry = bundle.getEntries().get(0);
|
||||
assertEquals("http://localhost:" + port + "/Patient/123", entry.getId().getValue());
|
||||
assertEquals("http://localhost:" + port + "/Patient/123/_history/456", entry.getLinkSelf().getValue());
|
||||
}
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyProvider implements IResourceProvider {
|
||||
|
||||
@Search
|
||||
public List<Patient> search() {
|
||||
Patient p = new Patient();
|
||||
p.setId(new IdDt("Patient", "123", "456"));
|
||||
p.addIdentifier("urn:system", "12345");
|
||||
return Collections.singletonList(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
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.HttpGet;
|
||||
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.hamcrest.core.IsNot;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
|
||||
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.testutil.RandomServerPortProvider;
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public class ServerFeaturesTest {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Test
|
||||
public void testPrettyPrint() throws Exception {
|
||||
/*
|
||||
* Not specified
|
||||
*/
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
/*
|
||||
* Disabled
|
||||
*/
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_pretty=false");
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
/*
|
||||
* Enabled
|
||||
*/
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_pretty=true");
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, IsNot.not(StringContains.containsString("<identifier><use")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptHeader() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_FHIR_XML);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_ATOM_XML);
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_FHIR_JSON);
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("\"identifier\":"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptHeaderWithMultiple() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", "text/plain, " + Constants.CT_FHIR_XML);
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", "text/plain, " + Constants.CT_ATOM_XML);
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", "text/plain, " + Constants.CT_FHIR_JSON);
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("\"identifier\":"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptHeaderNonFhirTypes() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_XML);
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier><use"));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_JSON);
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("\"identifier\":"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptHeaderWithPrettyPrint() throws Exception {
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_FHIR_XML+ "; pretty=true");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("<identifier>\n "));
|
||||
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1");
|
||||
httpGet.addHeader("Accept", Constants.CT_FHIR_JSON+ "; pretty=true");
|
||||
status = ourClient.execute(httpGet);
|
||||
responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertThat(responseContent, StringContains.containsString("\",\n"));
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
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();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
public Map<String, Patient> getIdToPatient() {
|
||||
Map<String, Patient> idToPatient = new HashMap<String, Patient>();
|
||||
{
|
||||
Patient patient = createPatient1();
|
||||
idToPatient.put("1", patient);
|
||||
}
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.getIdentifier().add(new IdentifierDt());
|
||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
patient.getIdentifier().get(0).setValue("00002");
|
||||
patient.getName().add(new HumanNameDt());
|
||||
patient.getName().get(0).addFamily("Test");
|
||||
patient.getName().get(0).addGiven("PatientTwo");
|
||||
patient.getGender().setText("F");
|
||||
patient.getId().setValue("2");
|
||||
idToPatient.put("2", patient);
|
||||
}
|
||||
return idToPatient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the resource by its identifier
|
||||
*
|
||||
* @param theId
|
||||
* The resource identity
|
||||
* @return The resource
|
||||
*/
|
||||
@Read()
|
||||
public Patient getResourceById(@IdParam IdDt theId) {
|
||||
return getIdToPatient().get(theId.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
private Patient createPatient1() {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier();
|
||||
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
|
||||
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
|
||||
patient.getIdentifier().get(0).setValue("00001");
|
||||
patient.addName();
|
||||
patient.getName().get(0).addFamily("Test");
|
||||
patient.getName().get(0).addGiven("PatientOne");
|
||||
patient.getGender().setText("M");
|
||||
patient.getId().setValue("1");
|
||||
return patient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,6 @@ 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;
|
||||
|
@ -24,6 +23,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
@ -45,6 +45,7 @@ public class TransactionTest {
|
|||
@Test
|
||||
public void testTransaction() throws Exception {
|
||||
Bundle b = new Bundle();
|
||||
InstantDt nowInstant = InstantDt.withCurrentTime();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().addFamily("Family1");
|
||||
|
@ -60,20 +61,38 @@ public class TransactionTest {
|
|||
|
||||
BundleEntry deletedEntry = b.addEntry();
|
||||
deletedEntry.setId(new IdDt("Patient/3"));
|
||||
deletedEntry.setDeleted(InstantDt.withCurrentTime());
|
||||
deletedEntry.setDeleted(nowInstant);
|
||||
|
||||
String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b);
|
||||
ourLog.info(bundleString);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/");
|
||||
httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true");
|
||||
httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8")));
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
ourLog.info(responseContent);
|
||||
|
||||
Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent);
|
||||
assertEquals(3, bundle.size());
|
||||
|
||||
}
|
||||
BundleEntry entry0 = bundle.getEntries().get(0);
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue());
|
||||
|
||||
BundleEntry entry1 = bundle.getEntries().get(1);
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue());
|
||||
|
||||
BundleEntry entry2 = bundle.getEntries().get(2);
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue());
|
||||
assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue());
|
||||
assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
|
@ -86,15 +105,19 @@ public class TransactionTest {
|
|||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyProvider patientProvider = new DummyProvider();
|
||||
RestfulServer server = new RestfulServer();
|
||||
server.setProviders(patientProvider);
|
||||
|
||||
org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder handler = new ServletHolder();
|
||||
handler.setServlet(server);
|
||||
proxyHandler.addServlet(handler, "/*");
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer();
|
||||
servlet.setProviders(patientProvider);
|
||||
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);
|
||||
|
@ -109,6 +132,15 @@ public class TransactionTest {
|
|||
|
||||
@Transaction
|
||||
public List<IResource> transaction(@TransactionParam List<IResource> theResources) {
|
||||
int index=1;
|
||||
for (IResource next : theResources) {
|
||||
String newId = "8"+Integer.toString(index);
|
||||
if (next.getResourceMetadata().containsKey(ResourceMetadataKeyEnum.DELETED_AT)) {
|
||||
newId = next.getId().getUnqualifiedId();
|
||||
}
|
||||
next.setId(new IdDt("Patient", newId, "9"+Integer.toString(index)));
|
||||
index++;
|
||||
}
|
||||
return theResources;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import ca.uhn.fhir.model.dstu.composite.QuantityDt;
|
|||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
|
||||
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -65,18 +66,19 @@ public abstract class BaseFhirDao {
|
|||
myContext = theContext;
|
||||
}
|
||||
|
||||
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory) {
|
||||
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory) {
|
||||
if (entity.getPublished() == null) {
|
||||
entity.setPublished(new Date());
|
||||
}
|
||||
|
||||
|
||||
if (theUpdateHistory) {
|
||||
final ResourceHistoryTable historyEntry = entity.toHistory(getContext());
|
||||
myEntityManager.persist(historyEntry);
|
||||
}
|
||||
|
||||
entity.setVersion(entity.getVersion()+1);
|
||||
|
||||
|
||||
entity.setVersion(entity.getVersion() + 1);
|
||||
theResource.setId(new IdDt(entity.getResourceType(), entity.getId().toString(), Long.toString(entity.getVersion())));
|
||||
|
||||
final List<ResourceIndexedSearchParamString> stringParams = extractSearchParamStrings(entity, theResource);
|
||||
final List<ResourceIndexedSearchParamToken> tokenParams = extractSearchParamTokens(entity, theResource);
|
||||
final List<ResourceIndexedSearchParamNumber> numberParams = extractSearchParamNumber(entity, theResource);
|
||||
|
@ -86,9 +88,9 @@ public abstract class BaseFhirDao {
|
|||
populateResourceIntoEntity(theResource, entity);
|
||||
|
||||
entity.setUpdated(new Date());
|
||||
|
||||
|
||||
if (entity.getId() == null) {
|
||||
myEntityManager.persist(entity);
|
||||
myEntityManager.persist(entity);
|
||||
} else {
|
||||
entity = myEntityManager.merge(entity);
|
||||
}
|
||||
|
@ -290,8 +292,7 @@ public abstract class BaseFhirDao {
|
|||
|
||||
if (nextObject instanceof QuantityDt) {
|
||||
QuantityDt nextValue = (QuantityDt) nextObject;
|
||||
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue().getValue(), nextValue.getSystem().getValueAsString(),
|
||||
nextValue.getUnits().getValue());
|
||||
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue().getValue(), nextValue.getSystem().getValueAsString(), nextValue.getUnits().getValue());
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
} else {
|
||||
|
@ -374,8 +375,7 @@ public abstract class BaseFhirDao {
|
|||
} else if (nextObject instanceof ContactDt) {
|
||||
ContactDt nextContact = (ContactDt) nextObject;
|
||||
if (nextContact.getValue().isEmpty() == false) {
|
||||
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, normalizeString(nextContact.getValue().getValueAsString()), nextContact
|
||||
.getValue().getValueAsString());
|
||||
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, normalizeString(nextContact.getValue().getValueAsString()), nextContact.getValue().getValueAsString());
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -15,11 +13,6 @@ import org.springframework.transaction.annotation.Propagation;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
|
||||
|
@ -36,7 +29,7 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
|
|||
|
||||
@Transactional(propagation = Propagation.REQUIRED)
|
||||
@Override
|
||||
public List<IResource> transaction(List<IResource> theResources) {
|
||||
public void transaction(List<IResource> theResources) {
|
||||
ourLog.info("Beginning transaction with {} resources", theResources.size());
|
||||
|
||||
FhirTerser terser = myContext.newTerser();
|
||||
|
@ -95,7 +88,6 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
|
|||
updateEntity(resource, table, table.getId() != null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,6 @@ import ca.uhn.fhir.model.api.IResource;
|
|||
|
||||
public interface IFhirSystemDao {
|
||||
|
||||
List<IResource> transaction(List<IResource> theResources);
|
||||
void transaction(List<IResource> theResources);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
|
@ -50,6 +53,7 @@ public abstract class BaseJpaResourceProvider<T extends IResource> implements IR
|
|||
return myDao.search(new HashMap<String, IQueryParameterType>());
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setDao(IFhirResourceDao<T> theDao) {
|
||||
myDao = theDao;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.rest.annotation.Transaction;
|
||||
import ca.uhn.fhir.rest.annotation.TransactionParam;
|
||||
|
||||
public class SystemProvider {
|
||||
|
||||
private IFhirSystemDao myDao;
|
||||
|
||||
@Required
|
||||
public void setDao(IFhirSystemDao theDao) {
|
||||
myDao = theDao;
|
||||
}
|
||||
|
||||
@Transaction
|
||||
public List<IResource> transaction(@TransactionParam List<IResource> theResources) {
|
||||
myDao.transaction(theResources);
|
||||
return theResources;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -46,20 +47,51 @@ public class FhirSystemDaoTest {
|
|||
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
|
||||
obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01"));
|
||||
|
||||
List<IResource> response = ourSystemDao.transaction(Arrays.asList((IResource)patient, obs));
|
||||
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
|
||||
|
||||
long patientId = Long.parseLong(patient.getId().getUnqualifiedId());
|
||||
long patientVersion = Long.parseLong(patient.getId().getUnqualifiedVersionId());
|
||||
long obsId = Long.parseLong(obs.getId().getUnqualifiedId());
|
||||
long obsVersion = Long.parseLong(obs.getId().getUnqualifiedVersionId());
|
||||
|
||||
assertThat(patientId, greaterThan(0L));
|
||||
assertEquals(patientVersion, 1L);
|
||||
assertThat(obsId, greaterThan(patientId));
|
||||
assertEquals(obsVersion, 1L);
|
||||
|
||||
// Try to search
|
||||
|
||||
List<Observation> obsResults = ourObservationDao.search(Observation.SP_NAME, new IdentifierDt("urn:system","testPersistWithSimpleLinkO01"));
|
||||
List<Observation> obsResults = ourObservationDao.search(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01"));
|
||||
assertEquals(1, obsResults.size());
|
||||
|
||||
List<Patient> patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system","testPersistWithSimpleLinkP01"));
|
||||
|
||||
List<Patient> patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01"));
|
||||
assertEquals(1, obsResults.size());
|
||||
|
||||
IdDt patientId = patResults.get(0).getId();
|
||||
|
||||
IdDt foundPatientId = patResults.get(0).getId();
|
||||
ResourceReferenceDt subject = obs.getSubject();
|
||||
assertEquals(patientId.getUnqualifiedId(), subject.getResourceId().getUnqualifiedId());
|
||||
assertEquals(foundPatientId.getUnqualifiedId(), subject.getResourceId().getUnqualifiedId());
|
||||
|
||||
// Update
|
||||
|
||||
patient = patResults.get(0);
|
||||
obs = obsResults.get(0);
|
||||
patient.addIdentifier("urn:system", "testPersistWithSimpleLinkP02");
|
||||
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
|
||||
|
||||
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
|
||||
|
||||
long patientId2 = Long.parseLong(patient.getId().getUnqualifiedId());
|
||||
long patientVersion2 = Long.parseLong(patient.getId().getUnqualifiedVersionId());
|
||||
long obsId2 = Long.parseLong(obs.getId().getUnqualifiedId());
|
||||
long obsVersion2 = Long.parseLong(obs.getId().getUnqualifiedVersionId());
|
||||
|
||||
assertEquals(patientId, patientId2);
|
||||
assertEquals(patientVersion2, 2L);
|
||||
assertEquals(obsId, obsId2);
|
||||
assertEquals(obsVersion2, 2L);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
ourCtx.close();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseJpaResourceProvider;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Questionnaire;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import java.util.*;
|
|||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseJpaResourceProvider;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.api.annotation.*;
|
||||
|
|
Loading…
Reference in New Issue