diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java index e7f909fdaaa..2105d49a6e6 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java @@ -28,6 +28,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.text.WordUtils; import org.hl7.fhir.instance.model.IBase; @@ -131,6 +132,23 @@ public class FhirContext { return getLocalizer().getMessage(FhirContext.class, "unknownResourceName", theResourceName, theVersion); } + public Class getCodingDtImplementation() { + FhirVersionEnum myVersionEnum = myVersion.getVersion(); + try { + + if (myVersionEnum.isEquivalentTo(FhirVersionEnum.DSTU2)) { + return (Class) Class.forName("ca.uhn.fhir.model.dstu2.composite.CodingDt"); + } else if (myVersionEnum.isEquivalentTo(FhirVersionEnum.DSTU1)) { + return (Class) Class.forName("ca.uhn.fhir.model.dstu.composite.CodingDt"); + + } else { + throw new IllegalStateException("No implementation found for BaseCodingDt in this FHIR Version." + myVersionEnum.toString()); + } + } catch (ClassNotFoundException e) { + throw new IllegalStateException("No implementation found for BaseCodingDt.", e); + } + } + /** * Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed * for extending the core library. diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java index 0cf0e4389b1..c77128a1ce7 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/ResourceMetadataKeyEnum.java @@ -28,6 +28,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; import org.apache.commons.lang3.StringUtils; import ca.uhn.fhir.model.primitive.DecimalDt; @@ -62,6 +63,36 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; */ public abstract class ResourceMetadataKeyEnum { + public static final ResourceMetadataKeyEnum> SECURITY_LABELS = new ResourceMetadataKeyEnum>("SECURITY_LABELS") { + @Override + public List get(IResource resource) { + Object obj = resource.getResourceMetadata().get(SECURITY_LABELS); + if (obj == null) { + return null; + } else { + try { + List securityLabels = (List) obj; + if (securityLabels.isEmpty()) + return null; + else + return securityLabels; + } catch (ClassCastException e) { + throw new InternalErrorException("Found an object of type '" + obj.getClass().getCanonicalName() + "' in resource metadata for key SECURITY_LABELS - Expected " + + BaseCodingDt.class.getCanonicalName()); + + } + + } + } + + @Override + public void put(IResource iResource, List labels) { + iResource.getResourceMetadata().put(SECURITY_LABELS, labels); + } + + }; + + /** * If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number * of scenarios, such as POSTing transaction bundles to a server, or returning resource history. diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index 7c11fae1054..e3f7b256e12 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -47,6 +47,8 @@ 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; @@ -85,12 +87,6 @@ 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.BooleanDt; -import ca.uhn.fhir.model.primitive.DecimalDt; -import ca.uhn.fhir.model.primitive.IdDt; -import ca.uhn.fhir.model.primitive.IntegerDt; -import ca.uhn.fhir.model.primitive.StringDt; -import ca.uhn.fhir.model.primitive.XhtmlDt; import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.util.ElementUtil; import ca.uhn.fhir.util.UrlUtil; @@ -652,7 +648,41 @@ public class JsonParser extends BaseParser implements IParser { theEventWriter.writeStartObject("meta"); writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart()); writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource)); - theEventWriter.writeEnd(); + + Object securityLabelRawObj = resource.getResourceMetadata().get(ResourceMetadataKeyEnum.SECURITY_LABELS); + if (securityLabelRawObj != null) { + List securityLabels = (List) securityLabelRawObj; + if (!securityLabels.isEmpty()) { + theEventWriter.writeStartArray("security"); + + for (BaseCodingDt securityLabel : securityLabels) { + theEventWriter.writeStartObject(); + + 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(); //end meta } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 1df2a0c1b1b..752e60ba0e9 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -30,13 +30,13 @@ import java.util.Map; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; 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.ICompositeType; import org.hl7.fhir.instance.model.IPrimitiveType; -import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBaseElement; import org.hl7.fhir.instance.model.api.IReference; @@ -48,29 +48,24 @@ import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition; -import ca.uhn.fhir.context.RuntimeElemContainedResources; import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition; import ca.uhn.fhir.context.RuntimePrimitiveDatatypeNarrativeDefinition; import ca.uhn.fhir.context.RuntimeResourceBlockDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition; -import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition; import ca.uhn.fhir.model.api.BaseBundle; 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.ICompositeDatatype; -import ca.uhn.fhir.model.api.ICompositeElement; import ca.uhn.fhir.model.api.IElement; import ca.uhn.fhir.model.api.IFhirVersion; import ca.uhn.fhir.model.api.IIdentifiableElement; import ca.uhn.fhir.model.api.IPrimitiveDatatype; import ca.uhn.fhir.model.api.IResource; -import ca.uhn.fhir.model.api.IResourceBlock; 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.BaseContainedDt; import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; import ca.uhn.fhir.model.base.resource.BaseBinary; import ca.uhn.fhir.model.base.resource.ResourceMetadataMap; @@ -1641,6 +1636,75 @@ class ParserState { } + + private class CodingSubElementState extends BaseState { + BaseCodingDt myCoding; + + String thePartWeAreAt; + + public CodingSubElementState(PreResourceState thePreResourceState, BaseCodingDt codingDt, String whichPartAreWeAt) { + super(thePreResourceState); + myCoding = codingDt; + thePartWeAreAt = whichPartAreWeAt; + } + + @Override + public void endingElement() throws DataFormatException { + pop(); + } + + @Override + public void attributeValue(String theName, String theValue) throws DataFormatException { + if ("value".equals(theName)) { + if ("system".equals(thePartWeAreAt)) + myCoding.setSystem(theValue); + else if ("code".equals(thePartWeAreAt)) + myCoding.setCode(theValue); + else if ("display".equals(thePartWeAreAt)) + myCoding.setDisplay(theValue); + else if ("version".equals(thePartWeAreAt)) { + /* + todo: handle version properly when BaseCodingDt is fixed to support version. For now, we just swallow version in order to avoid throwing a DataFormat exception. + + myCoding.setVersion(theValue); + */ + } else + throw new DataFormatException("Unexpected element '" + theValue + "' found in 'security' element"); + } else { + throw new DataFormatException("Unexpected attribute '" + theName + "' found in '" + thePartWeAreAt + "' element"); + } + } + + @Override + public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException { + throw new DataFormatException("Unexpected element '" + theLocalPart + "' found in 'system' element"); + + } + } + + + private class CodingElementState extends BaseState { + BaseCodingDt myCoding; + + + public CodingElementState(ParserState.PreResourceState thePreResourceState, BaseCodingDt codingDt) { + super(thePreResourceState); + myCoding = codingDt; + } + + @Override + public void endingElement() throws DataFormatException { + pop(); + } + + + @Override + public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException { + push(new CodingSubElementState(getPreResourceState(), myCoding, theLocalPart)); + } + + } + private class MetaElementState extends BaseState { private ResourceMetadataMap myMap; @@ -1664,6 +1728,22 @@ class ParserState { InstantDt updated = new InstantDt(); push(new PrimitiveState(getPreResourceState(), updated)); myMap.put(ResourceMetadataKeyEnum.UPDATED, updated); + } else if (theLocalPart.equals("security")) { + List securityLabels = (List) myMap.get(ResourceMetadataKeyEnum.SECURITY_LABELS); + if (securityLabels == null) { + securityLabels = new ArrayList(); + myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels); + } + BaseCodingDt securityLabel; + try { + securityLabel = myContext.getCodingDtImplementation().newInstance(); + } catch (InstantiationException e) { + throw new DataFormatException("Error parsing element 'security' ", e); + } catch (IllegalAccessException e) { + throw new DataFormatException("Error parsing element 'security' ", e); + } + push(new CodingElementState(getPreResourceState(), securityLabel)); + securityLabels.add(securityLabel); } else { throw new DataFormatException("Unexpected element '" + theLocalPart + "' found in 'meta' element"); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index f3d3fcd4bd6..40800549f0f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -44,6 +44,8 @@ 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; @@ -76,10 +78,6 @@ 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.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.narrative.INarrativeGenerator; import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper; @@ -719,6 +717,38 @@ public class XmlParser extends BaseParser implements IParser { if (updated != null) { writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString()); } + + Object securityLabelRawObj = resource.getResourceMetadata().get(ResourceMetadataKeyEnum.SECURITY_LABELS); + if (securityLabelRawObj != null) { + List securityLabels = (List) securityLabelRawObj; + if (!securityLabels.isEmpty()) { + + for (BaseCodingDt securityLabel : securityLabels) { + theEventWriter.writeStartElement("security"); + + 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(); + } + + } + } + theEventWriter.writeEndElement(); }