Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2015-04-20 14:48:18 -04:00
commit dfbfed2d35
12 changed files with 211 additions and 197 deletions

View File

@ -49,13 +49,14 @@ import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonGeneratorFactory;
import javax.json.stream.JsonParsingException;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.primitive.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.IBase;
import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
@ -88,13 +89,12 @@ 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.api.annotation.Child;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.BaseBinary;
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.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
@ -102,10 +102,6 @@ import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.util.UrlUtil;
/**
* This class is the FHIR JSON parser/encoder. Users should not interact with this
* class directly, but should use {@link FhirContext#newJsonParser()} to get an instance.
*/
public class JsonParser extends BaseParser implements IParser {
private static final Set<String> BUNDLE_TEXTNODE_CHILDREN_DSTU1;
@ -302,9 +298,9 @@ public class JsonParser extends BaseParser implements IParser {
// IResource nextResource = nextEntry.getResource();
}
if (nextEntry.getTransactionMethod().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
if (nextEntry.getTransactionOperation().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
theEventWriter.writeStartObject("transaction");
writeOptionalTagWithTextNode(theEventWriter, "method", nextEntry.getTransactionMethod().getValue());
writeOptionalTagWithTextNode(theEventWriter, "operation", nextEntry.getTransactionOperation().getValue());
writeOptionalTagWithTextNode(theEventWriter, "url", nextEntry.getLinkSearch().getValue());
theEventWriter.writeEnd();
}
@ -456,7 +452,7 @@ public class JsonParser extends BaseParser implements IParser {
case RESOURCE:
IBaseResource resource = (IBaseResource) theNextValue;
RuntimeResourceDefinition def = myContext.getResourceDefinition(resource);
encodeResourceToJsonStreamWriter(def, resource, theWriter, theChildName, false);
encodeResourceToJsonStreamWriter(def, resource, theWriter, theChildName, true);
break;
case UNDECL_EXT:
default:
@ -631,12 +627,12 @@ public class JsonParser extends BaseParser implements IParser {
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull,
boolean theContainedResource) throws IOException {
boolean theIsSubElementWithinResource) throws IOException {
String resourceId = null;
if (theResource instanceof IResource) {
IResource res = (IResource) theResource;
if (StringUtils.isNotBlank(res.getId().getIdPart())) {
if (theContainedResource) {
if (theIsSubElementWithinResource) {
resourceId = res.getId().getIdPart();
} else if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
resourceId = res.getId().getIdPart();
@ -644,17 +640,17 @@ public class JsonParser extends BaseParser implements IParser {
}
} else if (theResource instanceof IAnyResource) {
IAnyResource res = (IAnyResource) theResource;
if (theContainedResource && StringUtils.isNotBlank(res.getId())) {
if (theIsSubElementWithinResource && StringUtils.isNotBlank(res.getId())) {
resourceId = res.getId();
}
}
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, resourceId);
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theIsSubElementWithinResource, resourceId);
}
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theObjectNameOrNull,
boolean theContainedResource, String theResourceId) throws IOException {
if (!theContainedResource) {
boolean theIsSubElementWithinResource, String theResourceId) throws IOException {
if (!theIsSubElementWithinResource) {
super.containResourcesForEncoding(theResource);
}
@ -673,64 +669,55 @@ public class JsonParser extends BaseParser implements IParser {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) {
IResource resource = (IResource) theResource;
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
String versionIdPart = resourceId.getVersionIdPart();
if (isBlank(versionIdPart)) {
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
}
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
List<IdDt> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(resource);
if (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, profiles) == false) {
//Object securityLabelRawObj =
List<BaseCodingDt> securityLabels = (List<BaseCodingDt>) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.SECURITY_LABELS);
if (!ElementUtil.isEmpty(resource.getId().getVersionIdPart(), ResourceMetadataKeyEnum.UPDATED.get(resource))
|| (securityLabels != null && !securityLabels.isEmpty())) {
theEventWriter.writeStartObject("meta");
writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart());
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource));
if (profiles != null && profiles.isEmpty()==false) {
theEventWriter.writeStartArray("profile");
for (IdDt profile : profiles) {
if (profile != null && isNotBlank(profile.getValue())) {
theEventWriter.write(profile.getValue());
}
}
theEventWriter.writeEnd();
}
if (securityLabels.isEmpty()==false) {
if (securityLabels != null) {
if (!securityLabels.isEmpty()) {
theEventWriter.writeStartArray("security");
for (BaseCodingDt securityLabel : securityLabels) {
theEventWriter.writeStartObject();
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, def.getChildren(), theContainedResource);
theEventWriter.writeEnd();
}
theEventWriter.writeEnd();
}
if (tags != null && tags.isEmpty()==false) {
theEventWriter.writeStartArray("tag");
for (Tag tag : tags) {
theEventWriter.writeStartObject();
writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme());
writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm());
writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel());
theEventWriter.writeEnd();
UriDt system = securityLabel.getSystemElement();
if (system != null && !system.isEmpty())
writeOptionalTagWithTextNode(theEventWriter, "system", system.getValueAsString());
CodeDt code = securityLabel.getCodeElement();
if (code != null && !code.isEmpty())
writeOptionalTagWithTextNode(theEventWriter, "code", code.getValueAsString());
StringDt display = securityLabel.getDisplayElement();
if (display != null && !display.isEmpty())
writeOptionalTagWithTextNode(theEventWriter, "display", display.getValueAsString());
/*todo: handle version
StringDt version = securityLabel.getVersion();
if (version != null && ! version.isEmpty())
writeOptionalTagWithTextNode(theEventWriter, "version", version.getValueAsString());
*/
theEventWriter.writeEnd(); //end the individual security label
}
theEventWriter.writeEnd(); //end security labels array
}
theEventWriter.writeEnd();
}
theEventWriter.writeEnd(); //end meta
}
}
if (theResource instanceof IBaseBinary) {
IBaseBinary bin = (IBaseBinary) theResource;
if (theResource instanceof BaseBinary) {
BaseBinary bin = (BaseBinary) theResource;
theEventWriter.write("contentType", bin.getContentType());
theEventWriter.write("content", bin.getContentAsBase64());
} else {
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef, theContainedResource);
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef, theIsSubElementWithinResource);
}
theEventWriter.writeEnd();

