commit
d3ef577418
|
@ -69,6 +69,11 @@
|
|||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jena</groupId>
|
||||
<artifactId>apache-jena-libs</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-text</artifactId>
|
||||
|
|
|
@ -20,6 +20,7 @@ import ca.uhn.fhir.util.ReflectionUtil;
|
|||
import ca.uhn.fhir.util.VersionUtil;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.jena.riot.Lang;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -111,7 +112,7 @@ public class FhirContext {
|
|||
* of this method, e.g. {@link #forDstu2()} or {@link #forDstu3()} or {@link #forR4()}
|
||||
*/
|
||||
@Deprecated
|
||||
public FhirContext(Class<? extends IBaseResource> theResourceType) {
|
||||
public FhirContext(final Class<? extends IBaseResource> theResourceType) {
|
||||
this(toCollection(theResourceType));
|
||||
}
|
||||
|
||||
|
@ -120,7 +121,7 @@ public class FhirContext {
|
|||
* of this method, e.g. {@link #forDstu2()} or {@link #forDstu3()} or {@link #forR4()}
|
||||
*/
|
||||
@Deprecated
|
||||
public FhirContext(Class<?>... theResourceTypes) {
|
||||
public FhirContext(final Class<?>... theResourceTypes) {
|
||||
this(toCollection(theResourceTypes));
|
||||
}
|
||||
|
||||
|
@ -129,7 +130,7 @@ public class FhirContext {
|
|||
* of this method, e.g. {@link #forDstu2()} or {@link #forDstu3()} or {@link #forR4()}
|
||||
*/
|
||||
@Deprecated
|
||||
public FhirContext(Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
public FhirContext(final Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
this(null, theResourceTypes);
|
||||
}
|
||||
|
||||
|
@ -138,11 +139,11 @@ public class FhirContext {
|
|||
* of this method, e.g. {@link #forDstu2()} or {@link #forDstu3()} or {@link #forR4()}, but
|
||||
* this method can also be used if you wish to supply the version programmatically.
|
||||
*/
|
||||
public FhirContext(FhirVersionEnum theVersion) {
|
||||
public FhirContext(final FhirVersionEnum theVersion) {
|
||||
this(theVersion, null);
|
||||
}
|
||||
|
||||
private FhirContext(FhirVersionEnum theVersion, Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
private FhirContext(final FhirVersionEnum theVersion, final Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
VersionUtil.getVersion();
|
||||
|
||||
if (theVersion != null) {
|
||||
|
@ -191,7 +192,7 @@ public class FhirContext {
|
|||
|
||||
}
|
||||
|
||||
private String createUnknownResourceNameError(String theResourceName, FhirVersionEnum theVersion) {
|
||||
private String createUnknownResourceNameError(final String theResourceName, final FhirVersionEnum theVersion) {
|
||||
return getLocalizer().getMessage(FhirContext.class, "unknownResourceName", theResourceName, theVersion);
|
||||
}
|
||||
|
||||
|
@ -232,7 +233,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theAddProfileTagWhenEncoding The add profile mode (must not be <code>null</code>)
|
||||
*/
|
||||
public void setAddProfileTagWhenEncoding(AddProfileTagEnum theAddProfileTagWhenEncoding) {
|
||||
public void setAddProfileTagWhenEncoding(final AddProfileTagEnum theAddProfileTagWhenEncoding) {
|
||||
Validate.notNull(theAddProfileTagWhenEncoding, "theAddProfileTagWhenEncoding must not be null");
|
||||
myAddProfileTagWhenEncoding = theAddProfileTagWhenEncoding;
|
||||
}
|
||||
|
@ -247,7 +248,7 @@ public class FhirContext {
|
|||
*
|
||||
* @see #setDefaultTypeForProfile(String, Class)
|
||||
*/
|
||||
public Class<? extends IBaseResource> getDefaultTypeForProfile(String theProfile) {
|
||||
public Class<? extends IBaseResource> getDefaultTypeForProfile(final String theProfile) {
|
||||
validateInitialized();
|
||||
return myDefaultTypeForProfile.get(theProfile);
|
||||
}
|
||||
|
@ -257,7 +258,7 @@ public class FhirContext {
|
|||
* for extending the core library.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public BaseRuntimeElementDefinition<?> getElementDefinition(Class<? extends IBase> theElementType) {
|
||||
public BaseRuntimeElementDefinition<?> getElementDefinition(final Class<? extends IBase> theElementType) {
|
||||
validateInitialized();
|
||||
BaseRuntimeElementDefinition<?> retVal = myClassToElementDefinition.get(theElementType);
|
||||
if (retVal == null) {
|
||||
|
@ -273,7 +274,7 @@ public class FhirContext {
|
|||
* Note that this method is case insensitive!
|
||||
* </p>
|
||||
*/
|
||||
public BaseRuntimeElementDefinition<?> getElementDefinition(String theElementName) {
|
||||
public BaseRuntimeElementDefinition<?> getElementDefinition(final String theElementName) {
|
||||
validateInitialized();
|
||||
return myNameToElementDefinition.get(theElementName.toLowerCase());
|
||||
}
|
||||
|
@ -301,7 +302,7 @@ public class FhirContext {
|
|||
* This feature is not yet in its final state and should be considered an internal part of HAPI for now - use with
|
||||
* caution
|
||||
*/
|
||||
public void setLocalizer(HapiLocalizer theMessages) {
|
||||
public void setLocalizer(final HapiLocalizer theMessages) {
|
||||
myLocalizer = theMessages;
|
||||
}
|
||||
|
||||
|
@ -309,7 +310,7 @@ public class FhirContext {
|
|||
return myNarrativeGenerator;
|
||||
}
|
||||
|
||||
public void setNarrativeGenerator(INarrativeGenerator theNarrativeGenerator) {
|
||||
public void setNarrativeGenerator(final INarrativeGenerator theNarrativeGenerator) {
|
||||
myNarrativeGenerator = theNarrativeGenerator;
|
||||
}
|
||||
|
||||
|
@ -329,7 +330,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theParserOptions The parser options object - Must not be <code>null</code>
|
||||
*/
|
||||
public void setParserOptions(ParserOptions theParserOptions) {
|
||||
public void setParserOptions(final ParserOptions theParserOptions) {
|
||||
Validate.notNull(theParserOptions, "theParserOptions must not be null");
|
||||
myParserOptions = theParserOptions;
|
||||
}
|
||||
|
@ -360,7 +361,7 @@ public class FhirContext {
|
|||
*
|
||||
* @see PerformanceOptionsEnum for a list of available options
|
||||
*/
|
||||
public void setPerformanceOptions(Collection<PerformanceOptionsEnum> theOptions) {
|
||||
public void setPerformanceOptions(final Collection<PerformanceOptionsEnum> theOptions) {
|
||||
myPerformanceOptions.clear();
|
||||
if (theOptions != null) {
|
||||
myPerformanceOptions.addAll(theOptions);
|
||||
|
@ -371,7 +372,7 @@ public class FhirContext {
|
|||
* Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed
|
||||
* for extending the core library.
|
||||
*/
|
||||
public RuntimeResourceDefinition getResourceDefinition(Class<? extends IBaseResource> theResourceType) {
|
||||
public RuntimeResourceDefinition getResourceDefinition(final Class<? extends IBaseResource> theResourceType) {
|
||||
validateInitialized();
|
||||
if (theResourceType == null) {
|
||||
throw new NullPointerException("theResourceType can not be null");
|
||||
|
@ -387,7 +388,7 @@ public class FhirContext {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public RuntimeResourceDefinition getResourceDefinition(FhirVersionEnum theVersion, String theResourceName) {
|
||||
public RuntimeResourceDefinition getResourceDefinition(final FhirVersionEnum theVersion, final String theResourceName) {
|
||||
Validate.notNull(theVersion, "theVersion can not be null");
|
||||
validateInitialized();
|
||||
|
||||
|
@ -419,7 +420,7 @@ public class FhirContext {
|
|||
* Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed
|
||||
* for extending the core library.
|
||||
*/
|
||||
public RuntimeResourceDefinition getResourceDefinition(IBaseResource theResource) {
|
||||
public RuntimeResourceDefinition getResourceDefinition(final IBaseResource theResource) {
|
||||
validateInitialized();
|
||||
Validate.notNull(theResource, "theResource must not be null");
|
||||
return getResourceDefinition(theResource.getClass());
|
||||
|
@ -434,7 +435,7 @@ public class FhirContext {
|
|||
*
|
||||
* @throws DataFormatException If the resource name is not known
|
||||
*/
|
||||
public RuntimeResourceDefinition getResourceDefinition(String theResourceName) throws DataFormatException {
|
||||
public RuntimeResourceDefinition getResourceDefinition(final String theResourceName) throws DataFormatException {
|
||||
validateInitialized();
|
||||
Validate.notBlank(theResourceName, "theResourceName must not be blank");
|
||||
|
||||
|
@ -462,7 +463,7 @@ public class FhirContext {
|
|||
* Returns the scanned runtime model for the given type. This is an advanced feature which is generally only needed
|
||||
* for extending the core library.
|
||||
*/
|
||||
public RuntimeResourceDefinition getResourceDefinitionById(String theId) {
|
||||
public RuntimeResourceDefinition getResourceDefinitionById(final String theId) {
|
||||
validateInitialized();
|
||||
return myIdToResourceDefinition.get(theId);
|
||||
}
|
||||
|
@ -528,7 +529,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theRestfulClientFactory
|
||||
*/
|
||||
public void setRestfulClientFactory(IRestfulClientFactory theRestfulClientFactory) {
|
||||
public void setRestfulClientFactory(final IRestfulClientFactory theRestfulClientFactory) {
|
||||
Validate.notNull(theRestfulClientFactory, "theRestfulClientFactory must not be null");
|
||||
this.myRestfulClientFactory = theRestfulClientFactory;
|
||||
}
|
||||
|
@ -619,6 +620,23 @@ public class FhirContext {
|
|||
return new JsonParser(this, myParserErrorHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new RDF parser.
|
||||
*
|
||||
* <p>
|
||||
* Thread safety: <b>Parsers are not guaranteed to be thread safe</b>. Create a new parser instance for every thread
|
||||
* or every message being parsed/encoded.
|
||||
* </p>
|
||||
* <p>
|
||||
* Performance Note: <b>This method is cheap</b> to call, and may be called once for every message being processed
|
||||
* without incurring any performance penalty
|
||||
* </p>
|
||||
*/
|
||||
public IParser newRDFParser() {
|
||||
return new RDFParser(this, myParserErrorHandler, Lang.TURTLE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates a new client instance. This method requires an interface which is defined specifically for your use
|
||||
* cases to contain methods for each of the RESTful operations you wish to implement (e.g. "read ImagingStudy",
|
||||
|
@ -637,7 +655,7 @@ public class FhirContext {
|
|||
* @return A newly created client
|
||||
* @throws ConfigurationException If the interface type is not an interface
|
||||
*/
|
||||
public <T extends IRestfulClient> T newRestfulClient(Class<T> theClientType, String theServerBase) {
|
||||
public <T extends IRestfulClient> T newRestfulClient(final Class<T> theClientType, final String theServerBase) {
|
||||
return getRestfulClientFactory().newClient(theClientType, theServerBase);
|
||||
}
|
||||
|
||||
|
@ -653,7 +671,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theServerBase The URL of the base for the restful FHIR server to connect to
|
||||
*/
|
||||
public IGenericClient newRestfulGenericClient(String theServerBase) {
|
||||
public IGenericClient newRestfulGenericClient(final String theServerBase) {
|
||||
return getRestfulClientFactory().newGenericClient(theServerBase);
|
||||
}
|
||||
|
||||
|
@ -704,7 +722,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theType The custom type to add (must not be <code>null</code>)
|
||||
*/
|
||||
public void registerCustomType(Class<? extends IBase> theType) {
|
||||
public void registerCustomType(final Class<? extends IBase> theType) {
|
||||
Validate.notNull(theType, "theType must not be null");
|
||||
|
||||
ensureCustomTypeList();
|
||||
|
@ -723,7 +741,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theTypes The custom types to add (must not be <code>null</code> or contain null elements in the collection)
|
||||
*/
|
||||
public void registerCustomTypes(Collection<Class<? extends IBase>> theTypes) {
|
||||
public void registerCustomTypes(final Collection<Class<? extends IBase>> theTypes) {
|
||||
Validate.notNull(theTypes, "theTypes must not be null");
|
||||
Validate.noNullElements(theTypes.toArray(), "theTypes must not contain any null elements");
|
||||
|
||||
|
@ -732,22 +750,22 @@ public class FhirContext {
|
|||
myCustomTypes.addAll(theTypes);
|
||||
}
|
||||
|
||||
private BaseRuntimeElementDefinition<?> scanDatatype(Class<? extends IElement> theResourceType) {
|
||||
ArrayList<Class<? extends IElement>> resourceTypes = new ArrayList<>();
|
||||
private BaseRuntimeElementDefinition<?> scanDatatype(final Class<? extends IElement> theResourceType) {
|
||||
ArrayList<Class<? extends IElement>> resourceTypes = new ArrayList<Class<? extends IElement>>();
|
||||
resourceTypes.add(theResourceType);
|
||||
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> defs = scanResourceTypes(resourceTypes);
|
||||
return defs.get(theResourceType);
|
||||
}
|
||||
|
||||
private RuntimeResourceDefinition scanResourceType(Class<? extends IBaseResource> theResourceType) {
|
||||
ArrayList<Class<? extends IElement>> resourceTypes = new ArrayList<>();
|
||||
private RuntimeResourceDefinition scanResourceType(final Class<? extends IBaseResource> theResourceType) {
|
||||
ArrayList<Class<? extends IElement>> resourceTypes = new ArrayList<Class<? extends IElement>>();
|
||||
resourceTypes.add(theResourceType);
|
||||
Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> defs = scanResourceTypes(resourceTypes);
|
||||
return (RuntimeResourceDefinition) defs.get(theResourceType);
|
||||
}
|
||||
|
||||
private synchronized Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> scanResourceTypes(Collection<Class<? extends IElement>> theResourceTypes) {
|
||||
List<Class<? extends IBase>> typesToScan = new ArrayList<>();
|
||||
private synchronized Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> scanResourceTypes(final Collection<Class<? extends IElement>> theResourceTypes) {
|
||||
List<Class<? extends IBase>> typesToScan = new ArrayList<Class<? extends IBase>>();
|
||||
if (theResourceTypes != null) {
|
||||
typesToScan.addAll(theResourceTypes);
|
||||
}
|
||||
|
@ -819,7 +837,7 @@ public class FhirContext {
|
|||
* <code>null</code> or empty.
|
||||
* @param theClass The resource type, or <code>null</code> to clear any existing type
|
||||
*/
|
||||
public void setDefaultTypeForProfile(String theProfile, Class<? extends IBaseResource> theClass) {
|
||||
public void setDefaultTypeForProfile(final String theProfile, final Class<? extends IBaseResource> theClass) {
|
||||
Validate.notBlank(theProfile, "theProfile must not be null or empty");
|
||||
if (theClass == null) {
|
||||
myDefaultTypeForProfile.remove(theProfile);
|
||||
|
@ -833,7 +851,7 @@ public class FhirContext {
|
|||
*
|
||||
* @param theParserErrorHandler The error handler
|
||||
*/
|
||||
public void setParserErrorHandler(IParserErrorHandler theParserErrorHandler) {
|
||||
public void setParserErrorHandler(final IParserErrorHandler theParserErrorHandler) {
|
||||
Validate.notNull(theParserErrorHandler, "theParserErrorHandler must not be null");
|
||||
myParserErrorHandler = theParserErrorHandler;
|
||||
}
|
||||
|
@ -843,7 +861,7 @@ public class FhirContext {
|
|||
*
|
||||
* @see PerformanceOptionsEnum for a list of available options
|
||||
*/
|
||||
public void setPerformanceOptions(PerformanceOptionsEnum... thePerformanceOptions) {
|
||||
public void setPerformanceOptions(final PerformanceOptionsEnum... thePerformanceOptions) {
|
||||
Collection<PerformanceOptionsEnum> asList = null;
|
||||
if (thePerformanceOptions != null) {
|
||||
asList = Arrays.asList(thePerformanceOptions);
|
||||
|
@ -852,7 +870,7 @@ public class FhirContext {
|
|||
}
|
||||
|
||||
@SuppressWarnings({"cast"})
|
||||
private List<Class<? extends IElement>> toElementList(Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
private List<Class<? extends IElement>> toElementList(final Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
if (theResourceTypes == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -922,8 +940,8 @@ public class FhirContext {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static List<Class<? extends IBaseResource>> toCollection(Class<?>[] theResourceTypes) {
|
||||
ArrayList<Class<? extends IBaseResource>> retVal = new ArrayList<>(1);
|
||||
private static List<Class<? extends IBaseResource>> toCollection(final Class<?>[] theResourceTypes) {
|
||||
ArrayList<Class<? extends IBaseResource>> retVal = new ArrayList<Class<? extends IBaseResource>>(1);
|
||||
for (Class<?> clazz : theResourceTypes) {
|
||||
if (!IResource.class.isAssignableFrom(clazz)) {
|
||||
throw new IllegalArgumentException(clazz.getCanonicalName() + " is not an instance of " + IResource.class.getSimpleName());
|
||||
|
|
|
@ -0,0 +1,542 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import ca.uhn.fhir.util.rdf.RDFUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.jena.riot.Lang;
|
||||
import org.apache.jena.riot.system.StreamRDF;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* This class is the FHIR RDF parser/encoder. Users should not interact with this class directly, but should use
|
||||
* {@link FhirContext#newRDFParser()} to get an instance.
|
||||
*/
|
||||
public class RDFParser extends BaseParser {
|
||||
|
||||
private static final String FHIR_NS = "http://hl7.org/fhir";
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(RDFParser.class);
|
||||
|
||||
private FhirContext context;
|
||||
private Lang lang;
|
||||
|
||||
/**
|
||||
* Do not use this constructor, the recommended way to obtain a new instance of the RDF parser is to invoke
|
||||
* {@link FhirContext#newRDFParser()}.
|
||||
*
|
||||
* @param parserErrorHandler the Parser Error Handler
|
||||
*/
|
||||
public RDFParser(final FhirContext context, final IParserErrorHandler parserErrorHandler, final Lang lang) {
|
||||
super(context, parserErrorHandler);
|
||||
this.context = context;
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEncodeResourceToWriter(final IBaseResource resource,
|
||||
final Writer writer,
|
||||
final EncodeContext encodeContext) {
|
||||
StreamRDF eventWriter = RDFUtil.createRDFWriter(writer, this.lang);
|
||||
eventWriter.base(FHIR_NS);
|
||||
encodeResourceToRDFStreamWriter(resource, eventWriter, encodeContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T extends IBaseResource> T doParseResource(final Class<T> resourceType,
|
||||
final Reader reader) throws DataFormatException {
|
||||
|
||||
StreamRDF streamReader = RDFUtil.createRDFReader(reader, this.lang);
|
||||
streamReader.base(FHIR_NS);
|
||||
return parseResource(resourceType, streamReader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EncodingEnum getEncoding() {
|
||||
return EncodingEnum.RDF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser setPrettyPrint(final boolean prettyPrint) {
|
||||
return this;
|
||||
}
|
||||
|
||||
private void encodeResourceToRDFStreamWriter(final IBaseResource resource,
|
||||
final StreamRDF streamWriter,
|
||||
final boolean containedResource,
|
||||
final IIdType resourceId,
|
||||
final EncodeContext encodeContext) {
|
||||
RuntimeResourceDefinition resDef = this.context.getResourceDefinition(resource);
|
||||
if (resDef == null) {
|
||||
throw new ConfigurationException("Unknown resource type: " + resource.getClass());
|
||||
}
|
||||
|
||||
if (!containedResource) {
|
||||
super.containResourcesForEncoding(resource);
|
||||
}
|
||||
|
||||
if (resource instanceof IAnyResource) {
|
||||
// HL7.org Structures
|
||||
if (resourceId != null) {
|
||||
writeCommentsPre(streamWriter, resourceId);
|
||||
streamWriter.start();
|
||||
streamWriter.triple(RDFUtil.triple("<value> " + resourceId.getIdPart() + " </value>"));
|
||||
streamWriter.finish();
|
||||
writeCommentsPost(streamWriter, resourceId);
|
||||
}
|
||||
|
||||
encodeCompositeElementToStreamWriter(resource, resource, streamWriter, containedResource, new CompositeChildElement(resDef, encodeContext), encodeContext);
|
||||
|
||||
} else {
|
||||
|
||||
// DSTU2+
|
||||
if (resourceId != null) {
|
||||
streamWriter.start();
|
||||
streamWriter.triple(RDFUtil.triple("<value> " + resourceId.getIdPart() + " </value>"));
|
||||
encodeExtensionsIfPresent(resource, streamWriter, resourceId, false, encodeContext);
|
||||
streamWriter.finish();
|
||||
writeCommentsPost(streamWriter, resourceId);
|
||||
}
|
||||
/*
|
||||
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
||||
IdDt idDt = resource.getId();
|
||||
String versionIdPart = idDt.getVersionIdPart();
|
||||
if (isBlank(versionIdPart)) {
|
||||
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
|
||||
}
|
||||
List<BaseCodingDt> securityLabels = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.SECURITY_LABELS);
|
||||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding((resource), encodeContext);
|
||||
|
||||
if (!ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles)) {
|
||||
streamWriter.start();
|
||||
|
||||
for (IIdType profile : profiles) {
|
||||
streamWriter.start();
|
||||
streamWriter.triple(RDFUtil.triple("<value> " + profile.getValue() + " </value>"));
|
||||
streamWriter.finish();
|
||||
}
|
||||
for (BaseCodingDt securityLabel : securityLabels) {
|
||||
streamWriter.start();
|
||||
encodeCompositeElementToStreamWriter(resource, securityLabel, streamWriter, containedResource, null, encodeContext);
|
||||
streamWriter.finish();
|
||||
}
|
||||
if (tags != null) {
|
||||
for (Tag tag : tags) {
|
||||
if (tag.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
streamWriter.start();
|
||||
streamWriter.triple(RDFUtil.triple("<system> " + tag.getScheme() + " </system>"));
|
||||
streamWriter.triple(RDFUtil.triple("<code> " + tag.getTerm() + " </code>"));
|
||||
streamWriter.triple(RDFUtil.triple("<display> " + tag.getLabel() + " </display>"));
|
||||
streamWriter.finish();
|
||||
}
|
||||
}
|
||||
streamWriter.finish();
|
||||
}
|
||||
*/
|
||||
if (resource instanceof IBaseBinary) {
|
||||
IBaseBinary bin = (IBaseBinary) resource;
|
||||
streamWriter.triple(RDFUtil.triple("<contentType> " + bin.getContentType() + " </contentType>"));
|
||||
streamWriter.triple(RDFUtil.triple("<content> " + bin.getContentAsBase64() + " </content>"));
|
||||
} else {
|
||||
encodeCompositeElementToStreamWriter(resource, resource, streamWriter, containedResource, new CompositeChildElement(resDef, encodeContext), encodeContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
streamWriter.finish();
|
||||
}
|
||||
|
||||
private void writeCommentsPre(final StreamRDF eventWriter, final IBase element) {
|
||||
if (element != null && element.hasFormatComment()) {
|
||||
for (String next : element.getFormatCommentsPre()) {
|
||||
if (isNotBlank(next)) {
|
||||
eventWriter.base(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeCommentsPost(final StreamRDF eventWriter, final IBase element) {
|
||||
if (element != null && element.hasFormatComment()) {
|
||||
for (String next : element.getFormatCommentsPost()) {
|
||||
if (isNotBlank(next)) {
|
||||
eventWriter.base(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeChildElementToStreamWriter(final IBaseResource resource,
|
||||
final StreamRDF eventWriter,
|
||||
final BaseRuntimeChildDefinition childDefinition,
|
||||
final IBase element,
|
||||
final String childName,
|
||||
final BaseRuntimeElementDefinition<?> childDef,
|
||||
final String extensionUrl,
|
||||
final boolean includedResource,
|
||||
final CompositeChildElement parent,
|
||||
final EncodeContext encodeContext) {
|
||||
|
||||
String childGenericName = childDefinition.getElementName();
|
||||
|
||||
encodeContext.pushPath(childGenericName, false);
|
||||
try {
|
||||
|
||||
if (element == null || element.isEmpty()) {
|
||||
if (!isChildContained(childDef, includedResource)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
writeCommentsPre(eventWriter, element);
|
||||
|
||||
switch (childDef.getChildType()) {
|
||||
case ID_DATATYPE: {
|
||||
IIdType value = (IIdType) element;
|
||||
assert value != null;
|
||||
String encodedValue = "id".equals(childName) ? value.getIdPart() : value.getValue();
|
||||
if (StringUtils.isNotBlank(encodedValue) || !hasNoExtensions(value)) {
|
||||
eventWriter.start();
|
||||
if (StringUtils.isNotBlank(encodedValue)) {
|
||||
eventWriter.triple(RDFUtil.triple("<value> " + encodedValue + " </value>"));
|
||||
}
|
||||
encodeExtensionsIfPresent(resource, eventWriter, element, includedResource, encodeContext);
|
||||
eventWriter.finish();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
IPrimitiveType<?> pd = (IPrimitiveType) element;
|
||||
assert pd != null;
|
||||
String value = pd.getValueAsString();
|
||||
if (value != null || !hasNoExtensions(pd)) {
|
||||
eventWriter.start();
|
||||
String elementId = getCompositeElementId(element);
|
||||
if (isNotBlank(elementId)) {
|
||||
eventWriter.triple(RDFUtil.triple("<id> " + elementId + " </id>"));
|
||||
}
|
||||
if (value != null) {
|
||||
eventWriter.triple(RDFUtil.triple("<value> " + value + " </value>"));
|
||||
}
|
||||
encodeExtensionsIfPresent(resource, eventWriter, element, includedResource, encodeContext);
|
||||
eventWriter.finish();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE_BLOCK:
|
||||
case COMPOSITE_DATATYPE: {
|
||||
eventWriter.start();
|
||||
String elementId = getCompositeElementId(element);
|
||||
if (isNotBlank(elementId)) {
|
||||
eventWriter.triple(RDFUtil.triple("<id> " + elementId + " </id>"));
|
||||
}
|
||||
if (isNotBlank(extensionUrl)) {
|
||||
eventWriter.triple(RDFUtil.triple("<url> " + extensionUrl + " </url>"));
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(resource, element, eventWriter, includedResource, parent, encodeContext);
|
||||
eventWriter.finish();
|
||||
break;
|
||||
}
|
||||
case CONTAINED_RESOURCE_LIST:
|
||||
case CONTAINED_RESOURCES: {
|
||||
/*
|
||||
* Disable per #103 for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) { continue; }
|
||||
* theEventWriter.writeStartElement("contained"); encodeResourceToRDFStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue()));
|
||||
* theEventWriter.writeEndElement(); }
|
||||
*/
|
||||
for (IBaseResource next : getContainedResources().getContainedResources()) {
|
||||
IIdType resourceId = getContainedResources().getResourceId(next);
|
||||
eventWriter.start();
|
||||
encodeResourceToRDFStreamWriter(next, eventWriter, true, fixContainedResourceId(resourceId.getValue()), encodeContext);
|
||||
eventWriter.finish();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE: {
|
||||
IBaseResource baseResource = (IBaseResource) element;
|
||||
String resourceName = this.context.getResourceDefinition(baseResource).getName();
|
||||
if (!super.shouldEncodeResource(resourceName)) {
|
||||
break;
|
||||
}
|
||||
eventWriter.start();
|
||||
encodeContext.pushPath(resourceName, true);
|
||||
encodeResourceToRDFStreamWriter(resource, eventWriter, encodeContext);
|
||||
encodeContext.popPath();
|
||||
eventWriter.finish();
|
||||
break;
|
||||
}
|
||||
case EXTENSION_DECLARED:
|
||||
case UNDECL_EXT: {
|
||||
throw new IllegalStateException("state should not happen: " + childDef.getName());
|
||||
}
|
||||
}
|
||||
|
||||
writeCommentsPost(eventWriter, element);
|
||||
|
||||
} finally {
|
||||
encodeContext.popPath();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void encodeResourceToRDFStreamWriter(final IBaseResource resource,
|
||||
final StreamRDF eventWriter,
|
||||
final EncodeContext encodeContext) {
|
||||
IIdType resourceId = null;
|
||||
|
||||
if (StringUtils.isNotBlank(resource.getIdElement().getIdPart())) {
|
||||
resourceId = resource.getIdElement();
|
||||
if (resource.getIdElement().getValue().startsWith("urn:")) {
|
||||
resourceId = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!super.shouldEncodeResourceId(resource, encodeContext)) {
|
||||
resourceId = null;
|
||||
} else if (encodeContext.getResourcePath().size() == 1 && getEncodeForceResourceId() != null) {
|
||||
resourceId = getEncodeForceResourceId();
|
||||
}
|
||||
|
||||
encodeResourceToRDFStreamWriter(resource, eventWriter, false, resourceId, encodeContext);
|
||||
}
|
||||
|
||||
private void encodeUndeclaredExtensions(final IBaseResource resource,
|
||||
final StreamRDF eventWriter,
|
||||
final List<? extends IBaseExtension<?, ?>> extensions,
|
||||
final boolean includedResource,
|
||||
final EncodeContext encodeContext) {
|
||||
for (IBaseExtension<?, ?> next : extensions) {
|
||||
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
writeCommentsPre(eventWriter, next);
|
||||
|
||||
eventWriter.start();
|
||||
|
||||
String elementId = getCompositeElementId(next);
|
||||
if (isNotBlank(elementId)) {
|
||||
eventWriter.triple(RDFUtil.triple("<id> " + elementId + " </id>"));
|
||||
}
|
||||
|
||||
String url = getExtensionUrl(next.getUrl());
|
||||
eventWriter.triple(RDFUtil.triple("<url> " + url + " </url>"));
|
||||
|
||||
if (next.getValue() != null) {
|
||||
IBaseDatatype value = next.getValue();
|
||||
RuntimeChildUndeclaredExtensionDefinition extDef = this.context.getRuntimeChildUndeclaredExtensionDefinition();
|
||||
String childName = extDef.getChildNameByDatatype(value.getClass());
|
||||
BaseRuntimeElementDefinition<?> childDef;
|
||||
if (childName == null) {
|
||||
childDef = this.context.getElementDefinition(value.getClass());
|
||||
if (childDef == null) {
|
||||
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
|
||||
}
|
||||
childName = RuntimeChildUndeclaredExtensionDefinition.createExtensionChildName(childDef);
|
||||
} else {
|
||||
childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
|
||||
if (childDef == null) {
|
||||
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
encodeChildElementToStreamWriter(resource, eventWriter, extDef, value, childName,
|
||||
childDef, null, includedResource, null, encodeContext);
|
||||
}
|
||||
|
||||
// child extensions
|
||||
encodeExtensionsIfPresent(resource, eventWriter, next, includedResource, encodeContext);
|
||||
|
||||
eventWriter.finish();
|
||||
|
||||
writeCommentsPost(eventWriter, next);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeExtensionsIfPresent(final IBaseResource resource,
|
||||
final StreamRDF writer,
|
||||
final IBase element,
|
||||
final boolean includedResource,
|
||||
final EncodeContext encodeContext) {
|
||||
if (element instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) element;
|
||||
encodeUndeclaredExtensions(resource, writer, toBaseExtensionList(res.getUndeclaredExtensions()), includedResource, encodeContext);
|
||||
encodeUndeclaredExtensions(resource, writer, toBaseExtensionList(res.getUndeclaredModifierExtensions()), includedResource, encodeContext);
|
||||
}
|
||||
if (element instanceof IBaseHasExtensions) {
|
||||
IBaseHasExtensions res = (IBaseHasExtensions) element;
|
||||
encodeUndeclaredExtensions(resource, writer, res.getExtension(), includedResource, encodeContext);
|
||||
}
|
||||
if (element instanceof IBaseHasModifierExtensions) {
|
||||
IBaseHasModifierExtensions res = (IBaseHasModifierExtensions) element;
|
||||
encodeUndeclaredExtensions(resource, writer, res.getModifierExtension(), includedResource, encodeContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeExtension(final IBaseResource resource,
|
||||
final StreamRDF eventWriter,
|
||||
final boolean containedResource,
|
||||
final CompositeChildElement nextChildElem,
|
||||
final BaseRuntimeChildDefinition nextChild,
|
||||
final IBase nextValue,
|
||||
final String childName,
|
||||
final String extensionUrl,
|
||||
final BaseRuntimeElementDefinition<?> childDef,
|
||||
final EncodeContext encodeContext) {
|
||||
BaseRuntimeDeclaredChildDefinition extDef = (BaseRuntimeDeclaredChildDefinition) nextChild;
|
||||
eventWriter.start();
|
||||
|
||||
String elementId = getCompositeElementId(nextValue);
|
||||
if (isNotBlank(elementId)) {
|
||||
eventWriter.triple(RDFUtil.triple("<id> " + elementId + " </id>"));
|
||||
}
|
||||
eventWriter.triple(RDFUtil.triple("<url> " + extensionUrl + " </url>"));
|
||||
encodeChildElementToStreamWriter(resource, eventWriter, nextChild, nextValue, childName,
|
||||
childDef, null, containedResource, nextChildElem, encodeContext);
|
||||
eventWriter.finish();
|
||||
}
|
||||
|
||||
private void encodeCompositeElementToStreamWriter(final IBaseResource resource,
|
||||
final IBase element,
|
||||
final StreamRDF streamRDF,
|
||||
final boolean containedResource,
|
||||
final CompositeChildElement parent,
|
||||
final EncodeContext encodeContext) {
|
||||
|
||||
for (CompositeChildElement nextChildElem : super.compositeChildIterator(element, containedResource, parent, encodeContext)) {
|
||||
|
||||
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
|
||||
|
||||
if (nextChild.getElementName().equals("url") && element instanceof IBaseExtension) {
|
||||
/*
|
||||
* RDF encoding is a one-off for extensions. The URL element goes in an attribute
|
||||
* instead of being encoded as a normal element, only for RDF encoding
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
|
||||
INarrativeGenerator gen = this.context.getNarrativeGenerator();
|
||||
INarrative narr;
|
||||
if (resource instanceof IResource) {
|
||||
narr = ((IResource) resource).getText();
|
||||
} else if (resource instanceof IDomainResource) {
|
||||
narr = ((IDomainResource) resource).getText();
|
||||
} else {
|
||||
narr = null;
|
||||
}
|
||||
assert narr != null;
|
||||
if (gen != null && narr.isEmpty()) {
|
||||
gen.populateResourceNarrative(this.context, resource);
|
||||
}
|
||||
if (!narr.isEmpty()) {
|
||||
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
|
||||
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
|
||||
encodeChildElementToStreamWriter(resource,
|
||||
streamRDF, nextChild, narr, childName, type, null,
|
||||
containedResource, nextChildElem, encodeContext);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextChild instanceof RuntimeChildContainedResources) {
|
||||
encodeChildElementToStreamWriter(resource, streamRDF, nextChild, null,
|
||||
nextChild.getChildNameByDatatype(null),
|
||||
nextChild.getChildElementDefinitionByDatatype(null), null,
|
||||
containedResource, nextChildElem, encodeContext);
|
||||
} else {
|
||||
|
||||
List<? extends IBase> values = nextChild.getAccessor().getValues(element);
|
||||
values = super.preProcessValues(nextChild, resource, values, nextChildElem, encodeContext);
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (IBase nextValue : values) {
|
||||
if ((nextValue == null || nextValue.isEmpty())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ChildNameAndDef childNameAndDef = super.getChildNameAndDef(nextChild, nextValue);
|
||||
if (childNameAndDef == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String childName = childNameAndDef.getChildName();
|
||||
BaseRuntimeElementDefinition<?> childDef = childNameAndDef.getChildDef();
|
||||
String extensionUrl = getExtensionUrl(nextChild.getExtensionUrl());
|
||||
|
||||
if (extensionUrl != null && !childName.equals("extension")) {
|
||||
encodeExtension(resource, streamRDF, containedResource, nextChildElem, nextChild,
|
||||
nextValue, childName, extensionUrl, childDef, encodeContext);
|
||||
} else if (nextChild instanceof RuntimeChildExtension) {
|
||||
IBaseExtension<?, ?> extension = (IBaseExtension<?, ?>) nextValue;
|
||||
if ((extension.getValue() == null || extension.getValue().isEmpty())) {
|
||||
if (extension.getExtension().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
encodeChildElementToStreamWriter(resource, streamRDF, nextChild, nextValue,
|
||||
childName, childDef, getExtensionUrl(extension.getUrl()),
|
||||
containedResource, nextChildElem, encodeContext);
|
||||
} else if (!(nextChild instanceof RuntimeChildNarrativeDefinition) || !containedResource) {
|
||||
encodeChildElementToStreamWriter(resource, streamRDF, nextChild, nextValue,
|
||||
childName, childDef, extensionUrl, containedResource, nextChildElem, encodeContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <Q extends IBaseExtension<?, ?>> List<IBaseExtension<?, ?>> toBaseExtensionList(final List<Q> theList) {
|
||||
List<IBaseExtension<?, ?>> retVal = new ArrayList<>(theList.size());
|
||||
retVal.addAll(theList);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private <T extends IBaseResource> T parseResource(Class<T> resourceType, StreamRDF streamReader) {
|
||||
ParserState<T> parserState = ParserState.getPreResourceInstance(this, resourceType, context, false, getErrorHandler());
|
||||
return doRDFLoop(streamReader, parserState);
|
||||
}
|
||||
|
||||
|
||||
private <T> T doRDFLoop(StreamRDF streamReader, ParserState<T> parserState) {
|
||||
logger.trace("Entering RDF parsing loop with state: {}", parserState);
|
||||
return parserState.getObject();
|
||||
}
|
||||
}
|
|
@ -43,6 +43,7 @@ public class Constants {
|
|||
*/
|
||||
public static final Set<String> CORS_ALLWED_METHODS;
|
||||
public static final String CT_FHIR_JSON = "application/json+fhir";
|
||||
public static final String CT_RDF_TURTLE = "application/x-turtle";
|
||||
/**
|
||||
* The FHIR MimeType for JSON encoding in FHIR DSTU3+
|
||||
*/
|
||||
|
@ -71,6 +72,9 @@ public class Constants {
|
|||
public static final String FORMAT_HTML = "html";
|
||||
public static final String FORMAT_JSON = "json";
|
||||
public static final String FORMAT_XML = "xml";
|
||||
public static final String FORMAT_TURTLE = "text/turtle";
|
||||
|
||||
|
||||
/**
|
||||
* "text/html" and "html"
|
||||
*/
|
||||
|
|
|
@ -42,16 +42,25 @@ public enum EncodingEnum {
|
|||
public IParser newParser(FhirContext theContext) {
|
||||
return theContext.newXmlParser();
|
||||
}
|
||||
},
|
||||
|
||||
RDF(Constants.CT_RDF_TURTLE, Constants.CT_RDF_TURTLE, Constants.FORMAT_TURTLE) {
|
||||
@Override
|
||||
public IParser newParser(FhirContext theContext) {
|
||||
return theContext.newRDFParser();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* "json"
|
||||
*/
|
||||
public static final String JSON_PLAIN_STRING = "json";
|
||||
|
||||
/**
|
||||
* "xml"
|
||||
*/
|
||||
public static final String XML_PLAIN_STRING = "xml";
|
||||
|
||||
private static Map<String, EncodingEnum> ourContentTypeToEncoding;
|
||||
private static Map<String, EncodingEnum> ourContentTypeToEncodingLegacy;
|
||||
private static Map<String, EncodingEnum> ourContentTypeToEncodingStrict;
|
||||
|
@ -127,9 +136,9 @@ public enum EncodingEnum {
|
|||
return myResourceContentTypeNonLegacy;
|
||||
}
|
||||
|
||||
public abstract IParser newParser(FhirContext theContext);
|
||||
public abstract IParser newParser(final FhirContext theContext);
|
||||
|
||||
public static EncodingEnum detectEncoding(String theBody) {
|
||||
public static EncodingEnum detectEncoding(final String theBody) {
|
||||
EncodingEnum retVal = detectEncodingNoDefault(theBody);
|
||||
retVal = ObjectUtils.defaultIfNull(retVal, EncodingEnum.XML);
|
||||
return retVal;
|
||||
|
@ -158,7 +167,7 @@ public enum EncodingEnum {
|
|||
* even if the "+fhir" part is missing from the expected content type.
|
||||
* </p>
|
||||
*/
|
||||
public static EncodingEnum forContentType(String theContentType) {
|
||||
public static EncodingEnum forContentType(final String theContentType) {
|
||||
String contentTypeSplitted = getTypeWithoutCharset(theContentType);
|
||||
if (contentTypeSplitted == null) {
|
||||
return null;
|
||||
|
@ -177,7 +186,7 @@ public enum EncodingEnum {
|
|||
*
|
||||
* @see #forContentType(String)
|
||||
*/
|
||||
public static EncodingEnum forContentTypeStrict(String theContentType) {
|
||||
public static EncodingEnum forContentTypeStrict(final String theContentType) {
|
||||
String contentTypeSplitted = getTypeWithoutCharset(theContentType);
|
||||
if (contentTypeSplitted == null) {
|
||||
return null;
|
||||
|
@ -186,7 +195,7 @@ public enum EncodingEnum {
|
|||
}
|
||||
}
|
||||
|
||||
private static String getTypeWithoutCharset(String theContentType) {
|
||||
private static String getTypeWithoutCharset(final String theContentType) {
|
||||
if (theContentType == null) {
|
||||
return null;
|
||||
} else {
|
||||
|
@ -198,7 +207,7 @@ public enum EncodingEnum {
|
|||
/**
|
||||
* Is the given type a FHIR legacy (pre-DSTU3) content type?
|
||||
*/
|
||||
public static boolean isLegacy(String theContentType) {
|
||||
public static boolean isLegacy(final String theContentType) {
|
||||
String contentTypeSplitted = getTypeWithoutCharset(theContentType);
|
||||
if (contentTypeSplitted == null) {
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package ca.uhn.fhir.util.rdf;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 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 org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.commons.io.output.WriterOutputStream;
|
||||
import org.apache.jena.graph.Triple;
|
||||
import org.apache.jena.rdf.model.Model;
|
||||
import org.apache.jena.rdf.model.ModelFactory;
|
||||
import org.apache.jena.riot.Lang;
|
||||
import org.apache.jena.riot.system.StreamRDF;
|
||||
import org.apache.jena.riot.system.StreamRDFWriter;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.*;
|
||||
|
||||
public class RDFUtil {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RDFUtil.class);
|
||||
private static final Map<String, Integer> VALID_ENTITY_NAMES;
|
||||
|
||||
static {
|
||||
HashMap<String, Integer> validEntityNames = new HashMap<>(1448);
|
||||
VALID_ENTITY_NAMES = Collections.unmodifiableMap(validEntityNames);
|
||||
}
|
||||
|
||||
public static StreamRDF createRDFWriter(final Writer writer, final Lang lang) {
|
||||
WriterOutputStream wos = new WriterOutputStream(writer, Charset.defaultCharset());
|
||||
return StreamRDFWriter.getWriterStream(wos, lang);
|
||||
}
|
||||
|
||||
public static StreamRDF createRDFReader(final Reader reader, final Lang lang) {
|
||||
ReaderInputStream ris = new ReaderInputStream(reader, Charset.defaultCharset());
|
||||
return StreamRDFWriter.getWriterStream(null, lang);
|
||||
}
|
||||
|
||||
public static Triple triple(String tripleAsTurtle) {
|
||||
Model m = ModelFactory.createDefaultModel();
|
||||
m.read(new StringReader(tripleAsTurtle), "urn:x-base:", "TURTLE");
|
||||
return m.listStatements().next().asTriple();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package ca.uhn.fhir.util.rdf;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.apache.jena.graph.Triple;
|
||||
import org.apache.jena.riot.system.StreamRDF;
|
||||
import org.apache.jena.sparql.core.Quad;
|
||||
|
||||
/**
|
||||
* Wraps another {@link StreamRDF} and attempts to remove duplicate
|
||||
* triples and quads. To maintain streaming, duplicates are only
|
||||
* removed within a sliding window of configurable size. Default
|
||||
* size is 10000 triples and quads.
|
||||
*/
|
||||
public class StreamRDFDedup implements StreamRDF {
|
||||
private final StreamRDF wrapped;
|
||||
private final int windowSize;
|
||||
private final HashSet<Object> tripleAndQuadCache;
|
||||
private final LinkedList<Object> tripleAndQuadList = new LinkedList<Object>();
|
||||
|
||||
public StreamRDFDedup(StreamRDF wrapped) {
|
||||
this(wrapped, 10000);
|
||||
}
|
||||
|
||||
public StreamRDFDedup(StreamRDF wrapped, int windowSize) {
|
||||
this.wrapped = wrapped;
|
||||
this.windowSize = windowSize;
|
||||
// Initial capacity big enough to avoid rehashing
|
||||
this.tripleAndQuadCache = new HashSet<Object>(windowSize * 3 / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
wrapped.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triple(Triple triple) {
|
||||
if (!seen(triple)) {
|
||||
wrapped.triple(triple);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void quad(Quad quad) {
|
||||
if (!seen(quad)) {
|
||||
wrapped.quad(quad);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void base(String base) {
|
||||
wrapped.base(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void prefix(String prefix, String iri) {
|
||||
wrapped.prefix(prefix, iri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
wrapped.finish();
|
||||
}
|
||||
|
||||
private boolean seen(Object tuple) {
|
||||
if (tripleAndQuadCache.contains(tuple)) {
|
||||
return true;
|
||||
}
|
||||
tripleAndQuadCache.add(tuple);
|
||||
tripleAndQuadList.add(tuple);
|
||||
if (tripleAndQuadList.size() > windowSize) {
|
||||
forgetOldest();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void forgetOldest() {
|
||||
tripleAndQuadCache.remove(tripleAndQuadList.removeFirst());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package ca.uhn.fhir.util.rdf;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.apache.jena.atlas.io.IndentedWriter;
|
||||
import org.apache.jena.graph.Triple;
|
||||
import org.apache.jena.riot.system.RiotLib;
|
||||
import org.apache.jena.riot.system.StreamOps;
|
||||
import org.apache.jena.riot.system.StreamRDF;
|
||||
import org.apache.jena.riot.writer.WriterStreamRDFBlocks;
|
||||
import org.apache.jena.riot.writer.WriterStreamRDFPlain;
|
||||
import org.apache.jena.shared.PrefixMapping;
|
||||
import org.apache.jena.shared.impl.PrefixMappingImpl;
|
||||
import org.apache.jena.vocabulary.RDF;
|
||||
|
||||
|
||||
/**
|
||||
* Writes an iterator over triples to N-Triples or Turtle
|
||||
* in a streaming fashion, that is, without needing to hold
|
||||
* the entire thing in memory.
|
||||
* <p>
|
||||
* Instances are single-use.
|
||||
* <p>
|
||||
* There doesn't seem to be a pre-packaged version of this
|
||||
* functionality in Jena/ARQ that doesn't require a Graph or Model.
|
||||
*/
|
||||
public class StreamingRDFWriter {
|
||||
private final OutputStream out;
|
||||
private final Iterator<Triple> triples;
|
||||
private int dedupWindowSize = 10000;
|
||||
|
||||
public StreamingRDFWriter(OutputStream out, Iterator<Triple> triples) {
|
||||
this.out = out;
|
||||
this.triples = triples;
|
||||
}
|
||||
|
||||
public void setDedupWindowSize(int newSize) {
|
||||
this.dedupWindowSize = newSize;
|
||||
}
|
||||
|
||||
public void writeNTriples() {
|
||||
StreamRDF writer = new WriterStreamRDFPlain(new IndentedWriter(out));
|
||||
if (dedupWindowSize > 0) {
|
||||
writer = new StreamRDFDedup(writer, dedupWindowSize);
|
||||
}
|
||||
writer.start();
|
||||
StreamOps.sendTriplesToStream(triples, writer);
|
||||
writer.finish();
|
||||
}
|
||||
|
||||
public void writeTurtle(String baseIRI, PrefixMapping prefixes, boolean writeBase) {
|
||||
// Auto-register RDF prefix so that rdf:type is displayed well
|
||||
// All other prefixes come from the query and should be as author intended
|
||||
prefixes = ensureRDFPrefix(prefixes);
|
||||
|
||||
if (writeBase) {
|
||||
// Jena's streaming Turtle writers don't output base even if it is provided,
|
||||
// so we write it directly.
|
||||
IndentedWriter w = new IndentedWriter(out);
|
||||
RiotLib.writeBase(w, baseIRI);
|
||||
w.flush();
|
||||
}
|
||||
|
||||
StreamRDF writer = new WriterStreamRDFBlocks(out);
|
||||
if (dedupWindowSize > 0) {
|
||||
writer = new StreamRDFDedup(writer, dedupWindowSize);
|
||||
}
|
||||
writer.start();
|
||||
writer.base(baseIRI);
|
||||
for (Entry<String, String> e : prefixes.getNsPrefixMap().entrySet()) {
|
||||
writer.prefix(e.getKey(), e.getValue());
|
||||
}
|
||||
StreamOps.sendTriplesToStream(triples, writer);
|
||||
writer.finish();
|
||||
}
|
||||
|
||||
private PrefixMapping ensureRDFPrefix(PrefixMapping prefixes) {
|
||||
// Some prefix already registered for the RDF namespace -- good enough
|
||||
if (prefixes.getNsURIPrefix(RDF.getURI()) != null) return prefixes;
|
||||
// rdf: is registered to something else -- give up
|
||||
if (prefixes.getNsPrefixURI("rdf") != null) return prefixes;
|
||||
// Register rdf:
|
||||
PrefixMapping newPrefixes = new PrefixMappingImpl();
|
||||
newPrefixes.setNsPrefixes(prefixes);
|
||||
newPrefixes.setNsPrefix("rdf", RDF.getURI());
|
||||
return newPrefixes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,406 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.core.IsNot.not;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class RDFParserR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RDFParserR4Test.class);
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
|
||||
/*
|
||||
private Bundle createBundleWithPatient() {
|
||||
Bundle b = new Bundle();
|
||||
b.setId("BUNDLEID");
|
||||
b.getMeta().addProfile("http://FOO");
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("PATIENTID");
|
||||
p.getMeta().addProfile("http://BAR");
|
||||
p.addName().addGiven("GIVEN");
|
||||
b.addEntry().setResource(p);
|
||||
return b;
|
||||
}
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void testDontStripVersions() {
|
||||
/*
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
ctx.getParserOptions().setDontStripVersionsFromReferencesAtPaths("QuestionnaireResponse.questionnaire");
|
||||
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.getQuestionnaireElement().setValueAsString("Questionnaire/123/_history/456");
|
||||
|
||||
String output = ctx.newRDFParser().setPrettyPrint(true).encodeResourceToString(qr);
|
||||
ourLog.info(output);
|
||||
|
||||
assertThat(output, containsString("\"Questionnaire/123/_history/456\""));
|
||||
*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateContainedResourcesNotOutputtedTwice() {
|
||||
/*MedicationDispense md = new MedicationDispense();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
md.addAuthorizingPrescription().setResource(mr);
|
||||
|
||||
Medication med = new Medication();
|
||||
md.setMedication(new Reference(med));
|
||||
mr.setMedication(new Reference(med));
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(md);
|
||||
ourLog.info(encoded);
|
||||
|
||||
int idx = encoded.indexOf("\"Medication\"");
|
||||
assertNotEquals(-1, idx);
|
||||
|
||||
idx = encoded.indexOf("\"Medication\"", idx + 1);
|
||||
assertEquals(-1, idx);
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* See #814
|
||||
*/
|
||||
@Test
|
||||
public void testDuplicateContainedResourcesNotOutputtedTwiceWithManualIds() {
|
||||
/*
|
||||
MedicationDispense md = new MedicationDispense();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.setId("#MR");
|
||||
md.addAuthorizingPrescription().setResource(mr);
|
||||
|
||||
Medication med = new Medication();
|
||||
med.setId("#MED");
|
||||
md.setMedication(new Reference(med));
|
||||
mr.setMedication(new Reference(med));
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(md);
|
||||
ourLog.info(encoded);
|
||||
|
||||
int idx = encoded.indexOf("\"Medication\"");
|
||||
assertNotEquals(-1, idx);
|
||||
|
||||
idx = encoded.indexOf("\"Medication\"", idx + 1);
|
||||
assertEquals(-1, idx);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* See #814
|
||||
*/
|
||||
@Test
|
||||
public void testDuplicateContainedResourcesNotOutputtedTwiceWithManualIdsAndManualAddition() {
|
||||
/*
|
||||
MedicationDispense md = new MedicationDispense();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.setId("#MR");
|
||||
md.addAuthorizingPrescription().setResource(mr);
|
||||
|
||||
Medication med = new Medication();
|
||||
med.setId("#MED");
|
||||
|
||||
Reference medRef = new Reference();
|
||||
medRef.setReference("#MED");
|
||||
md.setMedication(medRef);
|
||||
mr.setMedication(medRef);
|
||||
|
||||
md.getContained().add(mr);
|
||||
md.getContained().add(med);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(md);
|
||||
ourLog.info(encoded);
|
||||
|
||||
int idx = encoded.indexOf("\"Medication\"");
|
||||
assertNotEquals(-1, idx);
|
||||
|
||||
idx = encoded.indexOf("\"Medication\"", idx + 1);
|
||||
assertEquals(-1, idx);
|
||||
*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeAndParseUnicodeCharacterInNarrative() {
|
||||
/*
|
||||
Patient p = new Patient();
|
||||
p.getText().getDiv().setValueAsString("<div>Copy © 1999</div>");
|
||||
String encoded = ourCtx.newRDFParser().encodeResourceToString(p);
|
||||
ourLog.info(encoded);
|
||||
|
||||
p = (Patient) ourCtx.newRDFParser().parseResource(encoded);
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">Copy © 1999</div>", p.getText().getDivAsString());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocalFirst() {
|
||||
/*
|
||||
Observation obs = new Observation();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.setId("#1");
|
||||
pt.addName().setFamily("FAM");
|
||||
obs.getSubject().setReference("#1");
|
||||
obs.getContained().add(pt);
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.setStatus(Encounter.EncounterStatus.ARRIVED);
|
||||
obs.getEncounter().setResource(enc);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
obs = ourCtx.newRDFParser().parseResource(Observation.class, encoded);
|
||||
assertEquals("#1", obs.getContained().get(0).getId());
|
||||
assertEquals("#2", obs.getContained().get(1).getId());
|
||||
|
||||
pt = (Patient) obs.getSubject().getResource();
|
||||
assertEquals("FAM", pt.getNameFirstRep().getFamily());
|
||||
|
||||
enc = (Encounter) obs.getEncounter().getResource();
|
||||
assertEquals(Encounter.EncounterStatus.ARRIVED, enc.getStatus());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocalLast() {
|
||||
/*
|
||||
Observation obs = new Observation();
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily("FAM");
|
||||
obs.getSubject().setResource(pt);
|
||||
|
||||
Encounter enc = new Encounter();
|
||||
enc.setId("#1");
|
||||
enc.setStatus(Encounter.EncounterStatus.ARRIVED);
|
||||
obs.getEncounter().setReference("#1");
|
||||
obs.getContained().add(enc);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
obs = ourCtx.newRDFParser().parseResource(Observation.class, encoded);
|
||||
assertEquals("#1", obs.getContained().get(0).getId());
|
||||
assertEquals("#2", obs.getContained().get(1).getId());
|
||||
|
||||
pt = (Patient) obs.getSubject().getResource();
|
||||
assertEquals("FAM", pt.getNameFirstRep().getFamily());
|
||||
|
||||
enc = (Encounter) obs.getEncounter().getResource();
|
||||
assertEquals(Encounter.EncounterStatus.ARRIVED, enc.getStatus());
|
||||
*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocalLast2() {
|
||||
/*
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
Practitioner pract = new Practitioner().setActive(true);
|
||||
mr.getRequester().setResource(pract);
|
||||
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(mr);
|
||||
ourLog.info(encoded);
|
||||
mr = ourCtx.newRDFParser().parseResource(MedicationRequest.class, encoded);
|
||||
|
||||
mr.setMedication(new Reference(new Medication().setStatus(Medication.MedicationStatus.ACTIVE)));
|
||||
encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(mr);
|
||||
ourLog.info(encoded);
|
||||
mr = ourCtx.newRDFParser().parseResource(MedicationRequest.class, encoded);
|
||||
|
||||
assertEquals("#2", mr.getContained().get(0).getId());
|
||||
assertEquals("#1", mr.getContained().get(1).getId());
|
||||
*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExcludeNothing() {
|
||||
/*
|
||||
IParser parser = ourCtx.newRDFParser().setPrettyPrint(true);
|
||||
Set<String> excludes = new HashSet<>();
|
||||
// excludes.add("*.id");
|
||||
parser.setDontEncodeElements(excludes);
|
||||
|
||||
Bundle b = createBundleWithPatient();
|
||||
|
||||
String encoded = parser.encodeResourceToString(b);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, containsString("BUNDLEID"));
|
||||
assertThat(encoded, containsString("http://FOO"));
|
||||
assertThat(encoded, containsString("PATIENTID"));
|
||||
assertThat(encoded, containsString("http://BAR"));
|
||||
assertThat(encoded, containsString("GIVEN"));
|
||||
|
||||
b = parser.parseResource(Bundle.class, encoded);
|
||||
|
||||
assertEquals("BUNDLEID", b.getIdElement().getIdPart());
|
||||
assertEquals("Patient/PATIENTID", b.getEntry().get(0).getResource().getId());
|
||||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testExcludeRootStuff() {
|
||||
/*
|
||||
IParser parser = ourCtx.newRDFParser().setPrettyPrint(true);
|
||||
|
||||
Set<String> excludes = new HashSet<>();
|
||||
excludes.add("id");
|
||||
excludes.add("meta");
|
||||
parser.setDontEncodeElements(excludes);
|
||||
|
||||
Bundle b = createBundleWithPatient();
|
||||
|
||||
String encoded = parser.encodeResourceToString(b);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, not(containsString("BUNDLEID")));
|
||||
assertThat(encoded, not(containsString("http://FOO")));
|
||||
assertThat(encoded, (containsString("PATIENTID")));
|
||||
assertThat(encoded, (containsString("http://BAR")));
|
||||
assertThat(encoded, containsString("GIVEN"));
|
||||
|
||||
b = parser.parseResource(Bundle.class, encoded);
|
||||
|
||||
assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
|
||||
assertEquals("Patient/PATIENTID", b.getEntry().get(0).getResource().getId());
|
||||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExcludeStarDotStuff() {
|
||||
/*
|
||||
IParser parser = ourCtx.newRDFParser().setPrettyPrint(true);
|
||||
Set<String> excludes = new HashSet<>();
|
||||
excludes.add("*.id");
|
||||
excludes.add("*.meta");
|
||||
parser.setDontEncodeElements(excludes);
|
||||
|
||||
Bundle b = createBundleWithPatient();
|
||||
|
||||
String encoded = parser.encodeResourceToString(b);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, not(containsString("BUNDLEID")));
|
||||
assertThat(encoded, not(containsString("http://FOO")));
|
||||
assertThat(encoded, not(containsString("PATIENTID")));
|
||||
assertThat(encoded, not(containsString("http://BAR")));
|
||||
assertThat(encoded, containsString("GIVEN"));
|
||||
|
||||
b = parser.parseResource(Bundle.class, encoded);
|
||||
|
||||
assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
|
||||
assertNotEquals("Patient/PATIENTID", b.getEntry().get(0).getResource().getId());
|
||||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test that long JSON strings don't get broken up
|
||||
*/
|
||||
@Test
|
||||
public void testNoBreakInLongString() {
|
||||
/*
|
||||
String longString = StringUtils.leftPad("", 100000, 'A');
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(longString);
|
||||
String encoded = ourCtx.newRDFParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
|
||||
assertThat(encoded, containsString(longString));
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseAndEncodeExtensionWithValueWithExtension() {
|
||||
/*
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"extension\": [\n" +
|
||||
" {\n" +
|
||||
" \"url\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/BirthWeight\",\n" +
|
||||
" \"_valueDecimal\": {\n" +
|
||||
" \"extension\": [\n" +
|
||||
" {\n" +
|
||||
" \"url\": \"http://www.hl7.org/fhir/extension-data-absent-reason.html\",\n" +
|
||||
" \"valueCoding\": {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/ValueSet/birthweight\",\n" +
|
||||
" \"code\": \"Underweight\",\n" +
|
||||
" \"userSelected\": false\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/EuroPrevallStudySubjects\",\n" +
|
||||
" \"value\": \"1\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"gender\": \"female\"\n" +
|
||||
"}";
|
||||
|
||||
IParser jsonParser = ourCtx.newRDFParser();
|
||||
IParser xmlParser = ourCtx.newXmlParser();
|
||||
jsonParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
|
||||
xmlParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
|
||||
|
||||
Patient parsed = jsonParser.parseResource(Patient.class, input);
|
||||
|
||||
ourLog.info(jsonParser.setPrettyPrint(true).encodeResourceToString(parsed));
|
||||
assertThat(xmlParser.encodeResourceToString(parsed), containsString("Underweight"));
|
||||
assertThat(jsonParser.encodeResourceToString(parsed), containsString("Underweight"));
|
||||
*/
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseExtensionOnPrimitive() throws IOException {
|
||||
/*
|
||||
String input = IOUtils.toString(JsonParserR4Test.class.getResourceAsStream("/extension-on-line.txt"), Constants.CHARSET_UTF8);
|
||||
IParser parser = ourCtx.newRDFParser().setPrettyPrint(true);
|
||||
Patient pt = parser.parseResource(Patient.class, input);
|
||||
|
||||
StringType line0 = pt.getAddressFirstRep().getLine().get(0);
|
||||
assertEquals("535 Sheppard Avenue West, Unit 1907", line0.getValue());
|
||||
Extension houseNumberExt = line0.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-houseNumber");
|
||||
assertEquals("535", ((StringType) houseNumberExt.getValue()).getValue());
|
||||
*/
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.json.*;
|
||||
import org.junit.Test;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
public class RDFParserTest {
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RDFParserTest.class);
|
||||
|
||||
private static final String TEST_STRUCTURELOADING_DATA =
|
||||
"{" +
|
||||
" \"resourceType\":\"Organization\"," +
|
||||
" \"id\":\"11111\"," +
|
||||
" \"meta\":{" +
|
||||
" \"lastUpdated\":\"3900-09-20T10:10:10.000-07:00\"" +
|
||||
" }," +
|
||||
" \"identifier\":[" +
|
||||
" {" +
|
||||
" \"value\":\"15250\"" +
|
||||
" }" +
|
||||
" ]," +
|
||||
" \"type\":{" +
|
||||
" \"coding\":[" +
|
||||
" {" +
|
||||
" \"system\":\"http://test\"," +
|
||||
" \"code\":\"ins\"," +
|
||||
" \"display\":\"General Ledger System\"," +
|
||||
" \"userSelected\":false" +
|
||||
" }" +
|
||||
" ]" +
|
||||
" }," +
|
||||
" \"name\":\"Acme Investments\"" +
|
||||
"}";
|
||||
|
||||
@Test
|
||||
public void testDontStripVersions() {
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
ctx.getParserOptions().setDontStripVersionsFromReferencesAtPaths("QuestionnaireResponse.questionnaire");
|
||||
|
||||
//QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
//qr.getQuestionnaireElement().setValueAsString("Questionnaire/123/_history/456");
|
||||
|
||||
//String output = ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(qr);
|
||||
//ourLog.info(output);
|
||||
|
||||
//assertThat(output, containsString("\"Questionnaire/123/_history/456\""));
|
||||
}
|
||||
|
||||
}
|
5
pom.xml
5
pom.xml
|
@ -976,6 +976,11 @@
|
|||
<artifactId>httpcore</artifactId>
|
||||
<version>${httpcore_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.jena</groupId>
|
||||
<artifactId>apache-jena-libs</artifactId>
|
||||
<version>3.11.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-highlighter</artifactId>
|
||||
|
|
Loading…
Reference in New Issue