Implement DSTU2 transaction semantics in JPA

This commit is contained in:
jamesagnew 2015-02-08 19:21:29 -05:00
parent 1f958221a7
commit 5600ba6763
46 changed files with 12170 additions and 2390 deletions

View File

@ -41,7 +41,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.UrlUtil;
@ -210,9 +211,14 @@ public class Bundle extends BaseBundle /* implements IElement */{
entry.getLinkAlternate().setValue(linkSearch);
}
BundleEntryStatusEnum entryStatus = ResourceMetadataKeyEnum.ENTRY_STATUS.get(theResource);
BundleEntrySearchModeEnum entryStatus = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(theResource);
if (entryStatus != null) {
entry.getStatus().setValueAsEnum(entryStatus);
entry.getSearchMode().setValueAsEnum(entryStatus);
}
BundleEntryTransactionOperationEnum entryTransactionOperation = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(theResource);
if (entryTransactionOperation != null) {
entry.getTransactionOperation().setValueAsEnum(entryTransactionOperation);
}
DecimalDt entryScore = ResourceMetadataKeyEnum.ENTRY_SCORE.get(theResource);

View File

@ -31,7 +31,8 @@ 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;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.util.ElementUtil;
public class BundleEntry extends BaseBundle {
@ -56,7 +57,8 @@ public class BundleEntry extends BaseBundle {
private InstantDt myPublished;
private IResource myResource;
private DecimalDt myScore;
private BoundCodeDt<BundleEntryStatusEnum> myStatus;
private BoundCodeDt<BundleEntrySearchModeEnum> mySearchMode;
private BoundCodeDt<BundleEntryTransactionOperationEnum> myTransactionOperation;
private XhtmlDt mySummary;
private StringDt myTitle;
private InstantDt myUpdated;
@ -197,12 +199,6 @@ public class BundleEntry extends BaseBundle {
return myScore;
}
public BoundCodeDt<BundleEntryStatusEnum> getStatus() {
if (myStatus == null) {
myStatus = new BoundCodeDt<BundleEntryStatusEnum>(BundleEntryStatusEnum.VALUESET_BINDER);
}
return myStatus;
}
public XhtmlDt getSummary() {
if (mySummary == null) {
@ -243,7 +239,7 @@ public class BundleEntry extends BaseBundle {
return super.isEmpty() &&
ElementUtil.isEmpty(
myDeletedResourceId, myDeletedResourceType, myDeletedResourceVersion, myDeletedAt,
myScore, myStatus, myCategories,
myScore, mySearchMode, myTransactionOperation, myCategories,
myLinkAlternate, myLinkSelf, myPublished, myResource, mySummary,
myTitle, myUpdated, myDeletedByEmail, myDeletedByName, myDeletedComment);
//@formatter:on
@ -326,9 +322,6 @@ public class BundleEntry extends BaseBundle {
myScore = theScore;
}
public void setStatus(BoundCodeDt<BundleEntryStatusEnum> theStatus) {
myStatus = theStatus;
}
/**
* @deprecated <b>DSTU2 Note:</b> As of DSTU2, bundle entries no longer have an updated time (this bit of metadata
@ -353,4 +346,29 @@ public class BundleEntry extends BaseBundle {
return b.toString();
}
public BoundCodeDt<BundleEntrySearchModeEnum> getSearchMode() {
if (mySearchMode == null) {
mySearchMode = new BoundCodeDt<BundleEntrySearchModeEnum>(BundleEntrySearchModeEnum.VALUESET_BINDER);
}
return mySearchMode;
}
public void setSearchMode(BoundCodeDt<BundleEntrySearchModeEnum> theSearchMode) {
mySearchMode = theSearchMode;
}
public BoundCodeDt<BundleEntryTransactionOperationEnum> getTransactionOperation() {
if (myTransactionOperation == null) {
myTransactionOperation = new BoundCodeDt<BundleEntryTransactionOperationEnum>(BundleEntryTransactionOperationEnum.VALUESET_BINDER);
}
return myTransactionOperation;
}
public void setTransactionOperation(BoundCodeDt<BundleEntryTransactionOperationEnum> theTransactionOperation) {
myTransactionOperation = theTransactionOperation;
}
}

View File

@ -34,8 +34,8 @@ 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.UriDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/**
@ -294,26 +294,55 @@ public abstract class ResourceMetadataKeyEnum<T> {
};
/**
* If present and populated with a {@link BundleEntryStatusEnum}, contains the "bundle entry status",
* which is the value of the status field in the Bundle.entry containing this resource. This value can be
* If present and populated with a {@link BundleEntrySearchModeEnum}, contains the "bundle entry search mode",
* which is the value of the status field in the Bundle entry containing this resource. The value for this key
* corresponds to field <code>Bundle.entry.search.mode</code>.
* This value can be
* set to provide a status value of "include" for included resources being returned by a server, or to
* set the value on a transaction, etc.
* "match" to indicate that the resource was returned because it matched the given search criteria.
* <p>
* Note that status is only used in FHIR DSTU2 and later.
* </p>
* <p>
* Values for this key are of type <b>{@link BundleEntryStatusEnum}</b>
* Values for this key are of type <b>{@link BundleEntrySearchModeEnum}</b>
* </p>
*/
public static final ResourceMetadataKeyEnum<BundleEntryStatusEnum> ENTRY_STATUS = new ResourceMetadataKeyEnum<BundleEntryStatusEnum>("ENTRY_STATUS") {
public static final ResourceMetadataKeyEnum<BundleEntrySearchModeEnum> ENTRY_SEARCH_MODE = new ResourceMetadataKeyEnum<BundleEntrySearchModeEnum>("ENTRY_SEARCH_MODE") {
@Override
public BundleEntryStatusEnum get(IResource theResource) {
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_STATUS, BundleEntryStatusEnum.class, BundleEntryStatusEnum.VALUESET_BINDER);
public BundleEntrySearchModeEnum get(IResource theResource) {
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_SEARCH_MODE, BundleEntrySearchModeEnum.class, BundleEntrySearchModeEnum.VALUESET_BINDER);
}
@Override
public void put(IResource theResource, BundleEntryStatusEnum theObject) {
theResource.getResourceMetadata().put(ENTRY_STATUS, theObject);
public void put(IResource theResource, BundleEntrySearchModeEnum theObject) {
theResource.getResourceMetadata().put(ENTRY_SEARCH_MODE, theObject);
}
};
/**
* If present and populated with a {@link BundleEntryTransactionOperationEnum}, contains the "bundle entry transaction operation",
* which is the value of the status field in the Bundle entry containing this resource. The value for this key
* corresponds to field <code>Bundle.entry.transaction.operation</code>.
* This value can be
* set in resources being transmitted to a server to provide a status value of "create" or "update" to indicate behaviour the
* server should observe. It may also be set to similar values (or to "noop") in resources being returned by
* a server as a result of a transaction to indicate to the client what operation was actually performed.
* <p>
* Note that status is only used in FHIR DSTU2 and later.
* </p>
* <p>
* Values for this key are of type <b>{@link BundleEntryTransactionOperationEnum}</b>
* </p>
*/
public static final ResourceMetadataKeyEnum<BundleEntryTransactionOperationEnum> ENTRY_TRANSACTION_OPERATION = new ResourceMetadataKeyEnum<BundleEntryTransactionOperationEnum>("ENTRY_TRANSACTION_OPERATION") {
@Override
public BundleEntryTransactionOperationEnum get(IResource theResource) {
return getEnumFromMetadataOrNullIfNone(theResource.getResourceMetadata(), ENTRY_TRANSACTION_OPERATION, BundleEntryTransactionOperationEnum.class, BundleEntryTransactionOperationEnum.VALUESET_BINDER);
}
@Override
public void put(IResource theResource, BundleEntryTransactionOperationEnum theObject) {
theResource.getResourceMetadata().put(ENTRY_TRANSACTION_OPERATION, theObject);
}
};

View File

@ -26,12 +26,10 @@ import java.util.Map;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
public enum BundleEntryStatusEnum {
public enum BundleEntrySearchModeEnum {
CREATE("create", "http://hl7.org/fhir/bundle-entry-status"),
UPDATE("update", "http://hl7.org/fhir/bundle-entry-status"),
MATCH("match", "http://hl7.org/fhir/bundle-entry-status"),
INCLUDE("include", "http://hl7.org/fhir/bundle-entry-status"),
MATCH("match", "http://hl7.org/fhir/search-entry-mode"),
INCLUDE("include", "http://hl7.org/fhir/search-entry-mode"),
;
@ -47,18 +45,18 @@ public enum BundleEntryStatusEnum {
*/
public static final String VALUESET_NAME = "BundleEntryStatus";
private static Map<String, BundleEntryStatusEnum> CODE_TO_ENUM = new HashMap<String, BundleEntryStatusEnum>();
private static Map<String, Map<String, BundleEntryStatusEnum>> SYSTEM_TO_CODE_TO_ENUM = new HashMap<String, Map<String, BundleEntryStatusEnum>>();
private static Map<String, BundleEntrySearchModeEnum> CODE_TO_ENUM = new HashMap<String, BundleEntrySearchModeEnum>();
private static Map<String, Map<String, BundleEntrySearchModeEnum>> SYSTEM_TO_CODE_TO_ENUM = new HashMap<String, Map<String, BundleEntrySearchModeEnum>>();
private final String myCode;
private final String mySystem;
static {
for (BundleEntryStatusEnum next : BundleEntryStatusEnum.values()) {
for (BundleEntrySearchModeEnum next : BundleEntrySearchModeEnum.values()) {
CODE_TO_ENUM.put(next.getCode(), next);
if (!SYSTEM_TO_CODE_TO_ENUM.containsKey(next.getSystem())) {
SYSTEM_TO_CODE_TO_ENUM.put(next.getSystem(), new HashMap<String, BundleEntryStatusEnum>());
SYSTEM_TO_CODE_TO_ENUM.put(next.getSystem(), new HashMap<String, BundleEntrySearchModeEnum>());
}
SYSTEM_TO_CODE_TO_ENUM.get(next.getSystem()).put(next.getCode(), next);
}
@ -81,33 +79,33 @@ public enum BundleEntryStatusEnum {
/**
* Returns the enumerated value associated with this code
*/
public BundleEntryStatusEnum forCode(String theCode) {
BundleEntryStatusEnum retVal = CODE_TO_ENUM.get(theCode);
public BundleEntrySearchModeEnum forCode(String theCode) {
BundleEntrySearchModeEnum retVal = CODE_TO_ENUM.get(theCode);
return retVal;
}
/**
* Converts codes to their respective enumerated values
*/
public static final IValueSetEnumBinder<BundleEntryStatusEnum> VALUESET_BINDER = new IValueSetEnumBinder<BundleEntryStatusEnum>() {
public static final IValueSetEnumBinder<BundleEntrySearchModeEnum> VALUESET_BINDER = new IValueSetEnumBinder<BundleEntrySearchModeEnum>() {
@Override
public String toCodeString(BundleEntryStatusEnum theEnum) {
public String toCodeString(BundleEntrySearchModeEnum theEnum) {
return theEnum.getCode();
}
@Override
public String toSystemString(BundleEntryStatusEnum theEnum) {
public String toSystemString(BundleEntrySearchModeEnum theEnum) {
return theEnum.getSystem();
}
@Override
public BundleEntryStatusEnum fromCodeString(String theCodeString) {
public BundleEntrySearchModeEnum fromCodeString(String theCodeString) {
return CODE_TO_ENUM.get(theCodeString);
}
@Override
public BundleEntryStatusEnum fromCodeString(String theCodeString, String theSystemString) {
Map<String, BundleEntryStatusEnum> map = SYSTEM_TO_CODE_TO_ENUM.get(theSystemString);
public BundleEntrySearchModeEnum fromCodeString(String theCodeString, String theSystemString) {
Map<String, BundleEntrySearchModeEnum> map = SYSTEM_TO_CODE_TO_ENUM.get(theSystemString);
if (map == null) {
return null;
}
@ -119,7 +117,7 @@ public enum BundleEntryStatusEnum {
/**
* Constructor
*/
BundleEntryStatusEnum(String theCode, String theSystem) {
BundleEntrySearchModeEnum(String theCode, String theSystem) {
myCode = theCode;
mySystem = theSystem;
}

View File

@ -0,0 +1,128 @@
package ca.uhn.fhir.model.valueset;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
public enum BundleEntryTransactionOperationEnum {
CREATE("create", "http://hl7.org/fhir/restful-interaction"),
UPDATE("update", "http://hl7.org/fhir/restful-interaction"),
DELETE("delete", "http://hl7.org/fhir/restful-interaction"),
NOOP("noop", "http://hl7.org/fhir/transaction-operation"),
;
/**
* Identifier for this Value Set:
* http://hl7.org/fhir/vs/address-use
*/
public static final String VALUESET_IDENTIFIER = "http://hl7.org/fhir/bundle-entry-status";
/**
* Name for this Value Set:
* AddressUse
*/
public static final String VALUESET_NAME = "BundleEntryStatus";
private static Map<String, BundleEntryTransactionOperationEnum> CODE_TO_ENUM = new HashMap<String, BundleEntryTransactionOperationEnum>();
private static Map<String, Map<String, BundleEntryTransactionOperationEnum>> SYSTEM_TO_CODE_TO_ENUM = new HashMap<String, Map<String, BundleEntryTransactionOperationEnum>>();
private final String myCode;
private final String mySystem;
static {
for (BundleEntryTransactionOperationEnum next : BundleEntryTransactionOperationEnum.values()) {
CODE_TO_ENUM.put(next.getCode(), next);
if (!SYSTEM_TO_CODE_TO_ENUM.containsKey(next.getSystem())) {
SYSTEM_TO_CODE_TO_ENUM.put(next.getSystem(), new HashMap<String, BundleEntryTransactionOperationEnum>());
}
SYSTEM_TO_CODE_TO_ENUM.get(next.getSystem()).put(next.getCode(), next);
}
}
/**
* Returns the code associated with this enumerated value
*/
public String getCode() {
return myCode;
}
/**
* Returns the code system associated with this enumerated value
*/
public String getSystem() {
return mySystem;
}
/**
* Returns the enumerated value associated with this code
*/
public BundleEntryTransactionOperationEnum forCode(String theCode) {
BundleEntryTransactionOperationEnum retVal = CODE_TO_ENUM.get(theCode);
return retVal;
}
/**
* Converts codes to their respective enumerated values
*/
public static final IValueSetEnumBinder<BundleEntryTransactionOperationEnum> VALUESET_BINDER = new IValueSetEnumBinder<BundleEntryTransactionOperationEnum>() {
@Override
public String toCodeString(BundleEntryTransactionOperationEnum theEnum) {
return theEnum.getCode();
}
@Override
public String toSystemString(BundleEntryTransactionOperationEnum theEnum) {
return theEnum.getSystem();
}
@Override
public BundleEntryTransactionOperationEnum fromCodeString(String theCodeString) {
return CODE_TO_ENUM.get(theCodeString);
}
@Override
public BundleEntryTransactionOperationEnum fromCodeString(String theCodeString, String theSystemString) {
Map<String, BundleEntryTransactionOperationEnum> map = SYSTEM_TO_CODE_TO_ENUM.get(theSystemString);
if (map == null) {
return null;
}
return map.get(theCodeString);
}
};
/**
* Constructor
*/
BundleEntryTransactionOperationEnum(String theCode, String theSystem) {
myCode = theCode;
mySystem = theSystem;
}
}

View File

@ -273,9 +273,21 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeStartObject();
writeOptionalTagWithTextNode(theEventWriter, "base", determineResourceBaseUrl(theBundle.getLinkBase().getValue(), nextEntry));
writeOptionalTagWithTextNode(theEventWriter, "status", nextEntry.getStatus());
writeOptionalTagWithTextNode(theEventWriter, "search", nextEntry.getLinkSearch());
writeOptionalTagWithDecimalNode(theEventWriter, "score", nextEntry.getScore());
if (nextEntry.getSearchMode().isEmpty() == false || nextEntry.getScore().isEmpty() == false) {
theEventWriter.writeStartObject("search");
writeOptionalTagWithTextNode(theEventWriter, "mode", nextEntry.getSearchMode().getValueAsString());
writeOptionalTagWithDecimalNode(theEventWriter, "score", nextEntry.getScore());
theEventWriter.writeEnd();
// IResource nextResource = nextEntry.getResource();
}
if (nextEntry.getTransactionOperation().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
theEventWriter.writeStartObject("transaction");
writeOptionalTagWithTextNode(theEventWriter, "operation", nextEntry.getTransactionOperation().getValue());
writeOptionalTagWithTextNode(theEventWriter, "match", nextEntry.getLinkSearch().getValue());
theEventWriter.writeEnd();
}
boolean deleted = nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false;
if (deleted) {

View File

@ -950,10 +950,10 @@ class ParserState<T> {
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
if ("base".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getLinkBase()));
} else if ("status".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getStatus()));
} else if ("transaction".equals(theLocalPart)) {
push(new BundleEntryTransactionState(myEntry));
} else if ("search".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getLinkSearch()));
push(new BundleEntrySearchState(myEntry));
} else if ("score".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getScore()));
} else if ("resource".equals(theLocalPart)) {
@ -1013,16 +1013,74 @@ class ParserState<T> {
if (!myEntry.getLinkSearch().isEmpty()) {
ResourceMetadataKeyEnum.LINK_SEARCH.put(myEntry.getResource(), myEntry.getLinkSearch().getValue());
}
if (!myEntry.getStatus().isEmpty()) {
ResourceMetadataKeyEnum.ENTRY_STATUS.put(myEntry.getResource(), myEntry.getStatus().getValueAsEnum());
if (!myEntry.getSearchMode().isEmpty()) {
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(myEntry.getResource(), myEntry.getSearchMode().getValueAsEnum());
}
if (!myEntry.getStatus().isEmpty()) {
if (!myEntry.getTransactionOperation().isEmpty()) {
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(myEntry.getResource(), myEntry.getTransactionOperation().getValueAsEnum());
}
if (!myEntry.getScore().isEmpty()) {
ResourceMetadataKeyEnum.ENTRY_SCORE.put(myEntry.getResource(), myEntry.getScore());
}
}
}
public class BundleEntrySearchState extends BaseState {
private BundleEntry myEntry;
public BundleEntrySearchState(BundleEntry theEntry) {
super(null);
myEntry = theEntry;
}
@Override
public void endingElement() throws DataFormatException {
pop();
}
@Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
if ("mode".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getSearchMode()));
} else if ("score".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getScore()));
} else {
throw new DataFormatException("Unexpected element in Bundle.entry.search: " + theLocalPart);
}
}
}
public class BundleEntryTransactionState extends BaseState {
private BundleEntry myEntry;
public BundleEntryTransactionState(BundleEntry theEntry) {
super(null);
myEntry = theEntry;
}
@Override
public void endingElement() throws DataFormatException {
pop();
}
@Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
if ("operation".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getTransactionOperation()));
} else if ("match".equals(theLocalPart)) {
push(new PrimitiveState(getPreResourceState(), myEntry.getLinkSearch()));
} else {
throw new DataFormatException("Unexpected element in Bundle.entry.search: " + theLocalPart);
}
}
}
private class BundleLinkState extends BaseState {
private BundleEntry myEntry;

View File

@ -86,12 +86,12 @@ import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
import ca.uhn.fhir.util.XmlUtil;
public class XmlParser extends BaseParser implements IParser {
static final String RESREF_DISPLAY = "display";
static final String RESREF_REFERENCE = "reference";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
static final String ATOM_NS = "http://www.w3.org/2005/Atom";
static final String FHIR_NS = "http://hl7.org/fhir";
static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearch/1.1/";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
static final String RESREF_DISPLAY = "display";
static final String RESREF_REFERENCE = "reference";
static final String TOMBSTONES_NS = "http://purl.org/atompub/tombstones/1.0";
static final String XHTML_NS = "http://www.w3.org/1999/xhtml";
@ -109,6 +109,109 @@ public class XmlParser extends BaseParser implements IParser {
myContext = theContext;
}
private XMLEventReader createStreamReader(Reader theReader) {
try {
return XmlUtil.createXmlReader(theReader);
} catch (FactoryConfigurationError e1) {
throw new ConfigurationException("Failed to initialize STaX event factory", e1);
} catch (XMLStreamException e1) {
throw new DataFormatException(e1);
}
// XMLEventReader streamReader;
// try {
// streamReader = myXmlInputFactory.createXMLEventReader(theReader);
// } catch (XMLStreamException e) {
// throw new DataFormatException(e);
// } catch (FactoryConfigurationError e) {
// throw new ConfigurationException("Failed to initialize STaX event factory", e);
// }
// return streamReader;
}
private XMLStreamWriter createXmlWriter(Writer theWriter) throws XMLStreamException {
XMLStreamWriter eventWriter;
eventWriter = XmlUtil.createXmlStreamWriter(theWriter);
eventWriter = decorateStreamWriter(eventWriter);
return eventWriter;
}
private XMLStreamWriter decorateStreamWriter(XMLStreamWriter eventWriter) {
if (myPrettyPrint) {
PrettyPrintWriterWrapper retVal = new PrettyPrintWriterWrapper(eventWriter);
return retVal;
} else {
NonPrettyPrintWriterWrapper retVal = new NonPrettyPrintWriterWrapper(eventWriter);
return retVal;
}
}
private <T> T doXmlLoop(XMLEventReader streamReader, ParserState<T> parserState) {
ourLog.trace("Entering XML parsing loop with state: {}", parserState);
try {
while (streamReader.hasNext()) {
XMLEvent nextEvent = streamReader.nextEvent();
try {
if (nextEvent.isStartElement()) {
StartElement elem = nextEvent.asStartElement();
String namespaceURI = elem.getName().getNamespaceURI();
if ("extension".equals(elem.getName().getLocalPart())) {
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
if (urlAttr == null || isBlank(urlAttr.getValue())) {
throw new DataFormatException("Extension element has no 'url' attribute");
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), false);
} else if ("modifierExtension".equals(elem.getName().getLocalPart())) {
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
if (urlAttr == null || isBlank(urlAttr.getValue())) {
throw new DataFormatException("Extension element has no 'url' attribute");
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), true);
} else {
String elementName = elem.getName().getLocalPart();
parserState.enteringNewElement(namespaceURI, elementName);
}
for (@SuppressWarnings("unchecked")
Iterator<Attribute> iter = elem.getAttributes(); iter.hasNext();) {
Attribute next = iter.next();
// if
// (next.getName().getLocalPart().equals("value")) {
parserState.attributeValue(next.getName().getLocalPart(), next.getValue());
// }
}
} else if (nextEvent.isAttribute()) {
Attribute elem = (Attribute) nextEvent;
String name = (elem.getName().getLocalPart());
parserState.attributeValue(name, elem.getValue());
} else if (nextEvent.isEndElement()) {
parserState.endingElement();
if (parserState.isComplete()) {
return parserState.getObject();
}
} else if (nextEvent.isCharacters()) {
parserState.string(nextEvent.asCharacters().getData());
}
parserState.xmlEvent(nextEvent);
} catch (DataFormatException e) {
throw new DataFormatException("DataFormatException at [" + nextEvent.getLocation().toString() + "]: " + e.getMessage(), e);
}
}
return null;
} catch (XMLStreamException e) {
throw new DataFormatException(e);
}
}
@Override
public String encodeBundleToString(Bundle theBundle) throws DataFormatException {
StringWriter stringWriter = new StringWriter();
@ -122,16 +225,16 @@ public class XmlParser extends BaseParser implements IParser {
try {
XMLStreamWriter eventWriter = createXmlWriter(theWriter);
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
encodeBundleToWriterUsingBundleResource(theBundle, eventWriter);
encodeBundleToWriterDstu2(theBundle, eventWriter);
} else {
encodeBundleToWriterUsingAtom(theBundle, eventWriter);
encodeBundleToWriterDstu1(theBundle, eventWriter);
}
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
private void encodeBundleToWriterUsingAtom(Bundle theBundle, XMLStreamWriter eventWriter) throws XMLStreamException {
private void encodeBundleToWriterDstu1(Bundle theBundle, XMLStreamWriter eventWriter) throws XMLStreamException {
eventWriter.writeStartElement("feed");
eventWriter.writeDefaultNamespace(ATOM_NS);
@ -250,13 +353,7 @@ public class XmlParser extends BaseParser implements IParser {
eventWriter.close();
}
private void writeOptionalAttribute(XMLStreamWriter theEventWriter, String theName, String theValue) throws XMLStreamException {
if (StringUtils.isNotBlank(theValue)) {
theEventWriter.writeAttribute(theName, theValue);
}
}
private void encodeBundleToWriterUsingBundleResource(Bundle theBundle, XMLStreamWriter theEventWriter) throws XMLStreamException {
private void encodeBundleToWriterDstu2(Bundle theBundle, XMLStreamWriter theEventWriter) throws XMLStreamException {
theEventWriter.writeStartElement("Bundle");
theEventWriter.writeDefaultNamespace(FHIR_NS);
@ -288,12 +385,22 @@ public class XmlParser extends BaseParser implements IParser {
for (BundleEntry nextEntry : theBundle.getEntries()) {
theEventWriter.writeStartElement("entry");
IResource nextResource = nextEntry.getResource();
writeOptionalTagWithValue(theEventWriter, "base", determineResourceBaseUrl(bundleBaseUrl, nextEntry));
writeOptionalTagWithValue(theEventWriter, "status", nextEntry.getStatus().getValue());
writeOptionalTagWithValue(theEventWriter, "search", nextEntry.getLinkSearch().getValue());
writeOptionalTagWithValue(theEventWriter, "score", nextEntry.getScore().getValueAsString());
if (nextEntry.getSearchMode().isEmpty() == false || nextEntry.getScore().isEmpty() == false) {
theEventWriter.writeStartElement("search");
writeOptionalTagWithValue(theEventWriter, "mode", nextEntry.getSearchMode().getValueAsString());
writeOptionalTagWithValue(theEventWriter, "score", nextEntry.getScore().getValueAsString());
theEventWriter.writeEndElement();
// IResource nextResource = nextEntry.getResource();
}
if (nextEntry.getTransactionOperation().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
theEventWriter.writeStartElement("transaction");
writeOptionalTagWithValue(theEventWriter, "operation", nextEntry.getTransactionOperation().getValue());
writeOptionalTagWithValue(theEventWriter, "match", nextEntry.getLinkSearch().getValue());
theEventWriter.writeEndElement();
}
boolean deleted = false;
if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false) {
@ -322,225 +429,6 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.close();
}
private void writeBundleResourceLink(XMLStreamWriter theEventWriter, String theRel, StringDt theUrl) throws XMLStreamException {
if (theUrl.isEmpty() == false) {
theEventWriter.writeStartElement("link");
theEventWriter.writeStartElement("relation");
theEventWriter.writeAttribute("value", theRel);
theEventWriter.writeEndElement();
theEventWriter.writeStartElement("url");
theEventWriter.writeAttribute("value", theUrl.getValue());
theEventWriter.writeEndElement();
theEventWriter.writeEndElement();
}
}
private void writeOptionalTagWithValue(XMLStreamWriter theEventWriter, String theName, String theValue) throws XMLStreamException {
if (StringUtils.isNotBlank(theValue)) {
theEventWriter.writeStartElement(theName);
theEventWriter.writeAttribute("value", theValue);
theEventWriter.writeEndElement();
}
}
private void writeCategories(XMLStreamWriter eventWriter, TagList categories) throws XMLStreamException {
if (categories != null) {
for (Tag next : categories) {
eventWriter.writeStartElement("category");
eventWriter.writeAttribute("term", defaultString(next.getTerm()));
eventWriter.writeAttribute("label", defaultString(next.getLabel()));
eventWriter.writeAttribute("scheme", defaultString(next.getScheme()));
eventWriter.writeEndElement();
}
}
}
@Override
public String encodeResourceToString(IBaseResource theResource) throws DataFormatException {
if (theResource == null) {
throw new NullPointerException("Resource can not be null");
}
Writer stringWriter = new StringWriter();
encodeResourceToWriter(theResource, stringWriter);
return stringWriter.toString();
}
@Override
public void encodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws DataFormatException {
XMLStreamWriter eventWriter;
try {
eventWriter = createXmlWriter(theWriter);
encodeResourceToXmlStreamWriter(theResource, eventWriter, false);
eventWriter.flush();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
private XMLStreamWriter createXmlWriter(Writer theWriter) throws XMLStreamException {
XMLStreamWriter eventWriter;
eventWriter = XmlUtil.createXmlStreamWriter(theWriter);
eventWriter = decorateStreamWriter(eventWriter);
return eventWriter;
}
@Override
public void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException {
try {
XMLStreamWriter eventWriter = createXmlWriter(theWriter);
eventWriter.writeStartElement(TagList.ELEMENT_NAME_LC);
eventWriter.writeDefaultNamespace(FHIR_NS);
for (Tag next : theTagList) {
eventWriter.writeStartElement(TagList.ATTR_CATEGORY);
if (isNotBlank(next.getTerm())) {
eventWriter.writeAttribute(Tag.ATTR_TERM, next.getTerm());
}
if (isNotBlank(next.getLabel())) {
eventWriter.writeAttribute(Tag.ATTR_LABEL, next.getLabel());
}
if (isNotBlank(next.getScheme())) {
eventWriter.writeAttribute(Tag.ATTR_SCHEME, next.getScheme());
}
eventWriter.writeEndElement();
}
eventWriter.writeEndElement();
eventWriter.close();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
@Override
public <T extends IBaseResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
return parseBundle(streamReader, theResourceType);
}
@Override
public <T extends IBaseResource> T parseResource(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
return parseResource(theResourceType, streamReader);
}
@Override
public TagList parseTagList(Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
ParserState<TagList> parserState = ParserState.getPreTagListInstance(myContext, false);
return doXmlLoop(streamReader, parserState);
}
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
return this;
}
private XMLEventReader createStreamReader(Reader theReader) {
try {
return XmlUtil.createXmlReader(theReader);
} catch (FactoryConfigurationError e1) {
throw new ConfigurationException("Failed to initialize STaX event factory", e1);
} catch (XMLStreamException e1) {
throw new DataFormatException(e1);
}
// XMLEventReader streamReader;
// try {
// streamReader = myXmlInputFactory.createXMLEventReader(theReader);
// } catch (XMLStreamException e) {
// throw new DataFormatException(e);
// } catch (FactoryConfigurationError e) {
// throw new ConfigurationException("Failed to initialize STaX event factory", e);
// }
// return streamReader;
}
private XMLStreamWriter decorateStreamWriter(XMLStreamWriter eventWriter) {
if (myPrettyPrint) {
PrettyPrintWriterWrapper retVal = new PrettyPrintWriterWrapper(eventWriter);
return retVal;
} else {
NonPrettyPrintWriterWrapper retVal = new NonPrettyPrintWriterWrapper(eventWriter);
return retVal;
}
}
private <T> T doXmlLoop(XMLEventReader streamReader, ParserState<T> parserState) {
ourLog.trace("Entering XML parsing loop with state: {}", parserState);
try {
while (streamReader.hasNext()) {
XMLEvent nextEvent = streamReader.nextEvent();
try {
if (nextEvent.isStartElement()) {
StartElement elem = nextEvent.asStartElement();
String namespaceURI = elem.getName().getNamespaceURI();
if ("extension".equals(elem.getName().getLocalPart())) {
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
if (urlAttr == null || isBlank(urlAttr.getValue())) {
throw new DataFormatException("Extension element has no 'url' attribute");
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), false);
} else if ("modifierExtension".equals(elem.getName().getLocalPart())) {
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
if (urlAttr == null || isBlank(urlAttr.getValue())) {
throw new DataFormatException("Extension element has no 'url' attribute");
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), true);
} else {
String elementName = elem.getName().getLocalPart();
parserState.enteringNewElement(namespaceURI, elementName);
}
for (@SuppressWarnings("unchecked")
Iterator<Attribute> iter = elem.getAttributes(); iter.hasNext();) {
Attribute next = iter.next();
// if
// (next.getName().getLocalPart().equals("value")) {
parserState.attributeValue(next.getName().getLocalPart(), next.getValue());
// }
}
} else if (nextEvent.isAttribute()) {
Attribute elem = (Attribute) nextEvent;
String name = (elem.getName().getLocalPart());
parserState.attributeValue(name, elem.getValue());
} else if (nextEvent.isEndElement()) {
parserState.endingElement();
if (parserState.isComplete()) {
return parserState.getObject();
}
} else if (nextEvent.isCharacters()) {
parserState.string(nextEvent.asCharacters().getData());
}
parserState.xmlEvent(nextEvent);
} catch (DataFormatException e) {
throw new DataFormatException("DataFormatException at [" + nextEvent.getLocation().toString() + "]: " + e.getMessage(), e);
}
}
return null;
} catch (XMLStreamException e) {
throw new DataFormatException(e);
}
}
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl, boolean theIncludedResource)
throws XMLStreamException, DataFormatException {
if (nextValue.isEmpty()) {
@ -586,16 +474,11 @@ public class XmlParser extends BaseParser implements IParser {
case CONTAINED_RESOURCES: {
ContainedDt value = (ContainedDt) nextValue;
/*
* Disable per #103
for (IResource next : value.getContainedResources()) {
if (getContainedResources().getResourceId(next) != null) {
continue;
}
theEventWriter.writeStartElement("contained");
encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue()));
theEventWriter.writeEndElement();
}
*/
* Disable per #103 for (IResource next : value.getContainedResources()) { if
* (getContainedResources().getResourceId(next) != null) { continue; }
* theEventWriter.writeStartElement("contained"); encodeResourceToXmlStreamWriter(next, theEventWriter,
* true, fixContainedResourceId(next.getId().getValue())); theEventWriter.writeEndElement(); }
*/
for (IBaseResource next : getContainedResources().getContainedResources()) {
IdDt resourceId = getContainedResources().getResourceId(next);
theEventWriter.writeStartElement("contained");
@ -697,6 +580,35 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren(), theIncludedResource);
}
private void encodeExtensionsIfPresent(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredExtensions(), "extension", theIncludedResource);
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredModifierExtensions(), "modifierExtension", theIncludedResource);
}
}
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, ResourceReferenceDt theRef) throws XMLStreamException {
String reference = determineReferenceText(theRef);
if (StringUtils.isNotBlank(reference)) {
theEventWriter.writeStartElement(RESREF_REFERENCE);
theEventWriter.writeAttribute("value", reference);
theEventWriter.writeEndElement();
}
if (!(theRef.getDisplay().isEmpty())) {
theEventWriter.writeStartElement(RESREF_DISPLAY);
theEventWriter.writeAttribute("value", theRef.getDisplay().getValue());
theEventWriter.writeEndElement();
}
}
private void encodeResourceToStreamWriterInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
/*
* DSTU2 requires extensions to come in a specific spot within the encoded content - This is a bit of a messy
@ -724,32 +636,27 @@ public class XmlParser extends BaseParser implements IParser {
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren(), theIncludedResource);
@Override
public String encodeResourceToString(IBaseResource theResource) throws DataFormatException {
if (theResource == null) {
throw new NullPointerException("Resource can not be null");
}
Writer stringWriter = new StringWriter();
encodeResourceToWriter(theResource, stringWriter);
return stringWriter.toString();
}
private void encodeExtensionsIfPresent(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredExtensions(), "extension", theIncludedResource);
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredModifierExtensions(), "modifierExtension", theIncludedResource);
}
}
@Override
public void encodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws DataFormatException {
XMLStreamWriter eventWriter;
try {
eventWriter = createXmlWriter(theWriter);
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, ResourceReferenceDt theRef) throws XMLStreamException {
String reference = determineReferenceText(theRef);
if (StringUtils.isNotBlank(reference)) {
theEventWriter.writeStartElement(RESREF_REFERENCE);
theEventWriter.writeAttribute("value", reference);
theEventWriter.writeEndElement();
}
if (!(theRef.getDisplay().isEmpty())) {
theEventWriter.writeStartElement(RESREF_DISPLAY);
theEventWriter.writeAttribute("value", theRef.getDisplay().getValue());
theEventWriter.writeEndElement();
encodeResourceToXmlStreamWriter(theResource, eventWriter, false);
eventWriter.flush();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
@ -836,6 +743,37 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.writeEndElement();
}
@Override
public void encodeTagListToWriter(TagList theTagList, Writer theWriter) throws IOException {
try {
XMLStreamWriter eventWriter = createXmlWriter(theWriter);
eventWriter.writeStartElement(TagList.ELEMENT_NAME_LC);
eventWriter.writeDefaultNamespace(FHIR_NS);
for (Tag next : theTagList) {
eventWriter.writeStartElement(TagList.ATTR_CATEGORY);
if (isNotBlank(next.getTerm())) {
eventWriter.writeAttribute(Tag.ATTR_TERM, next.getTerm());
}
if (isNotBlank(next.getLabel())) {
eventWriter.writeAttribute(Tag.ATTR_LABEL, next.getLabel());
}
if (isNotBlank(next.getScheme())) {
eventWriter.writeAttribute(Tag.ATTR_SCHEME, next.getScheme());
}
eventWriter.writeEndElement();
}
eventWriter.writeEndElement();
eventWriter.close();
} catch (XMLStreamException e) {
throw new ConfigurationException("Failed to initialize STaX event factory", e);
}
}
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, List<ExtensionDt> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
for (ExtensionDt next : theExtensions) {
theWriter.writeStartElement(tagName);
@ -970,16 +908,44 @@ public class XmlParser extends BaseParser implements IParser {
}
}
@Override
public <T extends IBaseResource> Bundle parseBundle(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
return parseBundle(streamReader, theResourceType);
}
private Bundle parseBundle(XMLEventReader theStreamReader, Class<? extends IBaseResource> theResourceType) {
ParserState<Bundle> parserState = ParserState.getPreAtomInstance(myContext, theResourceType, false);
return doXmlLoop(theStreamReader, parserState);
}
@Override
public <T extends IBaseResource> T parseResource(Class<T> theResourceType, Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
return parseResource(theResourceType, streamReader);
}
private <T extends IBaseResource> T parseResource(Class<T> theResourceType, XMLEventReader theStreamReader) {
ParserState<T> parserState = ParserState.getPreResourceInstance(theResourceType, myContext, false);
return doXmlLoop(theStreamReader, parserState);
}
@Override
public TagList parseTagList(Reader theReader) {
XMLEventReader streamReader = createStreamReader(theReader);
ParserState<TagList> parserState = ParserState.getPreTagListInstance(myContext, false);
return doXmlLoop(streamReader, parserState);
}
@Override
public IParser setPrettyPrint(boolean thePrettyPrint) {
myPrettyPrint = thePrettyPrint;
return this;
}
private void writeAtomLink(XMLStreamWriter theEventWriter, String theRel, StringDt theStringDt) throws XMLStreamException {
if (StringUtils.isNotBlank(theStringDt.getValue())) {
theEventWriter.writeStartElement("link");
@ -989,6 +955,37 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void writeBundleResourceLink(XMLStreamWriter theEventWriter, String theRel, StringDt theUrl) throws XMLStreamException {
if (theUrl.isEmpty() == false) {
theEventWriter.writeStartElement("link");
theEventWriter.writeStartElement("relation");
theEventWriter.writeAttribute("value", theRel);
theEventWriter.writeEndElement();
theEventWriter.writeStartElement("url");
theEventWriter.writeAttribute("value", theUrl.getValue());
theEventWriter.writeEndElement();
theEventWriter.writeEndElement();
}
}
private void writeCategories(XMLStreamWriter eventWriter, TagList categories) throws XMLStreamException {
if (categories != null) {
for (Tag next : categories) {
eventWriter.writeStartElement("category");
eventWriter.writeAttribute("term", defaultString(next.getTerm()));
eventWriter.writeAttribute("label", defaultString(next.getLabel()));
eventWriter.writeAttribute("scheme", defaultString(next.getScheme()));
eventWriter.writeEndElement();
}
}
}
private void writeOptionalAttribute(XMLStreamWriter theEventWriter, String theName, String theValue) throws XMLStreamException {
if (StringUtils.isNotBlank(theValue)) {
theEventWriter.writeAttribute(theName, theValue);
}
}
private void writeOptionalTagWithTextNode(XMLStreamWriter theEventWriter, String theTagName, InstantDt theInstantDt) throws XMLStreamException {
if (theInstantDt.getValue() != null) {
theEventWriter.writeStartElement(theTagName);
@ -1005,6 +1002,14 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void writeOptionalTagWithValue(XMLStreamWriter theEventWriter, String theName, String theValue) throws XMLStreamException {
if (StringUtils.isNotBlank(theValue)) {
theEventWriter.writeStartElement(theName);
theEventWriter.writeAttribute("value", theValue);
theEventWriter.writeEndElement();
}
}
private void writeTagWithTextNode(XMLStreamWriter theEventWriter, String theElementName, IdDt theIdDt) throws XMLStreamException {
theEventWriter.writeStartElement(theElementName);
if (StringUtils.isNotBlank(theIdDt.getValue())) {

View File

@ -27,10 +27,10 @@ import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
interface IParamBinder {
interface IParamBinder<T> {
List<IQueryParameterOr<?>> encode(FhirContext theContext, Object theString) throws InternalErrorException;
Object parse(String theName, List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
T parse(String theName, List<QualifiedParamList> theList) throws InternalErrorException, InvalidRequestException;
}

View File

@ -29,6 +29,8 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
@ -58,7 +60,13 @@ import ca.uhn.fhir.rest.annotation.VersionIdParam;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.CollectionBinder;
import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.param.NumberAndListParam;
import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
@ -455,6 +463,38 @@ public class MethodUtil {
return MethodUtil.findParamAnnotationIndex(theMethod, TagListParam.class);
}
/**
* This is a utility method intended provided to help the JPA module.
*/
public static IQueryParameterAnd<?> parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
QueryParameterAndBinder binder = null;
switch (theParamDef.getParamType()) {
case COMPOSITE:
throw new UnsupportedOperationException();
case DATE:
binder = new QueryParameterAndBinder(DateAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case NUMBER:
binder = new QueryParameterAndBinder(NumberAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case QUANTITY:
binder = new QueryParameterAndBinder(QuantityAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case REFERENCE:
binder = new QueryParameterAndBinder(ReferenceAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case STRING:
binder = new QueryParameterAndBinder(StringAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case TOKEN:
binder = new QueryParameterAndBinder(TokenAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
}
return binder.parse(theUnqualifiedParamName, theParameters);
}
@SuppressWarnings("unchecked")
public static List<IParameter> getResourceParameters(Method theMethod, Object theProvider) {
List<IParameter> parameters = new ArrayList<IParameter>();

View File

@ -29,7 +29,7 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
final class QueryParameterAndBinder extends BaseBinder<IQueryParameterAnd<?>> implements IParamBinder {
final class QueryParameterAndBinder extends BaseBinder<IQueryParameterAnd<?>> implements IParamBinder<IQueryParameterAnd<?>> {
QueryParameterAndBinder(Class<? extends IQueryParameterAnd<?>> theType, List<Class<? extends IQueryParameterType>> theCompositeTypes) {
super(theType, theCompositeTypes);
@ -43,7 +43,7 @@ final class QueryParameterAndBinder extends BaseBinder<IQueryParameterAnd<?>> im
}
@Override
public Object parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
public IQueryParameterAnd<?> parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
IQueryParameterAnd<?> dt;
try {
dt = newInstance();

View File

@ -29,7 +29,7 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> implements IParamBinder {
final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> implements IParamBinder<IQueryParameterOr<?>> {
QueryParameterOrBinder(Class<? extends IQueryParameterOr<?>> theType, List<Class<? extends IQueryParameterType>> theCompositeTypes) {
super(theType, theCompositeTypes);
@ -44,7 +44,7 @@ final class QueryParameterOrBinder extends BaseBinder<IQueryParameterOr<?>> impl
}
@Override
public Object parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
public IQueryParameterOr<?> parse(String theName, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException {
IQueryParameterOr<?> dt;
try {
dt = newInstance();

View File

@ -31,7 +31,7 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> implements IParamBinder {
final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> implements IParamBinder<IQueryParameterType> {
QueryParameterTypeBinder(Class<? extends IQueryParameterType> theType, List<Class<? extends IQueryParameterType>> theCompositeTypes) {
super(theType, theCompositeTypes);
@ -46,7 +46,7 @@ final class QueryParameterTypeBinder extends BaseBinder<IQueryParameterType> imp
}
@Override
public Object parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
public IQueryParameterType parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
String value = theParams.get(0).get(0);
if (StringUtils.isBlank(value)) {
return null;

View File

@ -29,7 +29,7 @@ import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
final class StringBinder implements IParamBinder {
final class StringBinder implements IParamBinder<String> {
StringBinder() {
}
@ -42,7 +42,7 @@ final class StringBinder implements IParamBinder {
}
@Override
public Object parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
public String parse(String theName, List<QualifiedParamList> theParams) throws InternalErrorException, InvalidRequestException {
if (theParams.size() == 0 || theParams.get(0).size() == 0) {
return "";
}

View File

@ -20,43 +20,7 @@ package ca.uhn.fhir.rest.server;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.ProvidedResourceScanner;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.Destroy;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.method.*;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.VersionUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.client.utils.DateUtils;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import static org.apache.commons.lang3.StringUtils.*;
import java.io.IOException;
import java.io.OutputStreamWriter;
@ -67,10 +31,67 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URLEncoder;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.UUID;
import java.util.zip.GZIPOutputStream;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.client.utils.DateUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.ProvidedResourceScanner;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
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.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.Destroy;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.ConformanceMethodBinding;
import ca.uhn.fhir.rest.method.OtherOperationTypeEnum;
import ca.uhn.fhir.rest.method.Request;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.method.SearchMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.VersionUtil;
public class RestfulServer extends HttpServlet {
@ -1202,8 +1223,8 @@ public class RestfulServer extends HttpServlet {
for (IResource next : includedResources) {
BundleEntry entry = bundle.addResource(next, theContext, theServerBase);
if (theContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
if (entry.getStatus().isEmpty()) {
entry.getStatus().setValueAsEnum(BundleEntryStatusEnum.INCLUDE);
if (entry.getSearchMode().isEmpty()) {
entry.getSearchMode().setValueAsEnum(BundleEntrySearchModeEnum.INCLUDE);
}
}
}

View File

@ -63,17 +63,11 @@ public class XmlUtil {
private static volatile boolean ourHaveLoggedStaxImplementation;
private static final Map<String, Integer> VALID_ENTITY_NAMES;
private static final ExtendedEntityReplacingXmlResolver XML_RESOLVER = new ExtendedEntityReplacingXmlResolver();
private static final Attributes.Name IMPLEMENTATION_TITLE = new Attributes.Name("Implementation-Title");
private static final Attributes.Name IMPLEMENTATION_VENDOR = new Attributes.Name("Implementation-Vendor");
private static final Attributes.Name IMPLEMENTATION_VERSION = new Attributes.Name("Implementation-Version");
private static final Attributes.Name BUNDLE_SYMBOLIC_NAME = new Attributes.Name("Bundle-SymbolicName");
private static final Attributes.Name BUNDLE_VENDOR = new Attributes.Name("Bundle-Vendor");
private static final Attributes.Name BUNDLE_VERSION = new Attributes.Name("Bundle-Version");
static {
@ -211,7 +205,7 @@ public class XmlUtil {
* being used (e.g. glassfish) so we don't set them there.
*/
try {
Class.forName("com.ctc.wstx.stax.WstxOutputFactory");
Class.forName("com.ctc.wstx.stax.WstxInputFactory");
if (inputFactory instanceof com.ctc.wstx.stax.WstxInputFactory) {
// inputFactory.setProperty(WstxInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
inputFactory.setProperty(WstxInputProperties.P_UNDECLARED_ENTITY_RESOLVER, XML_RESOLVER);
@ -366,6 +360,7 @@ public class XmlUtil {
case '"':
case '&':
hasEscapable = true;
break;
default:
break;
}

View File

@ -57,11 +57,13 @@ public class ValidationResult {
private String toDescription() {
StringBuilder b = new StringBuilder(100);
if (myOperationOutcome != null) {
if (myOperationOutcome != null && myOperationOutcome.getIssue().size() > 0) {
BaseOperationOutcome.BaseIssue issueFirstRep = myOperationOutcome.getIssueFirstRep();
b.append(issueFirstRep.getDetailsElement().getValue());
b.append(" - ");
b.append(issueFirstRep.getLocationFirstRep().getValue());
}else {
b.append("No issues");
}
return b.toString();
}

View File

@ -1,4 +1,6 @@
# Core Library Messages
ca.uhn.fhir.context.FhirContext.noStructures=Could not find any HAPI-FHIR structure JARs on the classpath. Note that as of HAPI-FHIR v0.8, a separate FHIR strcture JAR must be added to your classpath (or project pom.xml if you are using Maven)
ca.uhn.fhir.context.FhirContext.noStructuresForSpecifiedVersion=Could not find the HAPI-FHIR structure JAR on the classpath for version {0}. Note that as of HAPI-FHIR v0.8, a separate FHIR strcture JAR must be added to your classpath (or project pom.xml if you are using Maven)
@ -10,7 +12,7 @@ ca.uhn.fhir.rest.client.GenericClient.cannotDetermineResourceTypeFromUri=Unable
ca.uhn.fhir.rest.client.RestfulClientFactory.failedToRetrieveConformance=Failed to retrieve the server's metadata statement during client initialization. URL used was: {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.wrongVersionInConformance=The server at base URL "{0}" returned a conformance statement indicating that it supports FHIR version "{1}" which corresponds to {2}, but this client is configured to use {3} (via the FhirContext).
ca.uhn.fhir.rest.method.IncludeParameter.invalidIncludeNameInRequest=Invalid _include parameter value: '{0}'. Valid values are: {1}
ca.uhn.fhir.rest.method.IncludeParameter.invalidIncludeNameInRequest=Invalid _include parameter value: "{0}". Valid values are: {1}
ca.uhn.fhir.rest.method.IncludeParameter.orIncludeInRequest='OR' query parameters (values containing ',') are not supported in _include parameters
ca.uhn.fhir.rest.method.SearchMethodBinding.invalidSpecialParamName=Method [{0}] in provider [{1}] contains search parameter annotated to use name [{2}] - This name is reserved according to the FHIR specification and can not be used as a search parameter name.
@ -19,3 +21,10 @@ ca.uhn.fhir.rest.method.SearchMethodBinding.idNullForCompartmentSearch=ID parame
ca.uhn.fhir.validation.FhirValidator.noPhlocWarningOnStartup=Phloc-schematron library not found on classpath, will not attempt to perform schematron validation
ca.uhn.fhir.validation.FhirValidator.noPhlocError=Phloc-schematron library not found on classpath, can not enable perform schematron validation
# JPA Messages
ca.uhn.fhir.jpa.dao.FhirSystemDao.incomingNoopInTransaction=Transaction contains resource with operation NOOP. This is only valid as a response operation, not in a request.
ca.uhn.fhir.jpa.dao.FhirSystemDao.transactionOperationWithMultipleMatchFailure=Failed to {0} resource with match URL "{1}" because this search matched {2} resources
ca.uhn.fhir.jpa.dao.FhirSystemDao.transactionOperationFailedNoId=Failed to {0} resource in transaction because no ID was provided
ca.uhn.fhir.jpa.dao.FhirSystemDao.transactionOperationFailedUnknownId=Failed to {0} resource in transaction because no resource could be found with ID {1}

View File

@ -27,7 +27,7 @@
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>

View File

@ -7,9 +7,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@ -97,4 +97,4 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.compiler.source=1.7

View File

@ -20,8 +20,7 @@ package ca.uhn.fhir.jpa.dao;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.*;
import java.math.BigDecimal;
import java.util.ArrayList;
@ -96,7 +95,7 @@ import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.CompositeParam;
@ -372,6 +371,15 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
@Override
public BaseHasResource readEntity(IdDt theId) {
boolean checkForForcedId = true;
BaseHasResource entity = readEntity(theId, checkForForcedId);
return entity;
}
@Override
public BaseHasResource readEntity(IdDt theId, boolean theCheckForForcedId) {
validateResourceTypeAndThrowIllegalArgumentException(theId);
Long pid = translateForcedIdToPid(theId);
@ -396,10 +404,12 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
}
}
validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
validateResourceType(entity);
if (theCheckForForcedId) {
validateGivenIdIsAppropriateToRetrieveResource(theId, entity);
}
return entity;
}
@ -508,7 +518,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
// Execute the query and make sure we return distinct results
List<IResource> retVal = new ArrayList<IResource>();
loadResourcesByPid(pidsSubList, retVal, BundleEntryStatusEnum.MATCH);
loadResourcesByPid(pidsSubList, retVal, BundleEntrySearchModeEnum.MATCH);
// Load _include resources
if (theParams.getIncludes() != null && theParams.getIncludes().isEmpty() == false) {
@ -561,7 +571,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
ourLog.info("Loading {} included resources", includePids.size());
resources = loadResourcesById(includePids);
for (IResource next : resources) {
ResourceMetadataKeyEnum.ENTRY_STATUS.put(next, BundleEntryStatusEnum.INCLUDE);
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(next, BundleEntrySearchModeEnum.INCLUDE);
}
retVal.addAll(resources);
}
@ -1441,7 +1451,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
}
private void loadResourcesByPid(Collection<Long> theIncludePids, List<IResource> theResourceListToPopulate, BundleEntryStatusEnum theBundleEntryStatus) {
private void loadResourcesByPid(Collection<Long> theIncludePids, List<IResource> theResourceListToPopulate, BundleEntrySearchModeEnum theBundleEntryStatus) {
if (theIncludePids.isEmpty()) {
return;
}
@ -1469,7 +1479,7 @@ public class FhirResourceDao<T extends IResource> extends BaseFhirDao implements
continue;
}
ResourceMetadataKeyEnum.ENTRY_STATUS.put(resource, theBundleEntryStatus);
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(resource, theBundleEntryStatus);
theResourceListToPopulate.set(index, resource);
}

View File

@ -20,6 +20,8 @@ package ca.uhn.fhir.jpa.dao;
* #L%
*/
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
@ -36,11 +38,19 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.hl7.fhir.instance.model.IBaseResource;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.BaseHasResource;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
@ -49,11 +59,16 @@ import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.FhirTerser;
import com.google.common.collect.ArrayListMultimap;
public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDao.class);
@ -68,15 +83,14 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
Set<IdDt> allIds = new HashSet<IdDt>();
for (int i =0; i <theResources.size();i++) {
for (int i = 0; i < theResources.size(); i++) {
IResource res = theResources.get(i);
if(res.getId().hasIdPart() && !res.getId().hasResourceType()) {
if (res.getId().hasIdPart() && !res.getId().hasResourceType()) {
res.setId(new IdDt(toResourceName(res.getClass()), res.getId().getIdPart()));
}
/*
* Ensure that the bundle doesn't have any duplicates, since this causes all
* kinds of weirdness
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
*/
if (res.getId().hasResourceType() && res.getId().hasIdPart()) {
IdDt nextId = res.getId().toUnqualifiedVersionless();
@ -95,30 +109,89 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
List<ResourceTable> persistedResources = new ArrayList<ResourceTable>();
for (IResource nextResource : theResources) {
List<IResource> retVal = new ArrayList<IResource>();
OperationOutcome oo = new OperationOutcome();
retVal.add(oo);
for (int resourceIdx = 0; resourceIdx < theResources.size(); resourceIdx++) {
IResource nextResource = theResources.get(resourceIdx);
IdDt nextId = nextResource.getId();
if (nextId == null) {
nextId = new IdDt();
}
String resourceName = toResourceName(nextResource);
ResourceTable entity;
if (nextId.isEmpty()) {
entity = null;
} else {
try {
Long pid = translateForcedIdToPid(nextId);
entity = myEntityManager.find(ResourceTable.class, pid);
} catch (ResourceNotFoundException e) {
entity = null;
}
BundleEntryTransactionOperationEnum nextResouceOperationIn = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(nextResource);
if (nextResouceOperationIn == null && hasValue(ResourceMetadataKeyEnum.DELETED_AT.get(nextResource))) {
nextResouceOperationIn = BundleEntryTransactionOperationEnum.DELETE;
}
String matchUrl = ResourceMetadataKeyEnum.LINK_SEARCH.get(nextResource);
Set<Long> candidateMatches = null;
if (StringUtils.isNotBlank(matchUrl)) {
candidateMatches = processMatchUrl(matchUrl, nextResource.getClass());
}
ResourceTable entity;
if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
entity = null;
} else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE || nextResouceOperationIn == BundleEntryTransactionOperationEnum.DELETE) {
if (candidateMatches == null || candidateMatches.size() == 0) {
if (nextId == null || StringUtils.isBlank(nextId.getIdPart())) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDao.class, "transactionOperationFailedNoId", nextResouceOperationIn.name()));
}
entity = tryToLoadEntity(nextId);
if (entity == null) {
if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE) {
ourLog.debug("Attempting to UPDATE resource with unknown ID '{}', will CREATE instead", nextId);
} else if (candidateMatches == null) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDao.class, "transactionOperationFailedUnknownId", nextResouceOperationIn.name(), nextId));
} else {
ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource, BundleEntryTransactionOperationEnum.NOOP);
persistedResources.add(null);
retVal.add(nextResource);
continue;
}
}
} else if (candidateMatches.size() == 1) {
entity = loadFirstEntityFromCandidateMatches(candidateMatches);
} else {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDao.class, "transactionOperationWithMultipleMatchFailure", nextResouceOperationIn.name(), matchUrl, candidateMatches.size()));
}
} else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.NOOP) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDao.class, "incomingNoopInTransaction"));
} else if (nextId.isEmpty()) {
entity = null;
} else {
entity = tryToLoadEntity(nextId);
}
BundleEntryTransactionOperationEnum nextResouceOperationOut;
if (entity == null) {
nextResouceOperationOut = BundleEntryTransactionOperationEnum.CREATE;
entity = toEntity(nextResource);
if (!nextId.isEmpty() && nextId.getIdPart().startsWith("cid:")) {
if (nextId.isEmpty() == false && nextId.getIdPart().startsWith("cid:")) {
ourLog.debug("Resource in transaction has ID[{}], will replace with server assigned ID", nextId.getIdPart());
} else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
if (nextId.isEmpty() == false) {
ourLog.debug("Resource in transaction has ID[{}] but is marked for CREATE, will ignore ID", nextId.getIdPart());
}
if (candidateMatches != null) {
if (candidateMatches.size() == 1) {
ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
BaseHasResource existingEntity = loadFirstEntityFromCandidateMatches(candidateMatches);
IResource existing = (IResource) toResource(existingEntity);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(existing, BundleEntryTransactionOperationEnum.NOOP);
persistedResources.add(null);
retVal.add(existing);
continue;
}
if (candidateMatches.size() > 1) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDao.class, "transactionOperationWithMultipleMatchFailure", BundleEntryTransactionOperationEnum.CREATE.name(), matchUrl, candidateMatches.size()));
}
}
} else {
createForcedIdIfNeeded(entity, nextId);
}
@ -126,16 +199,20 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
if (entity.getForcedId() != null) {
myEntityManager.persist(entity.getForcedId());
}
// myEntityManager.flush();
creations++;
ourLog.info("Resource Type[{}] with ID[{}] does not exist, creating it", resourceName, nextId);
} else {
nextResouceOperationOut = nextResouceOperationIn;
if (nextResouceOperationOut == null) {
nextResouceOperationOut = BundleEntryTransactionOperationEnum.UPDATE;
}
updates++;
ourLog.info("Resource Type[{}] with ID[{}] exists, updating it", resourceName, nextId);
}
persistedResources.add(entity);
retVal.add(nextResource);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource, nextResouceOperationOut);
}
ourLog.info("Flushing transaction to database");
@ -143,14 +220,22 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
for (int i = 0; i < persistedResources.size(); i++) {
ResourceTable entity = persistedResources.get(i);
String resourceName = toResourceName(theResources.get(i));
IdDt nextId = theResources.get(i).getId();
IdDt newId = entity.getIdDt().toUnqualifiedVersionless();
IdDt newId;
if (entity == null) {
newId = retVal.get(i + 1).getId().toUnqualifiedVersionless();
} else {
newId = entity.getIdDt().toUnqualifiedVersionless();
}
if (nextId == null || nextId.isEmpty()) {
ourLog.info("Transaction resource (with no preexisting ID) has been assigned new ID[{}]", nextId, newId);
} else {
if (nextId.toUnqualifiedVersionless().equals(entity.getIdDt().toUnqualifiedVersionless())) {
if (nextId.toUnqualifiedVersionless().equals(newId)) {
ourLog.info("Transaction resource ID[{}] is being updated", newId);
} else {
if (!nextId.getIdPart().startsWith("#")) {
@ -182,26 +267,96 @@ public class FhirSystemDao extends BaseFhirDao implements IFhirSystemDao {
for (int i = 0; i < theResources.size(); i++) {
IResource resource = theResources.get(i);
ResourceTable table = persistedResources.get(i);
if (table == null) {
continue;
}
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(resource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
if (deletedInstantOrNull == null && ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(resource) == BundleEntryTransactionOperationEnum.DELETE) {
deletedTimestampOrNull = new Date();
ResourceMetadataKeyEnum.DELETED_AT.put(resource, new InstantDt(deletedTimestampOrNull));
}
updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull);
}
long delay = System.currentTimeMillis() - start;
ourLog.info("Transaction completed in {}ms with {} creations and {} updates", new Object[] { delay, creations, updates });
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Transaction completed in "+delay+"ms with "+creations+" creations and "+updates+" updates");
ArrayList<IResource> retVal = new ArrayList<IResource>();
retVal.add(oo);
retVal.addAll(theResources);
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Transaction completed in " + delay + "ms with " + creations + " creations and " + updates + " updates");
notifyWriteCompleted();
return retVal;
}
private boolean hasValue(InstantDt theInstantDt) {
return theInstantDt != null && theInstantDt.isEmpty() == false;
}
private ResourceTable tryToLoadEntity(IdDt nextId) {
ResourceTable entity;
try {
Long pid = translateForcedIdToPid(nextId);
entity = myEntityManager.find(ResourceTable.class, pid);
} catch (ResourceNotFoundException e) {
entity = null;
}
return entity;
}
private ResourceTable loadFirstEntityFromCandidateMatches(Set<Long> candidateMatches) {
return myEntityManager.find(ResourceTable.class, candidateMatches.iterator().next());
}
private Set<Long> processMatchUrl(String theMatchUrl, Class<? extends IBaseResource> theResourceType) {
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
SearchParameterMap paramMap = new SearchParameterMap();
List<NameValuePair> parameters;
try {
parameters = URLEncodedUtils.parse(new URI(theMatchUrl), "UTF-8");
} catch (URISyntaxException e) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Error was: " + e.toString());
}
ArrayListMultimap<String, QualifiedParamList> nameToParamLists = ArrayListMultimap.create();
for (NameValuePair next : parameters) {
String paramName = next.getName();
String qualifier = null;
for (int i = 0; i < paramMap.size(); i++) {
switch (paramName.charAt(i)) {
case '.':
case ':':
qualifier = paramName.substring(i);
paramName = paramName.substring(0, i);
i = Integer.MAX_VALUE;
break;
}
}
QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, next.getValue());
nameToParamLists.put(paramName, paramList);
}
for (String nextParamName : nameToParamLists.keySet()) {
RuntimeSearchParam paramDef = resourceDef.getSearchParam(nextParamName);
if (paramDef == null) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
}
List<QualifiedParamList> paramList = nameToParamLists.get(nextParamName);
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(paramDef, nextParamName, paramList);
paramMap.add(nextParamName, param);
}
IFhirResourceDao<? extends IResource> dao = getDao(theResourceType);
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap);
return ids;
}
@Override
public IBundleProvider history(Date theSince) {
StopWatch w = new StopWatch();

View File

@ -79,4 +79,11 @@ public interface IFhirResourceDao<T extends IResource> extends IDao {
Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams);
/**
* @param theCheckForForcedId If true, this method should fail if the requested ID contains
* a numeric PID which exists, but is obscured by a "forced ID" so should not exist as
* far as the outside world is concerned.
*/
BaseHasResource readEntity(IdDt theId, boolean theCheckForForcedId);
}

View File

@ -641,6 +641,7 @@ public class FhirResourceDaoTest {
assertTrue(patients.size() >= 2);
}
@Test
public void testHistoryByForcedId() {
IdDt idv1;
@ -661,6 +662,7 @@ public class FhirResourceDaoTest {
// Newest first
assertEquals("Patient/testHistoryByForcedId/_history/2", patients.get(0).getId().toUnqualified().getValue());
assertEquals("Patient/testHistoryByForcedId/_history/1", patients.get(1).getId().toUnqualified().getValue());
assertNotEquals(idv1, idv2);
}
@Test

View File

@ -1,19 +1,11 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.instrument.UnmodifiableClassException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
@ -33,31 +25,53 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
public class FhirSystemDaoTest {
private static ClassPathXmlApplicationContext ourCtx;
private static FhirContext ourFhirContext;
private static IFhirResourceDao<Location> ourLocationDao;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoTest.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirResourceDao<Device> ourDeviceDao;
private static IFhirResourceDao<DiagnosticReport> ourDiagnosticReportDao;
private static IFhirResourceDao<Organization> ourOrganizationDao;
private static IFhirResourceDao<Location> ourLocationDao;
private static Date ourTestStarted;
private static IFhirSystemDao ourSystemDao;
private static FhirContext ourFhirContext;
@Test
public void testGetResourceCounts() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01");
ourObservationDao.create(obs);
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient);
Map<String, Long> newCounts = ourSystemDao.getResourceCounts();
if (oldCounts.containsKey("Patient")) {
assertEquals(oldCounts.get("Patient") + 1, (long) newCounts.get("Patient"));
} else {
assertEquals(1L, (long) newCounts.get("Patient"));
}
assertEquals((long) oldCounts.get("Observation"), (long) newCounts.get("Observation"));
}
@Test
public void testHistory() throws Exception {
@ -65,7 +79,7 @@ public class FhirSystemDaoTest {
Thread.sleep(10);
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testHistory");
patient.addIdentifier().setSystem("urn:system").setValue("testHistory");
patient.addName().addFamily("Tester").addGiven("Joe");
IdDt pid = ourPatientDao.create(patient).getId().toVersionless();
@ -105,6 +119,84 @@ public class FhirSystemDaoTest {
}
@Test
public void testPersistWithSimpleLink() {
Patient patient = new Patient();
patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01"));
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
patient.addName().addFamily("Tester").addGiven("Joe");
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01"));
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId = (patient.getId().getIdPart());
String obsId = (obs.getId().getIdPart());
// assertThat(patientId, greaterThan(0L));
// assertEquals(patientVersion, 1L);
// assertThat(obsId, greaterThan(patientId));
// assertEquals(obsVersion, 1L);
// Try to search
IBundleProvider obsResults = ourObservationDao.search(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01"));
assertEquals(1, obsResults.size());
IBundleProvider patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01"));
assertEquals(1, obsResults.size());
IdDt foundPatientId = patResults.getResources(0, 1).get(0).getId();
ResourceReferenceDt subject = obs.getSubject();
assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart());
// Update
patient = (Patient) patResults.getResources(0, 1).get(0);
obs = (Observation) obsResults.getResources(0, 1).get(0);
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId2 = (patient.getId().getIdPart());
String patientVersion2 = (patient.getId().getVersionIdPart());
String obsId2 = (obs.getId().getIdPart());
String obsVersion2 = (obs.getId().getVersionIdPart());
assertEquals(patientId, patientId2);
assertEquals(patientVersion2, "2");
assertEquals(obsId, obsId2);
assertEquals(obsVersion2, "2");
}
@Test
public void testPersistWithUnknownId() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/999998888888"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject"));
}
obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject"));
}
}
@Test
public void testTagOperationss() throws Exception {
@ -179,7 +271,465 @@ public class FhirSystemDaoTest {
}
@Test
public void testTransactionWithUpdate() throws Exception {
public void testTransactionCreateMatchUrlWithOneMatch() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.NOOP, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertEquals(id, p.getId());
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
try {
ourSystemDao.transaction(Arrays.asList((IResource) p, o));
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionCreateMatchUrlWithZeroMatch() {
String methodName = "testTransactionCreateMatchUrlWithZeroMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().getIdPart(), not(containsString("test")));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(p.getId().toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionCreateNoMatchUrl() {
String methodName = "testTransactionCreateNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().getIdPart(), not(containsString("test")));
}
@Test
public void testTransactionDeleteMatchUrlWithOneMatch() {
String methodName = "testTransactionDeleteMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
try {
ourPatientDao.read(new IdDt("Patient/" + methodName));
fail();
} catch (ResourceNotFoundException e) {
// ok
}
}
@Test
public void testTransactionDeleteMatchUrlWithTwoMatch() {
String methodName = "testTransactionDeleteMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
try {
ourSystemDao.transaction(Arrays.asList((IResource) p, o));
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionDeleteMatchUrlWithZeroMatch() {
String methodName = "testTransactionDeleteMatchUrlWithZeroMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "ZZZ");
p.addName().addFamily("Hello");
IdDt id = ourPatientDao.create(p).getId();
p = new Patient();
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
IdDt id2 = ourPatientDao.create(p).getId();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), (containsString("test")));
assertThat(p.getId().toString(), endsWith("/_history/2"));
assertEquals(id2.toVersionless(), p.getId().toVersionless());
assertNotEquals(id2, p.getId());
try {
ourPatientDao.read(id2.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
Patient found = ourPatientDao.read(id);
assertEquals(id, found.getId());
}
@Test
public void testTransactionDeleteNoMatchUrl() {
String methodName = "testTransactionDeleteNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(p).getValue());
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
}
@Test(expected = InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() {
Patient patient1 = new Patient();
patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient1.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
Patient patient2 = new Patient();
patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
ourSystemDao.transaction(Arrays.asList((IResource) patient1, patient2));
}
@Test
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = FhirSystemDaoTest.class.getResourceAsStream("/bundle.json");
Bundle bundle = ourFhirContext.newJsonParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourSystemDao.transaction(res);
Patient p1 = (Patient) res.get(0);
String id = p1.getId().getValue();
ourLog.info("ID: {}", id);
assertThat(id, not(containsString("5556918")));
assertThat(id, not(equalToIgnoringCase("")));
}
@Test
public void testTransactionUpdateMatchUrlWithOneMatch() {
String methodName = "testTransactionUpdateMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateMatchUrlWithTwoMatch() {
String methodName = "testTransactionUpdateMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
try {
ourSystemDao.transaction(Arrays.asList((IResource) p, o));
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionUpdateMatchUrlWithZeroMatch() {
String methodName = "testTransactionUpdateMatchUrlWithZeroMatch";
Patient p = new Patient();
p.addName().addFamily("Hello");
IdDt id = ourPatientDao.create(p).getId();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId(id);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference(id);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(p.getId().toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateMatchUrlWithZeroMatchAndNotPreExisting() {
String methodName = "testTransactionUpdateMatchUrlWithZeroMatchAndNotPreExisting";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), containsString("test"));
assertThat(p.getId().toString(), endsWith("/_history/1"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(p.getId().toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateNoMatchUrl() {
String methodName = "testTransactionUpdateNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), containsString("test"));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateNoOperationSpecified() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
@ -196,8 +746,10 @@ public class FhirSystemDaoTest {
ourSystemDao.transaction(res);
assertFalse(p1.getId().isEmpty());
assertNotEquals("testTransactionWithUpdateXXX01", p1.getId().getVersionIdPart());
assertFalse(p2.getId().isEmpty());
assertEquals("testTransactionWithUpdateXXX01", p1.getId().getIdPart());
assertEquals("testTransactionWithUpdateXXX02", p2.getId().getIdPart());
assertNotEquals("testTransactionWithUpdateXXX01", p1.getId().getVersionIdPart());
assertNotEquals("testTransactionWithUpdateXXX02", p2.getId().getVersionIdPart());
assertEquals(p1.getId().toUnqualified().toVersionless(), p2.getSubject().getReference());
@ -206,18 +758,66 @@ public class FhirSystemDaoTest {
IdDt p2id = p2.getId().toUnqualified().toVersionless();
IdDt p2idWithVer = p2.getId().toUnqualified();
p1.addName().addFamily("Name1");
p1.setId(p1.getId().toUnqualified().toVersionless());
/*
* Make some changes
*/
res = new ArrayList<IResource>();
p1 = new Patient();
p1.getId().setValue("testTransactionWithUpdateXXX01");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithUpdate01");
p1.addName().addFamily("Name1");
res.add(p1);
p2 = new Observation();
p2.getId().setValue("testTransactionWithUpdateXXX02");
p2.getIdentifier().setSystem("system").setValue("testTransactionWithUpdate02");
p2.setSubject(new ResourceReferenceDt("Patient/testTransactionWithUpdateXXX01"));
p2.addReferenceRange().setHigh(new QuantityDt(123L));
p2.setId(p2.getId().toUnqualified().toVersionless());
res.add(p2);
List<IResource> results = ourSystemDao.transaction(res);
assertEquals(p1id, results.get(1).getId().toUnqualified().toVersionless());
assertEquals(p2id, results.get(2).getId().toUnqualified().toVersionless());
assertNotEquals(p1idWithVer, results.get(1).getId().toUnqualified());
assertNotEquals(p2idWithVer, results.get(2).getId().toUnqualified());
}
/**
* Issue #55
*/
@Test
public void testTransactionWithCidIds() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
res.add(p1);
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02");
o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o1);
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03");
o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o2);
ourSystemDao.transaction(res);
assertEquals(p1id, p1.getId().toUnqualified().toVersionless());
assertEquals(p2id, p2.getId().toUnqualified().toVersionless());
assertNotEquals(p1idWithVer, p1.getId().toUnqualified());
assertNotEquals(p2idWithVer, p2.getId().toUnqualified());
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
}
@ -282,175 +882,6 @@ public class FhirSystemDaoTest {
}
/**
* Issue #55
*/
@Test
public void testTransactionWithCidIds() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
res.add(p1);
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02");
o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o1);
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03");
o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o2);
ourSystemDao.transaction(res);
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
}
@Test
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = FhirSystemDaoTest.class.getResourceAsStream("/bundle.json");
Bundle bundle = ourFhirContext.newJsonParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourSystemDao.transaction(res);
Patient p1 = (Patient) res.get(0);
String id = p1.getId().getValue();
ourLog.info("ID: {}", id);
assertThat(id, not(containsString("5556918")));
assertThat(id, not(equalToIgnoringCase("")));
}
@Test
public void testPersistWithSimpleLink() {
Patient patient = new Patient();
patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01"));
patient.addIdentifier().setSystem("urn:system").setValue( "testPersistWithSimpleLinkP01");
patient.addName().addFamily("Tester").addGiven("Joe");
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01"));
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId = (patient.getId().getIdPart());
String patientVersion = (patient.getId().getVersionIdPart());
String obsId = (obs.getId().getIdPart());
String obsVersion = (obs.getId().getVersionIdPart());
// assertThat(patientId, greaterThan(0L));
// assertEquals(patientVersion, 1L);
// assertThat(obsId, greaterThan(patientId));
// assertEquals(obsVersion, 1L);
// Try to search
IBundleProvider obsResults = ourObservationDao.search(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01"));
assertEquals(1, obsResults.size());
IBundleProvider patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01"));
assertEquals(1, obsResults.size());
IdDt foundPatientId = patResults.getResources(0, 1).get(0).getId();
ResourceReferenceDt subject = obs.getSubject();
assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart());
// Update
patient = (Patient) patResults.getResources(0,1).get(0);
obs = (Observation) obsResults.getResources(0, 1).get(0);
patient.addIdentifier().setSystem("urn:system").setValue( "testPersistWithSimpleLinkP02");
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId2 = (patient.getId().getIdPart());
String patientVersion2 = (patient.getId().getVersionIdPart());
String obsId2 = (obs.getId().getIdPart());
String obsVersion2 = (obs.getId().getVersionIdPart());
assertEquals(patientId, patientId2);
assertEquals(patientVersion2, "2");
assertEquals(obsId, obsId2);
assertEquals(obsVersion2, "2");
}
@Test(expected=InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() {
Patient patient1 = new Patient();
patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient1.addIdentifier().setSystem("urn:system").setValue( "testPersistWithSimpleLinkP01");
Patient patient2 = new Patient();
patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient2.addIdentifier().setSystem("urn:system").setValue( "testPersistWithSimpleLinkP02");
ourSystemDao.transaction(Arrays.asList((IResource) patient1, patient2));
}
@Test
public void testGetResourceCounts() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01");
ourObservationDao.create(obs);
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient);
Map<String, Long> newCounts = ourSystemDao.getResourceCounts();
if (oldCounts.containsKey("Patient")) {
assertEquals(oldCounts.get("Patient") + 1, (long) newCounts.get("Patient"));
} else {
assertEquals(1L, (long) newCounts.get("Patient"));
}
assertEquals((long) oldCounts.get("Observation"), (long) newCounts.get("Observation"));
}
@Test
public void testPersistWithUnknownId() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/999998888888"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject"));
}
obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject"));
}
}
@AfterClass
public static void afterClass() {
ourCtx.close();
@ -459,14 +890,10 @@ public class FhirSystemDaoTest {
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
ourTestStarted = new Date();
ourCtx = new ClassPathXmlApplicationContext("fhir-jpabase-spring-test-config.xml");
ourFhirContext = ourCtx.getBean(FhirContext.class);
ourPatientDao = ourCtx.getBean("myPatientDao", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDao", IFhirResourceDao.class);
ourDiagnosticReportDao = ourCtx.getBean("myDiagnosticReportDao", IFhirResourceDao.class);
ourDeviceDao = ourCtx.getBean("myDeviceDao", IFhirResourceDao.class);
ourOrganizationDao = ourCtx.getBean("myOrganizationDao", IFhirResourceDao.class);
ourLocationDao = ourCtx.getBean("myLocationDao", IFhirResourceDao.class);
ourSystemDao = ourCtx.getBean("mySystemDao", IFhirSystemDao.class);
}

View File

@ -20,7 +20,6 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
@ -39,7 +38,6 @@ import ca.uhn.fhir.model.dstu.valueset.EncounterClassEnum;
import ca.uhn.fhir.model.dstu.valueset.EncounterStateEnum;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.IGenericClient;
@ -115,11 +113,11 @@ public class ResourceProviderDstu1Test {
assertEquals(2, found.size());
assertEquals(Patient.class, found.getEntries().get(0).getResource().getClass());
assertEquals(null, found.getEntries().get(0).getStatus().getValueAsEnum());
assertEquals(null, found.getEntries().get(0).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS));
assertEquals(null, found.getEntries().get(0).getSearchMode().getValueAsEnum());
assertEquals(null, found.getEntries().get(0).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
assertEquals(Organization.class, found.getEntries().get(1).getResource().getClass());
assertEquals(null, found.getEntries().get(1).getStatus().getValueAsEnum());
assertEquals(null, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS));
assertEquals(null, found.getEntries().get(1).getSearchMode().getValueAsEnum());
assertEquals(null, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
}

View File

@ -20,13 +20,13 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticOrder;
import ca.uhn.fhir.model.dstu2.resource.DocumentManifest;
import ca.uhn.fhir.model.dstu2.resource.DocumentReference;
@ -37,9 +37,8 @@ import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.EncounterClassEnum;
import ca.uhn.fhir.model.dstu2.valueset.EncounterStateEnum;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -143,11 +142,11 @@ public class ResourceProviderDstu2Test {
assertEquals(2, found.size());
assertEquals(Patient.class, found.getEntries().get(0).getResource().getClass());
assertEquals(BundleEntryStatusEnum.MATCH, found.getEntries().get(0).getStatus().getValueAsEnum());
assertEquals(BundleEntryStatusEnum.MATCH, found.getEntries().get(0).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS));
assertEquals(BundleEntrySearchModeEnum.MATCH, found.getEntries().get(0).getSearchMode().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.MATCH, found.getEntries().get(0).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
assertEquals(Organization.class, found.getEntries().get(1).getResource().getClass());
assertEquals(BundleEntryStatusEnum.INCLUDE, found.getEntries().get(1).getStatus().getValueAsEnum());
assertEquals(BundleEntryStatusEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_STATUS));
assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getSearchMode().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.INCLUDE, found.getEntries().get(1).getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE));
}
@ -398,7 +397,7 @@ public class ResourceProviderDstu2Test {
Bundle actual = ourClient.search().forResource(Patient.class).where(Patient.IDENTIFIER.exactly().systemAndCode("urn:system", "testSearchByIdentifier01")).encodedJson().prettyPrint().execute();
assertEquals(1, actual.size());
assertEquals(p1Id.getIdPart(), actual.getEntries().get(0).getResource().getId().getIdPart());
assertEquals(BundleEntryStatusEnum.MATCH, actual.getEntries().get(0).getStatus().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.MATCH, actual.getEntries().get(0).getSearchMode().getValueAsEnum());
}
@Test

View File

@ -27,7 +27,10 @@ public class JpaServerDemo extends RestfulServer {
protected void initialize() throws ServletException {
super.initialize();
// We want to support FHIR DSTU2 format
/*
* We want to support FHIR DSTU2 format. This means that the server
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
*/
setFhirContext(FhirContext.forDstu2());
// Get the spring context from the web container (it's declared in web.xml)
@ -38,14 +41,14 @@ public class JpaServerDemo extends RestfulServer {
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
* contains bean definitions for a resource provider for each resource type
*/
List<IResourceProvider> beans = myAppCtx.getBean("myResourceProvidersDev", List.class);
List<IResourceProvider> beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
setResourceProviders(beans);
/*
* The system provider implements non-resource-type methods, such as
* transaction, and global history.
*/
JpaSystemProvider systemProvider = myAppCtx.getBean("mySystemProviderDev", JpaSystemProvider.class);
JpaSystemProvider systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProvider.class);
setPlainProviders(systemProvider);
/*
@ -59,13 +62,17 @@ public class JpaServerDemo extends RestfulServer {
FhirContext ctx = getFhirContext();
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
/*
* This tells the server to use "incorrect" MIME types if it detects
* that the request is coming from a browser in the hopes that the
* This tells the server to use "browser friendly" MIME types if it
* detects that the request is coming from a browser, in the hopes that the
* browser won't just treat the content as a binary payload and try
* to download it (which is what generally happens if you load a
* FHIR URL in a browser)
* FHIR URL in a browser).
*
* This means that the server isn't technically complying with the
* FHIR specification for direct browser requests, but this mode
* is very helpful for testing and troubleshooting since it means
* you can look at FHIR URLs directly in a browser.
*/
setUseBrowserFriendlyContentTypes(true);
@ -78,8 +85,8 @@ public class JpaServerDemo extends RestfulServer {
* Do some fancy logging to create a nice access log that has details about each incoming request.
*/
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
loggingInterceptor.setLoggerName("fhirtest.access");
loggingInterceptor.setMessageFormat("Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]");
loggingInterceptor.setLoggerName("fhir.access");
loggingInterceptor.setMessageFormat("Path[${servletPath}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]");
this.registerInterceptor(loggingInterceptor);
}

View File

@ -6,8 +6,8 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="target/generated-resources/tinder"/>
<classpathentry kind="src" path="target/generated-sources/tinder"/>
<classpathentry including="**/*.java" kind="src" path="target/generated-resources/tinder"/>
<classpathentry including="**/*.java" kind="src" path="target/generated-sources/tinder"/>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
@ -24,16 +24,16 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -16,12 +16,12 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>

View File

@ -26,7 +26,7 @@ Copyright (c) 2011+, HL7, Inc
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Generated on Thu, Dec 18, 2014 17:00+0000 for FHIR v0.4.0
Generated on Sat, Feb 7, 2015 18:18+0000 for FHIR v0.4.0
-->
<xs:schema xmlns="http://hl7.org/fhir" xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://hl7.org/fhir" elementFormDefault="qualified" version="0.4.0">
<xs:include schemaLocation="alert.xsd"/>
@ -35,6 +35,7 @@ Copyright (c) 2011+, HL7, Inc
<xs:include schemaLocation="appointmentresponse.xsd"/>
<xs:include schemaLocation="basic.xsd"/>
<xs:include schemaLocation="binary.xsd"/>
<xs:include schemaLocation="bodysite.xsd"/>
<xs:include schemaLocation="bundle.xsd"/>
<xs:include schemaLocation="careplan.xsd"/>
<xs:include schemaLocation="careplan2.xsd"/>

View File

@ -26,7 +26,7 @@ Copyright (c) 2011+, HL7, Inc
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Generated on Thu, Dec 18, 2014 17:00+0000 for FHIR v0.4.0
Generated on Thu, Jan 8, 2015 07:22-0500 for FHIR v0.4.0
-->
<xs:schema xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:os="http://a9.com/-/spec/opensearch/1.1/" xmlns:osr="http://a9.com/-/opensearch/extensions/relevance/1.0/"
xmlns:fhir="http://hl7.org/fhir" xmlns:at="http://purl.org/atompub/tombstones/1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" targetNamespace="http://www.w3.org/2005/Atom" elementFormDefault="qualified" attributeFormDefault="unqualified">

View File

@ -26,7 +26,7 @@ Copyright (c) 2011+, HL7, Inc
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
Generated on Thu, Dec 18, 2014 17:00+0000 for FHIR v0.4.0
Generated on Thu, Jan 8, 2015 07:22-0500 for FHIR v0.4.0
-->
<xs:schema xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:os="http://a9.com/-/spec/opensearch/1.1/" xmlns:osr="http://a9.com/-/opensearch/extensions/relevance/1.0/"
xmlns:fhir="http://hl7.org/fhir" xmlns:at="http://purl.org/atompub/tombstones/1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" targetNamespace="http://www.w3.org/2005/Atom" elementFormDefault="qualified" attributeFormDefault="unqualified">

View File

@ -94,9 +94,14 @@ public class JsonParserTest {
" }],\n" +
" \"entry\" : [{\n" +
" \"base\" : \"http://foo/fhirBase2\",\n" +
" \"status\" : \"match\",\n" +
" \"search\" : \"http://foo/Patient?identifier=value\",\n" +
" \"score\" : 0.123,\n" +
" \"search\" : {\n" +
" \"mode\" : \"match\",\n" +
" \"score\" : 0.123\n" +
" },\n" +
" \"transaction\" : {\n" +
" \"operation\" : \"create\",\n" +
" \"match\" : \"http://foo/Patient?identifier=value\"\n" +
" },\n" +
" \"resource\" : {\n" +
" \"resourceType\" : \"Patient\",\n" +
" \"id\" : \"1\",\n" +
@ -117,7 +122,8 @@ public class JsonParserTest {
assertEquals("http://foo/fhirBase2/Patient/1/_history/2", pt.getId().getValue());
assertEquals("2012-01-02", pt.getBirthDateElement().getValueAsString());
assertEquals("0.123", ResourceMetadataKeyEnum.ENTRY_SCORE.get(pt).getValueAsString());
assertEquals("match", ResourceMetadataKeyEnum.ENTRY_STATUS.get(pt).getCode());
assertEquals("match", ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(pt).getCode());
assertEquals("create", ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(pt).getCode());
assertEquals("http://foo/Patient?identifier=value", ResourceMetadataKeyEnum.LINK_SEARCH.get(pt));
assertEquals("2001-02-22T11:22:33-05:00", ResourceMetadataKeyEnum.UPDATED.get(pt).getValueAsString());
@ -165,17 +171,16 @@ public class JsonParserTest {
assertEquals("1", parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION));
assertEquals("1", parsed.getId().getVersionIdPart());
assertEquals(new InstantDt("2014-08-18T01:43:30Z"), parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED));
assertEquals("transaction", parsed.getType().getValue());
assertEquals("searchset", parsed.getType().getValue());
assertEquals(3, parsed.getTotalResults().getValue().intValue());
assertEquals("http://example.com/base", parsed.getLinkBase().getValue());
assertEquals("https://example.com/base/MedicationPrescription?patient=347&searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&page=2", parsed.getLinkNext().getValue());
assertEquals("https://example.com/base/MedicationPrescription?patient=347", parsed.getLinkSelf().getValue());
assertEquals("https://example.com/base/MedicationPrescription?patient=347&_include=MedicationPrescription.medication", parsed.getLinkSelf().getValue());
assertEquals(1, parsed.getEntries().size());
assertEquals("update", parsed.getEntries().get(0).getStatus().getValue());
assertEquals(2, parsed.getEntries().size());
MedicationPrescription p = (MedicationPrescription) parsed.getEntries().get(0).getResource();
assertEquals("Patient/example", p.getPatient().getReference().getValue());
assertEquals("Patient/347", p.getPatient().getReference().getValue());
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());

View File

@ -1,12 +1,7 @@
package ca.uhn.fhir.parser;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.emptyOrNullString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.StringReader;
@ -28,7 +23,6 @@ import ca.uhn.fhir.model.dstu2.resource.MedicationPrescription;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
public class XmlParserTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserTest.class);
@ -62,26 +56,24 @@ public class XmlParserTest {
@Test
public void testParseAndEncodeBundle() throws Exception {
String content = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/bundle-example(example).xml"));
String content = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/bundle-example.xml"));
Bundle parsed = ourCtx.newXmlParser().parseBundle(content);
assertEquals("http://example.com/base/Bundle/example/_history/1", parsed.getId().getValue());
assertEquals("1", parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION));
assertEquals("1", parsed.getId().getVersionIdPart());
assertEquals(new InstantDt("2014-08-18T01:43:30Z"), parsed.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED));
assertEquals("transaction", parsed.getType().getValue());
assertEquals("searchset", parsed.getType().getValue());
assertEquals(3, parsed.getTotalResults().getValue().intValue());
assertEquals("http://example.com/base", parsed.getLinkBase().getValue());
assertEquals("https://example.com/base/MedicationPrescription?patient=347&searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&page=2", parsed.getLinkNext().getValue());
assertEquals("https://example.com/base/MedicationPrescription?patient=347", parsed.getLinkSelf().getValue());
assertEquals("https://example.com/base/MedicationPrescription?patient=347&_include=MedicationPrescription.medication", parsed.getLinkSelf().getValue());
assertEquals(1, parsed.getEntries().size());
assertEquals("update", parsed.getEntries().get(0).getStatus().getValue());
assertEquals(BundleEntryStatusEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_STATUS.get(parsed.getEntries().get(0).getResource()));
assertEquals(2, parsed.getEntries().size());
assertEquals("http://foo?search", parsed.getEntries().get(0).getLinkSearch().getValue());
MedicationPrescription p = (MedicationPrescription) parsed.getEntries().get(0).getResource();
assertEquals("Patient/example", p.getPatient().getReference().getValue());
assertEquals("Patient/347", p.getPatient().getReference().getValue());
assertEquals("2014-08-16T05:31:17Z", ResourceMetadataKeyEnum.UPDATED.get(p).getValueAsString());
assertEquals("http://example.com/base/MedicationPrescription/3123/_history/1", p.getId().getValue());
@ -152,9 +144,14 @@ public class XmlParserTest {
" </link>\n" +
" <entry>\n" +
" <base value=\"http://foo/fhirBase2\"/>\n" +
" <status value=\"match\"/>\n" +
" <search value=\"http://foo/Patient?identifier=value\"/>\n" +
" <score value=\"0.123\"/>\n" +
" <search>\n" +
" <mode value=\"match\"/>\n" +
" <score value=\"0.123\"/>\n" +
" </search>\n" +
" <transaction>\n" +
" <operation value=\"create\"/>\n" +
" <match value=\"http://foo/Patient?identifier=value\"/>\n" +
" </transaction>\n" +
" <resource>\n" +
" <Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <id value=\"1\"/>\n" +
@ -176,7 +173,8 @@ public class XmlParserTest {
assertEquals("http://foo/fhirBase2/Patient/1/_history/2", pt.getId().getValue());
assertEquals("2012-01-02", pt.getBirthDateElement().getValueAsString());
assertEquals("0.123", ResourceMetadataKeyEnum.ENTRY_SCORE.get(pt).getValueAsString());
assertEquals("match", ResourceMetadataKeyEnum.ENTRY_STATUS.get(pt).getCode());
assertEquals("match", ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(pt).getCode());
assertEquals("create", ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(pt).getCode());
assertEquals("http://foo/Patient?identifier=value", ResourceMetadataKeyEnum.LINK_SEARCH.get(pt));
assertEquals("2001-02-22T11:22:33-05:00", ResourceMetadataKeyEnum.UPDATED.get(pt).getValueAsString());

View File

@ -29,8 +29,9 @@ import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.server.Constants;
public class ClientServerValidationTestDev {
public class ClientServerValidationTestDstu2 {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientServerValidationTestDstu2.class);
private FhirContext myCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@ -40,12 +41,12 @@ public class ClientServerValidationTestDev {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
myCtx = FhirContext.forDstu1();
myCtx = FhirContext.forDstu2();
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
}
@Test
public void testServerReturnsAppropriateVersionDev() throws Exception {
public void testServerReturnsAppropriateVersionForDstu2() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.4.0");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
@ -66,9 +67,9 @@ public class ClientServerValidationTestDev {
}
@Test
public void testServerReturnsWrongVersionDev() throws Exception {
public void testServerReturnsWrongVersionForDstu2() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.8.0");
conf.setFhirVersion("0.80");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -84,7 +85,11 @@ public class ClientServerValidationTestDev {
myCtx.newRestfulGenericClient("http://foo");
fail();
} catch (FhirClientConnectionException e) {
assertThat(e.toString(), containsString("The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.4\" which corresponds to DSTU2, but this client is configured to use DSTU1 (at FhirContext creation time)"));
String out = e.toString();
String want = "The server at base URL \"http://foo/metadata\" returned a conformance statement indicating that it supports FHIR version \"0.80\" which corresponds to DSTU1, but this client is configured to use DSTU2 (via the FhirContext)";
ourLog.info(out);
ourLog.info(want);
assertThat(out, containsString(want));
}
}
}

View File

@ -1,8 +1,7 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
@ -40,7 +39,7 @@ import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.valueset.BundleEntryStatusEnum;
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
@ -144,7 +143,7 @@ public class IncludeTest {
assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless());
assertEquals(BundleEntryStatusEnum.INCLUDE, bundle.getEntries().get(2).getStatus().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.INCLUDE, bundle.getEntries().get(2).getSearchMode().getValueAsEnum());
Patient p1 = (Patient) bundle.toListOfResources().get(0);
assertEquals(0, p1.getContained().getContainedResources().size());
@ -170,7 +169,7 @@ public class IncludeTest {
assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless());
assertEquals(BundleEntryStatusEnum.INCLUDE, bundle.getEntries().get(2).getStatus().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.INCLUDE, bundle.getEntries().get(2).getSearchMode().getValueAsEnum());
Patient p1 = (Patient) bundle.toListOfResources().get(0);
assertEquals(0, p1.getContained().getContainedResources().size());
@ -196,7 +195,7 @@ public class IncludeTest {
assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless());
assertEquals(BundleEntryStatusEnum.INCLUDE, bundle.getEntries().get(2).getStatus().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.INCLUDE, bundle.getEntries().get(2).getSearchMode().getValueAsEnum());
Patient p1 = (Patient) bundle.toListOfResources().get(0);
assertEquals(0, p1.getContained().getContainedResources().size());
@ -223,8 +222,8 @@ public class IncludeTest {
assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless());
assertEquals(new IdDt("Organization/o2"), bundle.toListOfResources().get(3).getId().toUnqualifiedVersionless());
assertEquals(BundleEntryStatusEnum.INCLUDE, bundle.getEntries().get(2).getStatus().getValueAsEnum());
assertEquals(BundleEntryStatusEnum.INCLUDE, bundle.getEntries().get(3).getStatus().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.INCLUDE, bundle.getEntries().get(2).getSearchMode().getValueAsEnum());
assertEquals(BundleEntrySearchModeEnum.INCLUDE, bundle.getEntries().get(3).getSearchMode().getValueAsEnum());
Patient p1 = (Patient) bundle.toListOfResources().get(0);
assertEquals(0, p1.getContained().getContainedResources().size());

View File

@ -136,14 +136,15 @@ public class ResourceValidatorTest {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("bundle-example.json"));
Bundle b = ourCtx.newJsonParser().parseBundle(res);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b));
FhirValidator val = createFhirValidator();
ValidationResult result = val.validateWithResult(b);
OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
assertTrue(result.isSuccessful());
assertTrue(result.toString(), result.isSuccessful());
assertNotNull(operationOutcome);
assertEquals(0, operationOutcome.getIssue().size());
}

View File

@ -1,85 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?><Bundle xmlns="http://hl7.org/fhir">
<id value="example"/>
<meta>
<versionId value="1"/>
<lastUpdated value="2014-08-18T01:43:30Z"/>
</meta>
<type value="transaction"/>
<base value="http://example.com/base"/>
<total value="3"/>
<link>
<relation value="next"/>
<url value="https://example.com/base/MedicationPrescription?patient=347&amp;searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&amp;page=2"/>
</link>
<link>
<relation value="self"/>
<url value="https://example.com/base/MedicationPrescription?patient=347"/>
</link>
<entry>
<status value="update"/>
<search value="http://foo?search"/>
<resource>
<MedicationPrescription>
<id value="3123"/>
<meta>
<versionId value="1"/>
<lastUpdated value="2014-08-16T05:31:17Z"/>
</meta>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Penicillin VK 5ml suspension to be administered by oral route</p>
<p>ONE 5ml spoonful to be taken THREE times a day</p>
<p>100ml bottle</p>
<p>to patient ref: a23</p>
<p>by doctor X</p>
</div>
</text>
<status value="active"/>
<patient>
<reference value="Patient/example"/>
</patient>
<prescriber>
<reference value="Practitioner/example"/>
</prescriber>
<medication>
<reference value="Medication/example"/>
</medication>
<dosageInstruction>
<scheduledTiming>
<repeat>
<frequency value="3"/>
<duration value="1"/>
<units value="d"/>
</repeat>
</scheduledTiming>
<route>
<coding>
<system value="http://snomed.info/sct"/>
<code value="394899003"/>
<display value="oral administration of treatment"/>
</coding>
</route>
<doseQuantity>
<value value="5"/>
<units value="ml"/>
<system value="http://unitsofmeasure.org"/>
<code value="ml"/>
</doseQuantity>
</dosageInstruction>
<dispense>
<quantity>
<value value="100"/>
<units value="ml"/>
<system value="http://unitsofmeasure.org"/>
<code value="ml"/>
</quantity>
</dispense>
</MedicationPrescription>
</resource>
</entry>
</Bundle>

View File

@ -5,7 +5,7 @@
"versionId": "1",
"lastUpdated": "2014-08-18T01:43:30Z"
},
"type": "transaction",
"type": "searchset",
"base": "http://example.com/base",
"total": 3,
"link": [
@ -15,68 +15,38 @@
},
{
"relation": "self",
"url": "https://example.com/base/MedicationPrescription?patient=347"
"url": "https://example.com/base/MedicationPrescription?patient=347&_include=MedicationPrescription.medication"
}
],
"entry": [
{
"status": "update",
"search": {
"mode": "match",
"score": 1
},
"resource": {
"resourceType": "MedicationPrescription",
"id": "3123",
"meta": {
"versionId": "1",
"lastUpdated": "2014-08-16T05:31:17Z"
"meta" : {
"versionId" : "1",
"lastUpdated" : "2014-08-16T05:31:17Z"
},
"text": {
"status": "generated",
"div": "<div>\n <p>Penicillin VK 5ml suspension to be administered by oral route</p>\n <p>ONE 5ml spoonful to be taken THREE times a day</p>\n <p>100ml bottle</p>\n <p>to patient ref: a23</p>\n <p>by doctor X</p>\n </div>"
},
"status": "active",
"patient": {
"reference": "Patient/example"
},
"prescriber": {
"reference": "Practitioner/example"
"reference": "Patient/347"
},
"medication": {
"reference": "Medication/example"
},
"dosageInstruction": [
{
"scheduledTiming": {
"repeat": {
"frequency": 3,
"duration": 1,
"units": "d"
}
},
"route": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "394899003",
"display": "oral administration of treatment"
}
]
},
"doseQuantity": {
"value": 5,
"units": "ml",
"system": "http://unitsofmeasure.org",
"code": "ml"
}
}
],
"dispense": {
"quantity": {
"value": 100,
"units": "ml",
"system": "http://unitsofmeasure.org",
"code": "ml"
}
}
}
},
{
"search": {
"mode": "include"
},
"resource": {
"resourceType": "Medication",
"id": "example"
}
}
]
}

View File

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bundle xmlns="http://hl7.org/fhir">
<id value="example"/>
<meta>
<versionId value="1"/>
<lastUpdated value="2014-08-18T01:43:30Z"/>
</meta>
<type value="transaction"/>
<type value="searchset"/>
<base value="http://example.com/base"/>
<total value="3"/>
<link>
@ -14,72 +13,40 @@
</link>
<link>
<relation value="self"/>
<url value="https://example.com/base/MedicationPrescription?patient=347"/>
<url value="https://example.com/base/MedicationPrescription?patient=347&amp;_include=MedicationPrescription.medication"/>
</link>
<entry>
<status value="update"/>
<search>
<mode value="match"/>
<score value="1"/>
</search>
<transaction>
<match value="http://foo?search"/>
</transaction>
<resource>
<MedicationPrescription>
<id value="3123"/>
<meta>
<versionId value="1"/>
<lastUpdated value="2014-08-16T05:31:17Z"/>
<versionId value="1"/>
<lastUpdated value="2014-08-16T05:31:17Z"/>
</meta>
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<p>Penicillin VK 5ml suspension to be administered by oral route</p>
<p>ONE 5ml spoonful to be taken THREE times a day</p>
<p>100ml bottle</p>
<p>to patient ref: a23</p>
<p>by doctor X</p>
</div>
</text>
<status value="active"/>
<patient>
<reference value="Patient/example"/>
<reference value="Patient/347"/>
</patient>
<prescriber>
<reference value="Practitioner/example"/>
</prescriber>
<medication>
<reference value="Medication/example"/>
</medication>
<dosageInstruction>
<scheduledTiming>
<repeat>
<frequency value="3"/>
<duration value="1"/>
<units value="d"/>
</repeat>
</scheduledTiming>
<route>
<coding>
<system value="http://snomed.info/sct"/>
<code value="394899003"/>
<display value="oral administration of treatment"/>
</coding>
</route>
<doseQuantity>
<value value="5"/>
<units value="ml"/>
<system value="http://unitsofmeasure.org"/>
<code value="ml"/>
</doseQuantity>
</dosageInstruction>
<dispense>
<quantity>
<value value="100"/>
<units value="ml"/>
<system value="http://unitsofmeasure.org"/>
<code value="ml"/>
</quantity>
</dispense>
</MedicationPrescription>
</resource>
</entry>
<entry>
<search>
<mode value="include"/>
</search>
<resource>
<Medication>
<id value="example"/>
</Medication>
</resource>
</entry>
</Bundle>

35
pom.xml
View File

@ -601,22 +601,6 @@
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<classFilesDirectory>./hapi-fhir-base/target/classes</classFilesDirectory>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>findbugs</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId>
<version>1.1</version> </plugin> -->
</plugins>
@ -687,6 +671,25 @@
<module>hapi-fhir-jpaserver-base</module>
<module>examples</module>
</modules>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<classFilesDirectory>./hapi-fhir-base/target/classes</classFilesDirectory>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>findbugs</report>
</reports>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
</profile>
<profile>
<id>ALLMODULES</id>

View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project xmlns="http://maven.apache.org/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd" name="HAPI">
<bannerLeft>
<name>HAPI</name>
<src>images/hapi_fhir_banner.png</src>
<href>http://jamesagnew.github.io/hapi-fhir/</href>
</bannerLeft>
<bannerRight>
<name>FHIR</name>
<src>images/hapi_fhir_banner_right.png</src>
<href>http://jamesagnew.github.io/hapi-fhir/</href>
</bannerRight>
<poweredBy>
<logo name="Hosted on GitHub" href="https://github.com/jamesagnew/hapi-fhir" img="./images/github-logo-mini.png"/>
<logo name="Built with Maven 3" href="http://maven.apache.org" img="./images/maven-logo-mini.png" />
</poweredBy>
<version position="left" />
<body>
<head>
<!-- Syntax Highlighter -->
<script type="text/javascript" src="syntaxhighlighter/shCore.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJScript.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJava.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushBash.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushXml.js"></script>
<link href="syntaxhighlighter/shCore.css" rel="stylesheet" type="text/css" />
<link href="syntaxhighlighter/shThemeDefault.css" rel="stylesheet" type="text/css" />
<!--
HAPI stylesheet comes after because it overwrites the Syntax Highlighter
font size
-->
<link rel="shortcut icon" href="https://github.com/jamesagnew/hapi-fhir/images/favicon.png" />
<link rel="stylesheet" type="text/css" href="hapi.css" />
</head>
<links>
<item name="GitHub Page" href="https://github.com/jamesagnew/hapi-fhir/" />
<item name="hl7.org" href="http://hl7.org/" />
<item name="University Health Network" href="http://www.uhn.ca/" />
</links>
<menu name="Welcome">
<item name="Welcome" href="index.html" />
<item name="Download" href="./download.html" />
<item name="Upgrade Guide" href="./doc_upgrading.html" />
<item name="Changelog" href="./changes-report.html" />
</menu>
<menu name="Test Server">
<item name="Public Test Server" href="http://fhirtest.uhn.ca"/>
<item name="Vagrant (Private) Test Server" href="doc_vagrant.html"/>
</menu>
<menu name="Documentation">
<item name="Introduction" href="./doc_intro.html" />
<item name="The Data Model" href="./doc_fhirobjects.html">
<item name="Profiles &amp; Extensions" href="./doc_extensions.html" />
<item name="Resource References" href="./doc_resource_references.html" />
<item name="Tags" href="./doc_tags.html" />
<item name="Validation" href="./doc_validation.html" />
</item>
<item name="RESTful Client" href="./doc_rest_client.html" >
<item name="Interceptors (client)" href="./doc_rest_client_interceptor.html"/>
</item>
<item name="RESTful Server" href="./doc_rest_server.html" >
<item name="RESTful Operations" href="./doc_rest_operations.html" />
<item name="Narrative Generator" href="./doc_narrative.html" />
<item name="CORS Support" href="./doc_cors.html" />
<item name="Interceptors (server)" href="./doc_rest_server_interceptor.html" />
<item name="Web Testing UI" href="./doc_server_tester.html" />
</item>
<item name="Logging" href="./doc_logging.html" />
<item name="Tinder Plugin" href="./doc_tinder.html" />
</menu>
<menu name="Community">
<item name="Google Group" href="https://groups.google.com/d/forum/hapi-fhir" />
<item name="Issue Tracker" href="https://github.com/jamesagnew/hapi-fhir/issues" />
</menu>
<menu name="JavaDocs">
<<<<<<< HEAD:src/site/site.xml
<item name="API (Core)" href="./apidocs/index.html" />
<item name="API (DSTU Model)" href="./apidocs-dstu/index.html" />
<item name="API (DEV Model)" href="./apidocs-dev/index.html" />
=======
<item name="Core API" href="./apidocs/index.html" />
<item name="Model API (DSTU1)" href="./apidocs-dstu/index.html" />
<item name="Model API (DEV)" href="./apidocs-dev/index.html" />
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:src/site/site.xml
<item name="Source Code" href=".https://github.com/jamesagnew/hapi-fhir" />
</menu>
<menu name="Reports">
<item name="Developers" href="team-list.html" />
<item name="Unit Test Report" href="surefire-report.html" />
<item name="FindBugs" href="findbugs.html" />
<item name="License" href="license.html" />
<item name="Source Code" href="https://github.com/jamesagnew/hapi-fhir" />
</menu>
</body>
<skin>
<groupId>org.apache.maven.skins</groupId>
<artifactId>maven-fluido-skin</artifactId>
<version>1.3.1</version>
</skin>
<custom>
<fluidoSkin>
<googleSearch />
<!-- <sourceLineNumbersEnabled>true</sourceLineNumbersEnabled> -->
</fluidoSkin>
</custom>
</project>