View File

@ -20,17 +20,17 @@ package ca.uhn.fhir.parser;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.*;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
@ -46,12 +46,13 @@ import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.primitive.*;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBase;
import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
@ -72,32 +73,25 @@ import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
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.ExtensionDt;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
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.base.resource.BaseBinary;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper;
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
import ca.uhn.fhir.util.XmlUtil;
/**
* This class is the FHIR XML parser/encoder. Users should not interact with this
* class directly, but should use {@link FhirContext#newXmlParser()} to get an instance.
*/
public class XmlParser extends BaseParser implements IParser {
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/";
@ -251,12 +245,12 @@ public class XmlParser extends BaseParser implements IParser {
writeTagWithTextNode(eventWriter, "title", theBundle.getTitle());
writeTagWithTextNode(eventWriter, "id", theBundle.getBundleId());
writeAtomLink(eventWriter, Constants.LINK_SELF, theBundle.getLinkSelf());
writeAtomLink(eventWriter, Constants.LINK_FIRST, theBundle.getLinkFirst());
writeAtomLink(eventWriter, Constants.LINK_PREVIOUS, theBundle.getLinkPrevious());
writeAtomLink(eventWriter, Constants.LINK_NEXT, theBundle.getLinkNext());
writeAtomLink(eventWriter, Constants.LINK_LAST, theBundle.getLinkLast());
writeAtomLink(eventWriter, Constants.LINK_FHIR_BASE, theBundle.getLinkBase());
writeAtomLink(eventWriter, "self", theBundle.getLinkSelf());
writeAtomLink(eventWriter, "first", theBundle.getLinkFirst());
writeAtomLink(eventWriter, "previous", theBundle.getLinkPrevious());
writeAtomLink(eventWriter, "next", theBundle.getLinkNext());
writeAtomLink(eventWriter, "last", theBundle.getLinkLast());
writeAtomLink(eventWriter, "fhir-base", theBundle.getLinkBase());
if (theBundle.getTotalResults().getValue() != null) {
eventWriter.writeStartElement("os", "totalResults", OPENSEARCH_NS);
@ -418,9 +412,9 @@ public class XmlParser extends BaseParser implements IParser {
// IResource nextResource = nextEntry.getResource();
}
if (nextEntry.getTransactionMethod().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
if (nextEntry.getTransactionOperation().isEmpty() == false || nextEntry.getLinkSearch().isEmpty() == false) {
theEventWriter.writeStartElement("transaction");
writeOptionalTagWithValue(theEventWriter, "method", nextEntry.getTransactionMethod().getValue());
writeOptionalTagWithValue(theEventWriter, "operation", nextEntry.getTransactionOperation().getValue());
writeOptionalTagWithValue(theEventWriter, "url", nextEntry.getLinkSearch().getValue());
theEventWriter.writeEndElement();
}
@ -739,55 +733,69 @@ public class XmlParser extends BaseParser implements IParser {
// HL7.org Structures
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource);
} else {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
// DSTU2+
IResource resource = (IResource) theResource;
writeOptionalTagWithValue(theEventWriter, "id", theResourceId);
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
//Object securityLabelRawObj = resource.getResourceMetadata().get(ResourceMetadataKeyEnum.SECURITY_LABELS);
List<BaseCodingDt> securityLabels = (List<BaseCodingDt>) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.SECURITY_LABELS);
IdDt resourceId = resource.getId();
if (resourceId != null && isNotBlank(resourceId.getVersionIdPart())
|| (updated != null && !updated.isEmpty())
|| (securityLabels != null && !securityLabels.isEmpty())) {
theEventWriter.writeStartElement("meta");
String versionIdPart = resourceId.getVersionIdPart();
if (isBlank(versionIdPart)) {
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
}
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
List<IdDt> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(resource);
if (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, profiles) == false) {
theEventWriter.writeStartElement("meta");
writeOptionalTagWithValue(theEventWriter, "versionId", versionIdPart);
if (updated != null) {
writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString());
}
for (IdDt profile : profiles) {
theEventWriter.writeStartElement("profile");
theEventWriter.writeAttribute("value", profile.getValue());
theEventWriter.writeEndElement();
}
if (securityLabels != null) {
if (!securityLabels.isEmpty()) {
for (BaseCodingDt securityLabel : securityLabels) {
theEventWriter.writeStartElement("security");
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
encodeCompositeElementChildrenToStreamWriter(resource, securityLabel, theEventWriter, def.getChildren(), theContainedResource);
UriDt system = securityLabel.getSystemElement();
if (system != null && !system.isEmpty())
writeOptionalTagWithValue(theEventWriter, "system", system.getValueAsString());
CodeDt code = securityLabel.getCodeElement();
if (code != null && !code.isEmpty())
writeOptionalTagWithValue(theEventWriter, "code", code.getValueAsString());
StringDt display = securityLabel.getDisplayElement();
if (display != null && !display.isEmpty())
writeOptionalTagWithValue(theEventWriter, "display", display.getValueAsString());
/*todo: handle version
StringDt version = securityLabel.getVersion();
if (version != null && ! version.isEmpty())
writeOptionalTagWithValue(theEventWriter, "version", version.getValueAsString());
*/
theEventWriter.writeEndElement();
}
if (tags != null) {
for (Tag tag : tags) {
theEventWriter.writeStartElement("tag");
writeOptionalTagWithValue(theEventWriter, "system", tag.getScheme());
writeOptionalTagWithValue(theEventWriter, "code", tag.getTerm());
writeOptionalTagWithValue(theEventWriter, "display", tag.getLabel());
theEventWriter.writeEndElement();
}
}
theEventWriter.writeEndElement();
}
if (theResource instanceof IBaseBinary) {
IBaseBinary bin = (IBaseBinary) theResource;
if (theResource instanceof BaseBinary) {
BaseBinary bin = (BaseBinary) theResource;
writeOptionalTagWithValue(theEventWriter, "contentType", bin.getContentType());
writeOptionalTagWithValue(theEventWriter, "content", bin.getContentAsBase64());
} else {
@ -801,8 +809,8 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.writeAttribute("id", theResourceId);
}
if (theResource instanceof IBaseBinary) {
IBaseBinary bin = (IBaseBinary) theResource;
if (theResource instanceof BaseBinary) {
BaseBinary bin = (BaseBinary) theResource;
if (bin.getContentType() != null) {
theEventWriter.writeAttribute("contentType", bin.getContentType());
}

View File

@ -39,9 +39,11 @@
</bean>
</property>
</bean>
<bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEntityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="myTxManager" />
</beans>

View File

@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.ContextLoaderListener;
@ -167,10 +168,15 @@ public class TestRestfulServer extends RestfulServer {
* Do some fancy logging to create a nice access log that has details
* about each incoming request.
*/
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
List<IServerInterceptor> interceptorBeans = myAppCtx.getBean("myServerInterceptors", List.class);
for (IServerInterceptor interceptor : interceptorBeans)
this.registerInterceptor(interceptor);
/*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}]");
this.registerInterceptor(loggingInterceptor);
*/
}

View File

@ -21,4 +21,13 @@
</bean>
<tx:annotation-driven transaction-manager="myTxManager" />
<util:list id="myServerInterceptors">
<ref bean="myLoggingInterceptor"/>
</util:list>
<bean id="myLoggingInterceptor" class="ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor">
<property name="loggerName" value="fhirtest.access"/>
<property name="messageFormat"
value="Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]"/>
</bean>
</beans>

View File

@ -165,8 +165,10 @@
<h4>Search - Using HTTP POST</h4>
<p>
The FHIR specification allows the use of an HTTP POST to transmit a search to a server instead of using
an HTTP GET. With this style of search, the search parameters are included in the request body instead
The FHIR specification allows the use of an HTTP POST to transmit a search to a server instead of
using
an HTTP GET. With this style of search, the search parameters are included in the request body
instead
of the request URL, which can be useful if you need to transmit a search with a large number
of parameters.
</p>