Enhanced elements (#1192)
Squashed merge: Add elements exclude mode * Start working on elements enhancement * Work on elements projection * Work on elements filter * Feature is now working * Just some cleanup * Address compile issues
This commit is contained in:
parent
447c394cac
commit
e401ec86e4
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.parser;
|
|||
* 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.
|
||||
|
@ -30,11 +30,13 @@ import ca.uhn.fhir.util.UrlUtil;
|
|||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -47,11 +49,9 @@ public abstract class BaseParser implements IParser {
|
|||
private ContainedResources myContainedResources;
|
||||
private boolean myEncodeElementsAppliesToChildResourcesOnly;
|
||||
private FhirContext myContext;
|
||||
private Set<String> myDontEncodeElements;
|
||||
private boolean myDontEncodeElementsIncludesStars;
|
||||
private Set<String> myEncodeElements;
|
||||
private List<ElementsPath> myDontEncodeElements;
|
||||
private List<ElementsPath> myEncodeElements;
|
||||
private Set<String> myEncodeElementsAppliesToResourceTypes;
|
||||
private boolean myEncodeElementsIncludesStars;
|
||||
private IIdType myEncodeForceResourceId;
|
||||
private IParserErrorHandler myErrorHandler;
|
||||
private boolean myOmitResourceId;
|
||||
|
@ -65,20 +65,19 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theParserErrorHandler
|
||||
*/
|
||||
public BaseParser(FhirContext theContext, IParserErrorHandler theParserErrorHandler) {
|
||||
myContext = theContext;
|
||||
myErrorHandler = theParserErrorHandler;
|
||||
}
|
||||
|
||||
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final boolean theSubResource, final CompositeChildElement theParent) {
|
||||
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final CompositeChildElement theParent, EncodeContext theEncodeContext) {
|
||||
|
||||
BaseRuntimeElementCompositeDefinition<?> elementDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(theCompositeElement.getClass());
|
||||
final List<BaseRuntimeChildDefinition> children = elementDef.getChildrenAndExtension();
|
||||
|
||||
return new Iterable<BaseParser.CompositeChildElement>() {
|
||||
|
||||
@Override
|
||||
public Iterator<CompositeChildElement> iterator() {
|
||||
|
||||
|
@ -106,7 +105,7 @@ public abstract class BaseParser implements IParser {
|
|||
return false;
|
||||
}
|
||||
|
||||
myNext = new CompositeChildElement(theParent, myChildrenIter.next(), theSubResource);
|
||||
myNext = new CompositeChildElement(theParent, myChildrenIter.next(), theEncodeContext);
|
||||
|
||||
/*
|
||||
* There are lots of reasons we might skip encoding a particular child
|
||||
|
@ -181,8 +180,6 @@ public abstract class BaseParser implements IParser {
|
|||
theContained.getExistingIdToContainedResource().put(nextId, next);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no resources to contain
|
||||
}
|
||||
|
||||
List<IBaseReference> allReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, IBaseReference.class);
|
||||
|
@ -279,7 +276,7 @@ public abstract class BaseParser implements IParser {
|
|||
return ref.getValue();
|
||||
}
|
||||
|
||||
protected abstract void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException;
|
||||
protected abstract void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException, DataFormatException;
|
||||
|
||||
protected abstract <T extends IBaseResource> T doParseResource(Class<T> theResourceType, Reader theReader) throws DataFormatException;
|
||||
|
||||
|
@ -296,15 +293,27 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
@Override
|
||||
public final void encodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException {
|
||||
EncodeContext encodeContext = new EncodeContext();
|
||||
|
||||
encodeResourceToWriter(theResource, theWriter, encodeContext);
|
||||
}
|
||||
|
||||
protected void encodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
Validate.notNull(theResource, "theResource can not be null");
|
||||
Validate.notNull(theWriter, "theWriter can not be null");
|
||||
Validate.notNull(theEncodeContext, "theEncodeContext can not be null");
|
||||
|
||||
if (theResource.getStructureFhirVersionEnum() != myContext.getVersion().getVersion()) {
|
||||
throw new IllegalArgumentException(
|
||||
"This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
doEncodeResourceToWriter(theResource, theWriter);
|
||||
String resourceName = myContext.getResourceDefinition(theResource).getName();
|
||||
theEncodeContext.pushPath(resourceName, true);
|
||||
|
||||
doEncodeResourceToWriter(theResource, theWriter, theEncodeContext);
|
||||
|
||||
theEncodeContext.popPath();
|
||||
}
|
||||
|
||||
private void filterCodingsWithNoCodeOrSystem(List<? extends IBaseCoding> tagList) {
|
||||
|
@ -392,43 +401,32 @@ public abstract class BaseParser implements IParser {
|
|||
return myDontStripVersionsFromReferencesAtPaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #setEncodeElements(Set)}
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getEncodeElements() {
|
||||
return myEncodeElements;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncodeElements(Set<String> theEncodeElements) {
|
||||
myEncodeElementsIncludesStars = false;
|
||||
|
||||
if (theEncodeElements == null || theEncodeElements.isEmpty()) {
|
||||
myEncodeElements = null;
|
||||
} else {
|
||||
myEncodeElements = theEncodeElements;
|
||||
for (String next : theEncodeElements) {
|
||||
if (next.startsWith("*.")) {
|
||||
myEncodeElementsIncludesStars = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See {@link #setEncodeElementsAppliesToResourceTypes(Set)}
|
||||
*/
|
||||
@Override
|
||||
public Set<String> getEncodeElementsAppliesToResourceTypes() {
|
||||
return myEncodeElementsAppliesToResourceTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncodeElementsAppliesToResourceTypes(Set<String> theEncodeElementsAppliesToResourceTypes) {
|
||||
if (theEncodeElementsAppliesToResourceTypes == null || theEncodeElementsAppliesToResourceTypes.isEmpty()) {
|
||||
myEncodeElementsAppliesToResourceTypes = null;
|
||||
} else {
|
||||
myEncodeElementsAppliesToResourceTypes = theEncodeElementsAppliesToResourceTypes;
|
||||
myEncodeElements = theEncodeElements
|
||||
.stream()
|
||||
.map(ElementsPath::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
myEncodeElementsAppliesToResourceTypes = new HashSet<>();
|
||||
for (String next : myEncodeElements.stream().map(t -> t.getPath().get(0).getName()).collect(Collectors.toList())) {
|
||||
if (next.startsWith("*")) {
|
||||
myEncodeElementsAppliesToResourceTypes = null;
|
||||
break;
|
||||
}
|
||||
int dotIdx = next.indexOf('.');
|
||||
if (dotIdx == -1) {
|
||||
myEncodeElementsAppliesToResourceTypes.add(next);
|
||||
} else {
|
||||
myEncodeElementsAppliesToResourceTypes.add(next.substring(0, dotIdx));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,7 +446,7 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
protected List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> getExtensionMetadataKeys(IResource resource) {
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys = new ArrayList<Map.Entry<ResourceMetadataKeyEnum<?>, Object>>();
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys = new ArrayList<>();
|
||||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> entry : resource.getResourceMetadata().entrySet()) {
|
||||
if (entry.getKey() instanceof ResourceMetadataKeyEnum.ExtensionResourceMetadataKey) {
|
||||
extensionMetadataKeys.add(entry);
|
||||
|
@ -466,9 +464,9 @@ public abstract class BaseParser implements IParser {
|
|||
return url;
|
||||
}
|
||||
|
||||
protected TagList getMetaTagsForEncoding(IResource theIResource) {
|
||||
protected TagList getMetaTagsForEncoding(IResource theIResource, EncodeContext theEncodeContext) {
|
||||
TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(theIResource);
|
||||
if (shouldAddSubsettedTag()) {
|
||||
if (shouldAddSubsettedTag(theEncodeContext)) {
|
||||
tags = new TagList(tags);
|
||||
tags.add(new Tag(getSubsettedCodeSystem(), Constants.TAG_SUBSETTED_CODE, subsetDescription()));
|
||||
}
|
||||
|
@ -709,7 +707,7 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
protected List<? extends IBase> preProcessValues(BaseRuntimeChildDefinition theMetaChildUncast, IBaseResource theResource, List<? extends IBase> theValues,
|
||||
CompositeChildElement theCompositeChildElement) {
|
||||
CompositeChildElement theCompositeChildElement, EncodeContext theEncodeContext) {
|
||||
if (myContext.getVersion().getVersion().isRi()) {
|
||||
|
||||
/*
|
||||
|
@ -754,7 +752,7 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
if (shouldAddSubsettedTag()) {
|
||||
if (shouldAddSubsettedTag(theEncodeContext)) {
|
||||
IBaseCoding coding = metaValue.addTag();
|
||||
coding.setCode(Constants.TAG_SUBSETTED_CODE);
|
||||
coding.setSystem(getSubsettedCodeSystem());
|
||||
|
@ -806,16 +804,13 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
@Override
|
||||
public void setDontEncodeElements(Set<String> theDontEncodeElements) {
|
||||
myDontEncodeElementsIncludesStars = false;
|
||||
if (theDontEncodeElements == null || theDontEncodeElements.isEmpty()) {
|
||||
myDontEncodeElements = null;
|
||||
} else {
|
||||
myDontEncodeElements = theDontEncodeElements;
|
||||
for (String next : theDontEncodeElements) {
|
||||
if (next.startsWith("*.")) {
|
||||
myDontEncodeElementsIncludesStars = true;
|
||||
}
|
||||
}
|
||||
myDontEncodeElements = theDontEncodeElements
|
||||
.stream()
|
||||
.map(ElementsPath::new)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -885,22 +880,39 @@ public abstract class BaseParser implements IParser {
|
|||
return this;
|
||||
}
|
||||
|
||||
protected boolean shouldAddSubsettedTag() {
|
||||
return isSummaryMode() || isSuppressNarratives() || getEncodeElements() != null;
|
||||
protected boolean shouldAddSubsettedTag(EncodeContext theEncodeContext) {
|
||||
if (isSummaryMode()) {
|
||||
return true;
|
||||
}
|
||||
if (isSuppressNarratives()) {
|
||||
return true;
|
||||
}
|
||||
if (myEncodeElements != null) {
|
||||
if (isEncodeElementsAppliesToChildResourcesOnly() && theEncodeContext.getResourcePath().size() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String currentResourceName = theEncodeContext.getResourcePath().get(theEncodeContext.getResourcePath().size() - 1).getName();
|
||||
if (myEncodeElementsAppliesToResourceTypes == null || myEncodeElementsAppliesToResourceTypes.contains(currentResourceName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean shouldEncodeResourceId(IBaseResource theResource, boolean theSubResource) {
|
||||
protected boolean shouldEncodeResourceId(IBaseResource theResource, EncodeContext theEncodeContext) {
|
||||
boolean retVal = true;
|
||||
if (isOmitResourceId()) {
|
||||
retVal = false;
|
||||
} else {
|
||||
if (myDontEncodeElements != null) {
|
||||
String resourceName = myContext.getResourceDefinition(theResource).getName();
|
||||
if (myDontEncodeElements.contains(resourceName + ".id")) {
|
||||
if (myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath(resourceName + ".id"))) {
|
||||
retVal = false;
|
||||
} else if (myDontEncodeElements.contains("*.id")) {
|
||||
} else if (myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath("*.id"))) {
|
||||
retVal = false;
|
||||
} else if (theSubResource == false && myDontEncodeElements.contains("id")) {
|
||||
} else if (theEncodeContext.getResourcePath().size() == 1 && myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath("id"))) {
|
||||
retVal = false;
|
||||
}
|
||||
}
|
||||
|
@ -914,9 +926,11 @@ public abstract class BaseParser implements IParser {
|
|||
protected boolean shouldEncodeResourceMeta(IResource theResource) {
|
||||
if (myDontEncodeElements != null) {
|
||||
String resourceName = myContext.getResourceDefinition(theResource).getName();
|
||||
if (myDontEncodeElements.contains(resourceName + ".meta")) {
|
||||
if (myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath(resourceName + ".meta"))) {
|
||||
return false;
|
||||
} else return !myDontEncodeElements.contains("*.meta");
|
||||
} else {
|
||||
return myDontEncodeElements.stream().anyMatch(t -> t.startsWithPath("*.meta"));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -965,13 +979,13 @@ public abstract class BaseParser implements IParser {
|
|||
private final BaseRuntimeChildDefinition myDef;
|
||||
private final CompositeChildElement myParent;
|
||||
private final RuntimeResourceDefinition myResDef;
|
||||
private final boolean mySubResource;
|
||||
private final EncodeContext myEncodeContext;
|
||||
|
||||
public CompositeChildElement(CompositeChildElement theParent, BaseRuntimeChildDefinition theDef, boolean theSubResource) {
|
||||
public CompositeChildElement(CompositeChildElement theParent, BaseRuntimeChildDefinition theDef, EncodeContext theEncodeContext) {
|
||||
myDef = theDef;
|
||||
myParent = theParent;
|
||||
myResDef = null;
|
||||
mySubResource = theSubResource;
|
||||
myEncodeContext = theEncodeContext;
|
||||
|
||||
if (ourLog.isTraceEnabled()) {
|
||||
if (theParent != null) {
|
||||
|
@ -986,11 +1000,11 @@ public abstract class BaseParser implements IParser {
|
|||
|
||||
}
|
||||
|
||||
public CompositeChildElement(RuntimeResourceDefinition theResDef, boolean theSubResource) {
|
||||
public CompositeChildElement(RuntimeResourceDefinition theResDef, EncodeContext theEncodeContext) {
|
||||
myResDef = theResDef;
|
||||
myDef = null;
|
||||
myParent = null;
|
||||
mySubResource = theSubResource;
|
||||
myEncodeContext = theEncodeContext;
|
||||
}
|
||||
|
||||
private void addParent(CompositeChildElement theParent, StringBuilder theB) {
|
||||
|
@ -1038,71 +1052,75 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean checkIfParentShouldBeEncodedAndBuildPath(StringBuilder thePathBuilder, boolean theStarPass) {
|
||||
Set<String> encodeElements = myEncodeElements;
|
||||
if (encodeElements != null && encodeElements.isEmpty() == false) {
|
||||
if (isEncodeElementsAppliesToChildResourcesOnly() && !mySubResource) {
|
||||
encodeElements = null;
|
||||
}
|
||||
private boolean checkIfParentShouldBeEncodedAndBuildPath() {
|
||||
List<ElementsPath> encodeElements = myEncodeElements;
|
||||
|
||||
String currentResourceName = myEncodeContext.getResourcePath().get(myEncodeContext.getResourcePath().size() - 1).getName();
|
||||
if (myEncodeElementsAppliesToResourceTypes != null && !myEncodeElementsAppliesToResourceTypes.contains(currentResourceName)) {
|
||||
encodeElements = null;
|
||||
}
|
||||
return checkIfPathMatchesForEncoding(thePathBuilder, theStarPass, myEncodeElementsAppliesToResourceTypes, encodeElements, true);
|
||||
}
|
||||
|
||||
private boolean checkIfParentShouldNotBeEncodedAndBuildPath(StringBuilder thePathBuilder, boolean theStarPass) {
|
||||
return checkIfPathMatchesForEncoding(thePathBuilder, theStarPass, null, myDontEncodeElements, false);
|
||||
}
|
||||
boolean retVal = checkIfPathMatchesForEncoding(encodeElements, true);
|
||||
|
||||
private boolean checkIfPathMatchesForEncoding(StringBuilder thePathBuilder, boolean theStarPass, Set<String> theResourceTypes, Set<String> theElements, boolean theCheckingForWhitelist) {
|
||||
if (myResDef != null) {
|
||||
if (theResourceTypes != null) {
|
||||
if (!theResourceTypes.contains(myResDef.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (theStarPass) {
|
||||
thePathBuilder.append('*');
|
||||
} else {
|
||||
thePathBuilder.append(myResDef.getName());
|
||||
}
|
||||
if (theElements == null) {
|
||||
return true;
|
||||
}
|
||||
return theElements.contains(thePathBuilder.toString());
|
||||
} else if (myParent != null) {
|
||||
boolean parentCheck;
|
||||
if (theCheckingForWhitelist) {
|
||||
parentCheck = myParent.checkIfParentShouldBeEncodedAndBuildPath(thePathBuilder, theStarPass);
|
||||
} else {
|
||||
parentCheck = myParent.checkIfParentShouldNotBeEncodedAndBuildPath(thePathBuilder, theStarPass);
|
||||
}
|
||||
if (parentCheck) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (myDef != null) {
|
||||
if (myDef.getMin() > 0) {
|
||||
if (theElements.contains("*.(mandatory)")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
thePathBuilder.append('.');
|
||||
thePathBuilder.append(myDef.getElementName());
|
||||
String currentPath = thePathBuilder.toString();
|
||||
boolean retVal = theElements.contains(currentPath);
|
||||
int dotIdx = currentPath.indexOf('.');
|
||||
if (!retVal) {
|
||||
if (dotIdx != -1 && theElements.contains(currentPath.substring(dotIdx + 1))) {
|
||||
if (!myParent.isSubResource()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
/*
|
||||
* We force the meta tag to be encoded even if it's not specified as an element in the
|
||||
* elements filter, specifically because we'll need it in order to automatically add
|
||||
* the SUBSETTED tag
|
||||
*/
|
||||
if (!retVal) {
|
||||
if ("meta".equals(myEncodeContext.getLeafResourcePathFirstField()) && shouldAddSubsettedTag(myEncodeContext)) {
|
||||
// The next element is a child of the <meta> element
|
||||
retVal = true;
|
||||
} else if ("meta".equals(myDef.getElementName()) && shouldAddSubsettedTag(myEncodeContext)) {
|
||||
// The next element is the <meta> element
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private boolean checkIfParentShouldNotBeEncodedAndBuildPath() {
|
||||
return checkIfPathMatchesForEncoding(myDontEncodeElements, false);
|
||||
}
|
||||
|
||||
private boolean checkIfPathMatchesForEncoding(List<ElementsPath> theElements, boolean theCheckingForEncodeElements) {
|
||||
|
||||
boolean retVal = false;
|
||||
myEncodeContext.pushPath(myDef.getElementName(), false);
|
||||
|
||||
if (theCheckingForEncodeElements && isEncodeElementsAppliesToChildResourcesOnly() && myEncodeContext.getResourcePath().size() < 2) {
|
||||
retVal = true;
|
||||
} else if (theElements == null) {
|
||||
retVal = true;
|
||||
} else {
|
||||
EncodeContextPath currentResourcePath = myEncodeContext.getCurrentResourcePath();
|
||||
ourLog.trace("Current resource path: {}", currentResourcePath);
|
||||
for (ElementsPath next : theElements) {
|
||||
|
||||
if (next.startsWith(currentResourcePath)) {
|
||||
if (theCheckingForEncodeElements || next.getPath().size() == currentResourcePath.getPath().size()) {
|
||||
retVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next.getPath().get(next.getPath().size() - 1).getName().equals("(mandatory)")) {
|
||||
if (myDef.getMin() > 0) {
|
||||
retVal = true;
|
||||
break;
|
||||
}
|
||||
if (currentResourcePath.getPath().size() > next.getPath().size()) {
|
||||
retVal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
myEncodeContext.popPath();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public BaseRuntimeChildDefinition getDef() {
|
||||
|
@ -1113,38 +1131,189 @@ public abstract class BaseParser implements IParser {
|
|||
return myParent;
|
||||
}
|
||||
|
||||
public RuntimeResourceDefinition getResDef() {
|
||||
return myResDef;
|
||||
}
|
||||
|
||||
private boolean isSubResource() {
|
||||
return mySubResource;
|
||||
}
|
||||
|
||||
public boolean shouldBeEncoded() {
|
||||
boolean retVal = true;
|
||||
if (myEncodeElements != null) {
|
||||
retVal = checkIfParentShouldBeEncodedAndBuildPath(new StringBuilder(), false);
|
||||
if (retVal == false && myEncodeElementsIncludesStars) {
|
||||
retVal = checkIfParentShouldBeEncodedAndBuildPath(new StringBuilder(), true);
|
||||
}
|
||||
retVal = checkIfParentShouldBeEncodedAndBuildPath();
|
||||
}
|
||||
if (retVal && myDontEncodeElements != null) {
|
||||
retVal = !checkIfParentShouldNotBeEncodedAndBuildPath(new StringBuilder(), false);
|
||||
if (retVal && myDontEncodeElementsIncludesStars) {
|
||||
retVal = !checkIfParentShouldNotBeEncodedAndBuildPath(new StringBuilder(), true);
|
||||
}
|
||||
retVal = !checkIfParentShouldNotBeEncodedAndBuildPath();
|
||||
}
|
||||
// if (retVal == false && myEncodeElements.contains("*.(mandatory)")) {
|
||||
// if (myDef.getMin() > 0) {
|
||||
// retVal = true;
|
||||
// }
|
||||
// }
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
protected class EncodeContextPath {
|
||||
private final List<EncodeContextPathElement> myPath;
|
||||
|
||||
public EncodeContextPath() {
|
||||
myPath = new ArrayList<>(10);
|
||||
}
|
||||
|
||||
public EncodeContextPath(List<EncodeContextPathElement> thePath) {
|
||||
myPath = thePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return myPath.toString();
|
||||
}
|
||||
|
||||
protected List<EncodeContextPathElement> getPath() {
|
||||
return myPath;
|
||||
}
|
||||
|
||||
public EncodeContextPath getCurrentResourcePath() {
|
||||
EncodeContextPath retVal = null;
|
||||
for (int i = myPath.size() - 1; i >= 0; i--) {
|
||||
if (myPath.get(i).isResource()) {
|
||||
retVal = new EncodeContextPath(myPath.subList(i, myPath.size()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Validate.isTrue(retVal != null);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
protected class ElementsPath extends EncodeContextPath {
|
||||
|
||||
protected ElementsPath(String thePath) {
|
||||
StringTokenizer tok = new StringTokenizer(thePath, ".");
|
||||
boolean first = true;
|
||||
while (tok.hasMoreTokens()) {
|
||||
String next = tok.nextToken();
|
||||
if (first && next.equals("*")) {
|
||||
getPath().add(new EncodeContextPathElement("*", true));
|
||||
} else if (isNotBlank(next)) {
|
||||
getPath().add(new EncodeContextPathElement(next, Character.isUpperCase(next.charAt(0))));
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean startsWith(EncodeContextPath theCurrentResourcePath) {
|
||||
for (int i = 0; i < getPath().size(); i++) {
|
||||
if (theCurrentResourcePath.getPath().size() == i) {
|
||||
return true;
|
||||
}
|
||||
EncodeContextPathElement expected = getPath().get(i);
|
||||
EncodeContextPathElement actual = theCurrentResourcePath.getPath().get(i);
|
||||
if (!expected.matches(actual)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean startsWithPath(String thePath) {
|
||||
return startsWith(new ElementsPath(thePath));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* EncodeContext is a shared state object that is passed around the
|
||||
* encode process
|
||||
*/
|
||||
protected class EncodeContext extends EncodeContextPath {
|
||||
private final ArrayList<EncodeContextPathElement> myResourcePath = new ArrayList<>(10);
|
||||
|
||||
protected ArrayList<EncodeContextPathElement> getResourcePath() {
|
||||
return myResourcePath;
|
||||
}
|
||||
|
||||
public String getLeafResourcePathFirstField() {
|
||||
String retVal = null;
|
||||
for (int i = getPath().size() - 1; i >= 0; i--) {
|
||||
if (getPath().get(i).isResource()) {
|
||||
break;
|
||||
} else {
|
||||
retVal = getPath().get(i).getName();
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an element at the end of the path
|
||||
*/
|
||||
protected void pushPath(String thePathElement, boolean theResource) {
|
||||
assert isNotBlank(thePathElement);
|
||||
assert !thePathElement.contains(".");
|
||||
assert theResource ^ Character.isLowerCase(thePathElement.charAt(0));
|
||||
|
||||
EncodeContextPathElement element = new EncodeContextPathElement(thePathElement, theResource);
|
||||
getPath().add(element);
|
||||
if (theResource) {
|
||||
myResourcePath.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the element at the end of the path
|
||||
*/
|
||||
public void popPath() {
|
||||
EncodeContextPathElement removed = getPath().remove(getPath().size() - 1);
|
||||
if (removed.isResource()) {
|
||||
myResourcePath.remove(myResourcePath.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected class EncodeContextPathElement {
|
||||
private final String myName;
|
||||
private final boolean myResource;
|
||||
|
||||
public EncodeContextPathElement(String theName, boolean theResource) {
|
||||
Validate.notBlank(theName);
|
||||
myName = theName;
|
||||
myResource = theResource;
|
||||
}
|
||||
|
||||
|
||||
public boolean matches(EncodeContextPathElement theOther) {
|
||||
if (myResource != theOther.isResource()) {
|
||||
return false;
|
||||
}
|
||||
if (myName.equals(theOther.getName())) {
|
||||
return true;
|
||||
}
|
||||
if (myName.equals("*")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(17, 37)
|
||||
.append(myName)
|
||||
.append(myResource)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (myResource) {
|
||||
return myName + "(res)";
|
||||
}
|
||||
return myName;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public boolean isResource() {
|
||||
return myResource;
|
||||
}
|
||||
}
|
||||
|
||||
static class ContainedResources {
|
||||
private long myNextContainedId = 1;
|
||||
|
||||
|
@ -1242,7 +1411,6 @@ public abstract class BaseParser implements IParser {
|
|||
for (IBaseResource nextResource : getResourceList()) {
|
||||
if (getResourceToIdMap().get(nextResource) != null) {
|
||||
ids.add(getResourceToIdMap().get(nextResource).getValue());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1274,24 +1442,24 @@ public abstract class BaseParser implements IParser {
|
|||
return new ArrayList<>(securityLabels);
|
||||
}
|
||||
|
||||
static boolean hasExtensions(IBase theElement) {
|
||||
static boolean hasNoExtensions(IBase theElement) {
|
||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
|
||||
if (res.getUndeclaredExtensions().size() > 0 || res.getUndeclaredModifierExtensions().size() > 0) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (theElement instanceof IBaseHasExtensions) {
|
||||
IBaseHasExtensions res = (IBaseHasExtensions) theElement;
|
||||
if (res.hasExtension()) {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (theElement instanceof IBaseHasModifierExtensions) {
|
||||
IBaseHasModifierExtensions res = (IBaseHasModifierExtensions) theElement;
|
||||
return res.hasModifierExtension();
|
||||
return !res.hasModifierExtension();
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -51,16 +51,6 @@ public interface IParser {
|
|||
|
||||
void encodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException;
|
||||
|
||||
/**
|
||||
* See {@link #setEncodeElements(Set)}
|
||||
*/
|
||||
Set<String> getEncodeElements();
|
||||
|
||||
/**
|
||||
* See {@link #setEncodeElementsAppliesToResourceTypes(Set)}
|
||||
*/
|
||||
Set<String> getEncodeElementsAppliesToResourceTypes();
|
||||
|
||||
/**
|
||||
* If not set to null (as is the default) this ID will be used as the ID in any
|
||||
* resources encoded by this parser
|
||||
|
@ -258,14 +248,6 @@ public interface IParser {
|
|||
*/
|
||||
boolean isEncodeElementsAppliesToChildResourcesOnly();
|
||||
|
||||
/**
|
||||
* If provided, tells the parse which resource types to apply {@link #setEncodeElements(Set) encode elements} to. Any
|
||||
* resource types not specified here will be encoded completely, with no elements excluded.
|
||||
*
|
||||
* @param theEncodeElementsAppliesToResourceTypes
|
||||
*/
|
||||
void setEncodeElementsAppliesToResourceTypes(Set<String> theEncodeElementsAppliesToResourceTypes);
|
||||
|
||||
/**
|
||||
* When encoding, force this resource ID to be encoded as the resource ID
|
||||
*/
|
||||
|
|
|
@ -140,21 +140,21 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public void doEncodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theEventWriter) throws IOException {
|
||||
public void doEncodeResourceToJsonLikeWriter(IBaseResource theResource, JsonLikeWriter theEventWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
if (myPrettyPrint) {
|
||||
theEventWriter.setPrettyPrint(myPrettyPrint);
|
||||
}
|
||||
theEventWriter.init();
|
||||
|
||||
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
|
||||
encodeResourceToJsonStreamWriter(resDef, theResource, theEventWriter, null, false, false);
|
||||
encodeResourceToJsonStreamWriter(resDef, theResource, theEventWriter, null, false, theEncodeContext);
|
||||
theEventWriter.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException {
|
||||
protected void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
JsonLikeWriter eventWriter = createJsonWriter(theWriter);
|
||||
doEncodeResourceToJsonLikeWriter(theResource, eventWriter);
|
||||
doEncodeResourceToJsonLikeWriter(theResource, eventWriter, theEncodeContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -192,8 +192,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBase theNextValue,
|
||||
BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theContainedResource, boolean theSubResource, CompositeChildElement theChildElem,
|
||||
boolean theForceEmpty) throws IOException {
|
||||
BaseRuntimeElementDefinition<?> theChildDef, String theChildName, boolean theContainedResource, CompositeChildElement theChildElem,
|
||||
boolean theForceEmpty, EncodeContext theEncodeContext) throws IOException {
|
||||
|
||||
switch (theChildDef.getChildType()) {
|
||||
case ID_DATATYPE: {
|
||||
|
@ -265,7 +265,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
} else {
|
||||
theEventWriter.beginObject();
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theSubResource, theChildElem);
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theChildElem, theEncodeContext);
|
||||
theEventWriter.endObject();
|
||||
break;
|
||||
}
|
||||
|
@ -283,7 +283,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
|
||||
for (IBaseResource next : containedResources) {
|
||||
IIdType resourceId = getContainedResources().getResourceId(next);
|
||||
encodeResourceToJsonStreamWriter(theResDef, next, theEventWriter, null, true, false, fixContainedResourceId(resourceId.getValue()));
|
||||
encodeResourceToJsonStreamWriter(theResDef, next, theEventWriter, null, true, fixContainedResourceId(resourceId.getValue()), theEncodeContext);
|
||||
}
|
||||
|
||||
theEventWriter.endArray();
|
||||
|
@ -311,7 +311,11 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
case RESOURCE:
|
||||
IBaseResource resource = (IBaseResource) theNextValue;
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(resource);
|
||||
encodeResourceToJsonStreamWriter(def, resource, theEventWriter, theChildName, false, true);
|
||||
|
||||
theEncodeContext.pushPath(def.getName(), true);
|
||||
encodeResourceToJsonStreamWriter(def, resource, theEventWriter, theChildName, false, theEncodeContext);
|
||||
theEncodeContext.popPath();
|
||||
|
||||
break;
|
||||
case UNDECL_EXT:
|
||||
default:
|
||||
|
@ -321,7 +325,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, JsonLikeWriter theEventWriter,
|
||||
boolean theContainedResource, boolean theSubResource, CompositeChildElement theParent) throws IOException {
|
||||
boolean theContainedResource, CompositeChildElement theParent, EncodeContext theEncodeContext) throws IOException {
|
||||
|
||||
{
|
||||
String elementId = getCompositeElementId(theElement);
|
||||
|
@ -331,14 +335,14 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
boolean haveWrittenExtensions = false;
|
||||
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theSubResource, theParent)) {
|
||||
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent, theEncodeContext)) {
|
||||
|
||||
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
|
||||
|
||||
if (nextChildElem.getDef().getElementName().equals("extension") || nextChildElem.getDef().getElementName().equals("modifierExtension")
|
||||
|| nextChild instanceof RuntimeChildDeclaredExtensionDefinition) {
|
||||
if (!haveWrittenExtensions) {
|
||||
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem, theParent);
|
||||
extractAndWriteExtensionsAsDirectChild(theElement, theEventWriter, myContext.getElementDefinition(theElement.getClass()), theResDef, theResource, nextChildElem, theParent, theEncodeContext);
|
||||
haveWrittenExtensions = true;
|
||||
}
|
||||
continue;
|
||||
|
@ -361,7 +365,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
|
||||
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource, theSubResource, nextChildElem, false);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, type, childName, theContainedResource, nextChildElem, false, theEncodeContext);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -369,12 +373,12 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
} else if (nextChild instanceof RuntimeChildContainedResources) {
|
||||
String childName = nextChild.getValidChildNames().iterator().next();
|
||||
BaseRuntimeElementDefinition<?> child = nextChild.getChildByName(childName);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource, theSubResource, nextChildElem, false);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, null, child, childName, theContainedResource, nextChildElem, false, theEncodeContext);
|
||||
continue;
|
||||
}
|
||||
|
||||
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
|
||||
values = super.preProcessValues(nextChild, theResource, values, nextChildElem);
|
||||
values = super.preProcessValues(nextChild, theResource, values, nextChildElem, theEncodeContext);
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
continue;
|
||||
|
@ -407,6 +411,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
String childName = childNameAndDef.getChildName();
|
||||
theEncodeContext.pushPath(childName, false);
|
||||
|
||||
BaseRuntimeElementDefinition<?> childDef = childNameAndDef.getChildDef();
|
||||
boolean primitive = childDef.getChildType() == ChildTypeEnum.PRIMITIVE_DATATYPE;
|
||||
|
||||
|
@ -452,18 +458,19 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
if (nextChild.getMax() > 1 || nextChild.getMax() == Child.MAX_UNLIMITED) {
|
||||
beginArray(theEventWriter, childName);
|
||||
inArray = true;
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, theSubResource, nextChildElem, force);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force, theEncodeContext);
|
||||
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
|
||||
// suppress narratives from contained resources
|
||||
} else {
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, theSubResource, nextChildElem, false);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, childName, theContainedResource, nextChildElem, false, theEncodeContext);
|
||||
}
|
||||
currentChildName = childName;
|
||||
} else {
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, theSubResource, nextChildElem, force);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theContainedResource, nextChildElem, force, theEncodeContext);
|
||||
}
|
||||
|
||||
valueIdx++;
|
||||
theEncodeContext.popPath();
|
||||
}
|
||||
|
||||
if (inArray) {
|
||||
|
@ -525,7 +532,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, heldExts, heldModExts, theEncodeContext);
|
||||
if (inArray) {
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
|
@ -541,11 +548,10 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
}
|
||||
|
||||
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonLikeWriter theEventWriter, boolean theContainedResource, boolean theSubResource,
|
||||
CompositeChildElement theParent) throws IOException, DataFormatException {
|
||||
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonLikeWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent, EncodeContext theEncodeContext) throws IOException, DataFormatException {
|
||||
|
||||
writeCommentsPreAndPost(theNextValue, theEventWriter);
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theSubResource, theParent);
|
||||
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theNextValue, theEventWriter, theContainedResource, theParent, theEncodeContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -558,27 +564,15 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
"This parser is for FHIR version " + myContext.getVersion().getVersion() + " - Can not encode a structure for version " + theResource.getStructureFhirVersionEnum());
|
||||
}
|
||||
|
||||
doEncodeResourceToJsonLikeWriter(theResource, theJsonLikeWriter);
|
||||
EncodeContext encodeContext = new EncodeContext();
|
||||
String resourceName = myContext.getResourceDefinition(theResource).getName();
|
||||
encodeContext.pushPath(resourceName, true);
|
||||
doEncodeResourceToJsonLikeWriter(theResource, theJsonLikeWriter, encodeContext);
|
||||
}
|
||||
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, String theObjectNameOrNull,
|
||||
boolean theContainedResource, boolean theSubResource) throws IOException {
|
||||
boolean theContainedResource, EncodeContext theEncodeContext) throws IOException {
|
||||
IIdType resourceId = null;
|
||||
// if (theResource instanceof IResource) {
|
||||
// IResource res = (IResource) theResource;
|
||||
// if (StringUtils.isNotBlank(res.getId().getIdPart())) {
|
||||
// if (theContainedResource) {
|
||||
// resourceId = res.getId().getIdPart();
|
||||
// } else if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
|
||||
// resourceId = res.getId().getIdPart();
|
||||
// }
|
||||
// }
|
||||
// } else if (theResource instanceof IAnyResource) {
|
||||
// IAnyResource res = (IAnyResource) theResource;
|
||||
// if (/* theContainedResource && */StringUtils.isNotBlank(res.getIdElement().getIdPart())) {
|
||||
// resourceId = res.getIdElement().getIdPart();
|
||||
// }
|
||||
// }
|
||||
|
||||
if (StringUtils.isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||
resourceId = theResource.getIdElement();
|
||||
|
@ -588,18 +582,18 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
if (!theContainedResource) {
|
||||
if (super.shouldEncodeResourceId(theResource, theSubResource) == false) {
|
||||
if (!super.shouldEncodeResourceId(theResource, theEncodeContext)) {
|
||||
resourceId = null;
|
||||
} else if (!theSubResource && getEncodeForceResourceId() != null) {
|
||||
} else if (theEncodeContext.getResourcePath().size() == 1 && getEncodeForceResourceId() != null) {
|
||||
resourceId = getEncodeForceResourceId();
|
||||
}
|
||||
}
|
||||
|
||||
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, theSubResource, resourceId);
|
||||
encodeResourceToJsonStreamWriter(theResDef, theResource, theEventWriter, theObjectNameOrNull, theContainedResource, resourceId, theEncodeContext);
|
||||
}
|
||||
|
||||
private void encodeResourceToJsonStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, String theObjectNameOrNull,
|
||||
boolean theContainedResource, boolean theSubResource, IIdType theResourceId) throws IOException {
|
||||
boolean theContainedResource, IIdType theResourceId, EncodeContext theEncodeContext) throws IOException {
|
||||
if (!theContainedResource) {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
}
|
||||
|
@ -630,7 +624,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
writeCommentsPreAndPost(theResourceId, theEventWriter);
|
||||
}
|
||||
if (haveExtension) {
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext);
|
||||
}
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
|
@ -644,7 +638,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding(resource);
|
||||
TagList tags = getMetaTagsForEncoding(resource, theEncodeContext);
|
||||
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
||||
IdDt resourceId = resource.getId();
|
||||
String versionIdPart = resourceId.getVersionIdPart();
|
||||
|
@ -672,7 +666,9 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
beginArray(theEventWriter, "security");
|
||||
for (BaseCodingDt securityLabel : securityLabels) {
|
||||
theEventWriter.beginObject();
|
||||
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, theContainedResource, theSubResource, null);
|
||||
theEncodeContext.pushPath("security", false);
|
||||
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, theContainedResource, null, theEncodeContext);
|
||||
theEncodeContext.popPath();
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
|
@ -693,23 +689,23 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
addExtensionMetadata(theResDef, theResource, theContainedResource, theSubResource, extensionMetadataKeys, resDef, theEventWriter);
|
||||
addExtensionMetadata(theResDef, theResource, theContainedResource, extensionMetadataKeys, resDef, theEventWriter, theEncodeContext);
|
||||
|
||||
theEventWriter.endObject(); // end meta
|
||||
}
|
||||
}
|
||||
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, theContainedResource, new CompositeChildElement(resDef, theEncodeContext), theEncodeContext);
|
||||
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
|
||||
|
||||
private void addExtensionMetadata(RuntimeResourceDefinition theResDef, IBaseResource theResource,
|
||||
boolean theContainedResource, boolean theSubResource,
|
||||
boolean theContainedResource,
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys,
|
||||
RuntimeResourceDefinition resDef,
|
||||
JsonLikeWriter theEventWriter) throws IOException {
|
||||
JsonLikeWriter theEventWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
if (extensionMetadataKeys.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
@ -718,7 +714,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> entry : extensionMetadataKeys) {
|
||||
metaResource.addUndeclaredExtension((ExtensionDt) entry.getValue());
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, metaResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||
encodeCompositeElementToStreamWriter(theResDef, theResource, metaResource, theEventWriter, theContainedResource, new CompositeChildElement(resDef, theEncodeContext), theEncodeContext);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -726,7 +722,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
* called _name): resource extensions, and extension extensions
|
||||
*/
|
||||
private void extractAndWriteExtensionsAsDirectChild(IBase theElement, JsonLikeWriter theEventWriter, BaseRuntimeElementDefinition<?> theElementDef, RuntimeResourceDefinition theResDef,
|
||||
IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent) throws IOException {
|
||||
IBaseResource theResource, CompositeChildElement theChildElem, CompositeChildElement theParent, EncodeContext theEncodeContext) throws IOException {
|
||||
List<HeldExtension> extensions = new ArrayList<>(0);
|
||||
List<HeldExtension> modifierExtensions = new ArrayList<>(0);
|
||||
|
||||
|
@ -739,7 +735,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
// Write the extensions
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext);
|
||||
}
|
||||
|
||||
private void extractDeclaredExtensions(IBase theResource, BaseRuntimeElementDefinition<?> resDef, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions,
|
||||
|
@ -1260,18 +1256,18 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonLikeWriter theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions,
|
||||
List<HeldExtension> modifierExtensions) throws IOException {
|
||||
List<HeldExtension> modifierExtensions, EncodeContext theEncodeContext) throws IOException {
|
||||
if (extensions.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "extension");
|
||||
for (HeldExtension next : extensions) {
|
||||
next.write(resDef, theResource, theEventWriter);
|
||||
next.write(resDef, theResource, theEventWriter, theEncodeContext);
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
if (modifierExtensions.isEmpty() == false) {
|
||||
beginArray(theEventWriter, "modifierExtension");
|
||||
for (HeldExtension next : modifierExtensions) {
|
||||
next.write(resDef, theResource, theEventWriter);
|
||||
next.write(resDef, theResource, theEventWriter, theEncodeContext);
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
@ -1334,7 +1330,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
return url1.compareTo(url2);
|
||||
}
|
||||
|
||||
private void managePrimitiveExtension(final IBase theValue, final RuntimeResourceDefinition theResDef, final IBaseResource theResource, final JsonLikeWriter theEventWriter, final BaseRuntimeElementDefinition<?> def, final String childName) throws IOException {
|
||||
private void managePrimitiveExtension(final IBase theValue, final RuntimeResourceDefinition theResDef, final IBaseResource theResource, final JsonLikeWriter theEventWriter, final BaseRuntimeElementDefinition<?> def, final String childName, EncodeContext theEncodeContext) throws IOException {
|
||||
if (def.getChildType().equals(ID_DATATYPE) || def.getChildType().equals(PRIMITIVE_DATATYPE)) {
|
||||
final List<HeldExtension> extensions = new ArrayList<HeldExtension>(0);
|
||||
final List<HeldExtension> modifierExtensions = new ArrayList<HeldExtension>(0);
|
||||
|
@ -1350,15 +1346,15 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
if (haveContent) {
|
||||
beginObject(theEventWriter, '_' + childName);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions);
|
||||
writeExtensionsAsDirectChild(theResource, theEventWriter, theResDef, extensions, modifierExtensions, theEncodeContext);
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter) throws IOException {
|
||||
public void write(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, EncodeContext theEncodeContext) throws IOException {
|
||||
if (myUndeclaredExtension != null) {
|
||||
writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension);
|
||||
writeUndeclaredExtension(theResDef, theResource, theEventWriter, myUndeclaredExtension, theEncodeContext);
|
||||
} else {
|
||||
theEventWriter.beginObject();
|
||||
|
||||
|
@ -1372,7 +1368,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
*
|
||||
* See #327
|
||||
*/
|
||||
List<? extends IBase> preProcessedValue = preProcessValues(myDef, theResource, Collections.singletonList(myValue), myChildElem);
|
||||
List<? extends IBase> preProcessedValue = preProcessValues(myDef, theResource, Collections.singletonList(myValue), myChildElem, theEncodeContext);
|
||||
|
||||
// // Check for undeclared extensions on the declared extension
|
||||
// // (grrrrrr....)
|
||||
|
@ -1391,18 +1387,18 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
|
||||
BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
|
||||
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
|
||||
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myChildElem, null);
|
||||
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, myChildElem, null, theEncodeContext);
|
||||
} else {
|
||||
String childName = myDef.getChildNameByDatatype(myValue.getClass());
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, false, myParent, false);
|
||||
managePrimitiveExtension(myValue, theResDef, theResource, theEventWriter, def, childName);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false, myParent, false, theEncodeContext);
|
||||
managePrimitiveExtension(myValue, theResDef, theResource, theEventWriter, def, childName, theEncodeContext);
|
||||
}
|
||||
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBaseExtension<?, ?> ext) throws IOException {
|
||||
private void writeUndeclaredExtension(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonLikeWriter theEventWriter, IBaseExtension<?, ?> ext, EncodeContext theEncodeContext) throws IOException {
|
||||
IBase value = ext.getValue();
|
||||
final String extensionUrl = getExtensionUrl(ext.getUrl());
|
||||
|
||||
|
@ -1429,7 +1425,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
}
|
||||
|
||||
for (Object next : ext.getExtension()) {
|
||||
writeUndeclaredExtension(theResDef, theResource, theEventWriter, (IBaseExtension<?, ?>) next);
|
||||
writeUndeclaredExtension(theResDef, theResource, theEventWriter, (IBaseExtension<?, ?>) next, theEncodeContext);
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
} else {
|
||||
|
@ -1438,7 +1434,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
* Pre-process value - This is called in case the value is a reference
|
||||
* since we might modify the text
|
||||
*/
|
||||
value = JsonParser.super.preProcessValues(myDef, theResource, Collections.singletonList(value), myChildElem).get(0);
|
||||
value = JsonParser.super.preProcessValues(myDef, theResource, Collections.singletonList(value), myChildElem, theEncodeContext).get(0);
|
||||
|
||||
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
|
||||
String childName = extDef.getChildNameByDatatype(value.getClass());
|
||||
|
@ -1449,8 +1445,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
if (childDef == null) {
|
||||
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
|
||||
}
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, false, myParent, false);
|
||||
managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName);
|
||||
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true, myParent,false, theEncodeContext);
|
||||
managePrimitiveExtension(value, theResDef, theResource, theEventWriter, childDef, childName, theEncodeContext);
|
||||
}
|
||||
|
||||
// theEventWriter.name(myUndeclaredExtension.get);
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.parser;
|
|||
* 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.
|
||||
|
@ -20,28 +20,32 @@ package ca.uhn.fhir.parser;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.io.Writer;
|
||||
import java.util.*;
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper;
|
||||
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
|
||||
import ca.uhn.fhir.util.XmlUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.*;
|
||||
import javax.xml.stream.events.*;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import ca.uhn.fhir.context.*;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.primitive.*;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* This class is the FHIR XML parser/encoder. Users should not interact with this class directly, but should use
|
||||
|
@ -52,21 +56,20 @@ 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/";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
|
||||
static final String RESREF_DISPLAY = "display";
|
||||
static final String RESREF_REFERENCE = "reference";
|
||||
static final String TOMBSTONES_NS = "http://purl.org/atompub/tombstones/1.0";
|
||||
static final String XHTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParser.class);
|
||||
|
||||
// private static final Set<String> RESOURCE_NAMESPACES;
|
||||
|
||||
private FhirContext myContext;
|
||||
private boolean myPrettyPrint;
|
||||
|
||||
/**
|
||||
* Do not use this constructor, the recommended way to obtain a new instance of the XML parser is to invoke
|
||||
* {@link FhirContext#newXmlParser()}.
|
||||
*
|
||||
*
|
||||
* @param theParserErrorHandler
|
||||
*/
|
||||
public XmlParser(FhirContext theContext, IParserErrorHandler theParserErrorHandler) {
|
||||
|
@ -101,12 +104,12 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws DataFormatException {
|
||||
public void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter, EncodeContext theEncodeContext) throws DataFormatException {
|
||||
XMLStreamWriter eventWriter;
|
||||
try {
|
||||
eventWriter = createXmlWriter(theWriter);
|
||||
|
||||
encodeResourceToXmlStreamWriter(theResource, eventWriter, false, false);
|
||||
encodeResourceToXmlStreamWriter(theResource, eventWriter, false, theEncodeContext);
|
||||
eventWriter.flush();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new ConfigurationException("Failed to initialize STaX event factory", e);
|
||||
|
@ -123,83 +126,81 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
ourLog.trace("Entering XML parsing loop with state: {}", parserState);
|
||||
|
||||
try {
|
||||
List<String> heldComments = new ArrayList<String>(1);
|
||||
List<String> heldComments = new ArrayList<>(1);
|
||||
|
||||
while (streamReader.hasNext()) {
|
||||
XMLEvent nextEvent = streamReader.nextEvent();
|
||||
try {
|
||||
|
||||
switch (nextEvent.getEventType()) {
|
||||
case XMLStreamConstants.START_ELEMENT: {
|
||||
StartElement elem = nextEvent.asStartElement();
|
||||
case XMLStreamConstants.START_ELEMENT: {
|
||||
StartElement elem = nextEvent.asStartElement();
|
||||
|
||||
String namespaceURI = elem.getName().getNamespaceURI();
|
||||
String namespaceURI = elem.getName().getNamespaceURI();
|
||||
|
||||
if ("extension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
String url;
|
||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("extension"), "url");
|
||||
url = null;
|
||||
if ("extension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
String url;
|
||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("extension"), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = urlAttr.getValue();
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, url, false, getServerBaseUrl());
|
||||
} else if ("modifierExtension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
String url;
|
||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("modifierExtension"), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = urlAttr.getValue();
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, url, true, getServerBaseUrl());
|
||||
} else {
|
||||
url = urlAttr.getValue();
|
||||
String elementName = elem.getName().getLocalPart();
|
||||
parserState.enteringNewElement(namespaceURI, elementName);
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, url, false, getServerBaseUrl());
|
||||
} else if ("modifierExtension".equals(elem.getName().getLocalPart())) {
|
||||
Attribute urlAttr = elem.getAttributeByName(new QName("url"));
|
||||
String url;
|
||||
if (urlAttr == null || isBlank(urlAttr.getValue())) {
|
||||
getErrorHandler().missingRequiredElement(new ParseLocation().setParentElementName("modifierExtension"), "url");
|
||||
url = null;
|
||||
} else {
|
||||
url = urlAttr.getValue();
|
||||
}
|
||||
parserState.enteringNewElementExtension(elem, url, true, getServerBaseUrl());
|
||||
} else {
|
||||
String elementName = elem.getName().getLocalPart();
|
||||
parserState.enteringNewElement(namespaceURI, elementName);
|
||||
}
|
||||
|
||||
if (!heldComments.isEmpty()) {
|
||||
for (String next : heldComments) {
|
||||
parserState.commentPre(next);
|
||||
if (!heldComments.isEmpty()) {
|
||||
for (String next : heldComments) {
|
||||
parserState.commentPre(next);
|
||||
}
|
||||
heldComments.clear();
|
||||
}
|
||||
heldComments.clear();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Iterator<Attribute> attributes = elem.getAttributes();
|
||||
for (Iterator<Attribute> iter = attributes; iter.hasNext();) {
|
||||
Attribute next = iter.next();
|
||||
parserState.attributeValue(next.getName().getLocalPart(), next.getValue());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
case XMLStreamConstants.END_ELEMENT: {
|
||||
if (!heldComments.isEmpty()) {
|
||||
for (String next : heldComments) {
|
||||
parserState.commentPost(next);
|
||||
for (Iterator<Attribute> attributes = elem.getAttributes(); attributes.hasNext(); ) {
|
||||
Attribute next = attributes.next();
|
||||
parserState.attributeValue(next.getName().getLocalPart(), next.getValue());
|
||||
}
|
||||
heldComments.clear();
|
||||
|
||||
break;
|
||||
}
|
||||
parserState.endingElement();
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
case XMLStreamConstants.END_ELEMENT: {
|
||||
if (!heldComments.isEmpty()) {
|
||||
for (String next : heldComments) {
|
||||
parserState.commentPost(next);
|
||||
}
|
||||
heldComments.clear();
|
||||
}
|
||||
parserState.endingElement();
|
||||
// if (parserState.isComplete()) {
|
||||
// return parserState.getObject();
|
||||
// }
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.CHARACTERS: {
|
||||
parserState.string(nextEvent.asCharacters().getData());
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.COMMENT: {
|
||||
Comment comment = (Comment) nextEvent;
|
||||
String commentText = comment.getText();
|
||||
heldComments.add(commentText);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.CHARACTERS: {
|
||||
parserState.string(nextEvent.asCharacters().getData());
|
||||
break;
|
||||
}
|
||||
case XMLStreamConstants.COMMENT: {
|
||||
Comment comment = (Comment) nextEvent;
|
||||
String commentText = comment.getText();
|
||||
heldComments.add(commentText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parserState.xmlEvent(nextEvent);
|
||||
|
@ -215,115 +216,125 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
}
|
||||
|
||||
private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase theElement, String childName, BaseRuntimeElementDefinition<?> childDef,
|
||||
String theExtensionUrl, boolean theIncludedResource, boolean theSubResource, CompositeChildElement theParent) throws XMLStreamException, DataFormatException {
|
||||
if (theElement == null || theElement.isEmpty()) {
|
||||
if (isChildContained(childDef, theIncludedResource)) {
|
||||
// We still want to go in..
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
String theExtensionUrl, boolean theIncludedResource, CompositeChildElement theParent, EncodeContext theEncodeContext) throws XMLStreamException, DataFormatException {
|
||||
theEncodeContext.pushPath(childName, false);
|
||||
try {
|
||||
|
||||
writeCommentsPre(theEventWriter, theElement);
|
||||
|
||||
switch (childDef.getChildType()) {
|
||||
case ID_DATATYPE: {
|
||||
IIdType value = IIdType.class.cast(theElement);
|
||||
String encodedValue = "id".equals(childName) ? value.getIdPart() : value.getValue();
|
||||
if (StringUtils.isNotBlank(encodedValue) || super.hasExtensions(value)) {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
if (StringUtils.isNotBlank(encodedValue)) {
|
||||
theEventWriter.writeAttribute("value", encodedValue);
|
||||
}
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource, theSubResource);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
IPrimitiveType<?> pd = IPrimitiveType.class.cast(theElement);
|
||||
String value = pd.getValueAsString();
|
||||
if (value != null || super.hasExtensions(pd)) {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
String elementId = getCompositeElementId(theElement);
|
||||
if (isNotBlank(elementId)) {
|
||||
theEventWriter.writeAttribute("id", elementId);
|
||||
if (theElement == null || theElement.isEmpty()) {
|
||||
if (isChildContained(childDef, theIncludedResource)) {
|
||||
// We still want to go in..
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if (value != null) {
|
||||
theEventWriter.writeAttribute("value", value);
|
||||
}
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource,theSubResource);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE_BLOCK:
|
||||
case COMPOSITE_DATATYPE: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
String elementId = getCompositeElementId(theElement);
|
||||
if (isNotBlank(elementId)) {
|
||||
theEventWriter.writeAttribute("id", elementId);
|
||||
}
|
||||
if (isNotBlank(theExtensionUrl)) {
|
||||
theEventWriter.writeAttribute("url", theExtensionUrl);
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResource, theElement, theEventWriter, theIncludedResource, theSubResource, theParent);
|
||||
theEventWriter.writeEndElement();
|
||||
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"); encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue()));
|
||||
* theEventWriter.writeEndElement(); }
|
||||
*/
|
||||
for (IBaseResource next : getContainedResources().getContainedResources()) {
|
||||
IIdType resourceId = getContainedResources().getResourceId(next);
|
||||
theEventWriter.writeStartElement("contained");
|
||||
encodeResourceToXmlStreamWriter(next, theEventWriter, true, false, fixContainedResourceId(resourceId.getValue()));
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
IBaseResource resource = (IBaseResource) theElement;
|
||||
encodeResourceToXmlStreamWriter(resource, theEventWriter, false, true);
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML: {
|
||||
XhtmlDt dt = XhtmlDt.class.cast(theElement);
|
||||
if (dt.hasContent()) {
|
||||
encodeXhtml(dt, theEventWriter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML_HL7ORG: {
|
||||
IBaseXhtml dt = IBaseXhtml.class.cast(theElement);
|
||||
if (!dt.isEmpty()) {
|
||||
// TODO: this is probably not as efficient as it could be
|
||||
XhtmlDt hdt = new XhtmlDt();
|
||||
hdt.setValueAsString(dt.getValueAsString());
|
||||
encodeXhtml(hdt, theEventWriter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXTENSION_DECLARED:
|
||||
case UNDECL_EXT: {
|
||||
throw new IllegalStateException("state should not happen: " + childDef.getName());
|
||||
}
|
||||
}
|
||||
|
||||
writeCommentsPost(theEventWriter, theElement);
|
||||
writeCommentsPre(theEventWriter, theElement);
|
||||
|
||||
switch (childDef.getChildType()) {
|
||||
case ID_DATATYPE: {
|
||||
IIdType value = IIdType.class.cast(theElement);
|
||||
String encodedValue = "id".equals(childName) ? value.getIdPart() : value.getValue();
|
||||
if (StringUtils.isNotBlank(encodedValue) || !super.hasNoExtensions(value)) {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
if (StringUtils.isNotBlank(encodedValue)) {
|
||||
theEventWriter.writeAttribute("value", encodedValue);
|
||||
}
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_DATATYPE: {
|
||||
IPrimitiveType<?> pd = IPrimitiveType.class.cast(theElement);
|
||||
String value = pd.getValueAsString();
|
||||
if (value != null || !super.hasNoExtensions(pd)) {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
String elementId = getCompositeElementId(theElement);
|
||||
if (isNotBlank(elementId)) {
|
||||
theEventWriter.writeAttribute("id", elementId);
|
||||
}
|
||||
if (value != null) {
|
||||
theEventWriter.writeAttribute("value", value);
|
||||
}
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE_BLOCK:
|
||||
case COMPOSITE_DATATYPE: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
String elementId = getCompositeElementId(theElement);
|
||||
if (isNotBlank(elementId)) {
|
||||
theEventWriter.writeAttribute("id", elementId);
|
||||
}
|
||||
if (isNotBlank(theExtensionUrl)) {
|
||||
theEventWriter.writeAttribute("url", theExtensionUrl);
|
||||
}
|
||||
encodeCompositeElementToStreamWriter(theResource, theElement, theEventWriter, theIncludedResource, theParent, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
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"); encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(next.getId().getValue()));
|
||||
* theEventWriter.writeEndElement(); }
|
||||
*/
|
||||
for (IBaseResource next : getContainedResources().getContainedResources()) {
|
||||
IIdType resourceId = getContainedResources().getResourceId(next);
|
||||
theEventWriter.writeStartElement("contained");
|
||||
encodeResourceToXmlStreamWriter(next, theEventWriter, true, fixContainedResourceId(resourceId.getValue()), theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RESOURCE: {
|
||||
theEventWriter.writeStartElement(childName);
|
||||
IBaseResource resource = (IBaseResource) theElement;
|
||||
String resourceName = myContext.getResourceDefinition(resource).getName();
|
||||
theEncodeContext.pushPath(resourceName, true);
|
||||
encodeResourceToXmlStreamWriter(resource, theEventWriter, false, theEncodeContext);
|
||||
theEncodeContext.popPath();
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML: {
|
||||
XhtmlDt dt = XhtmlDt.class.cast(theElement);
|
||||
if (dt.hasContent()) {
|
||||
encodeXhtml(dt, theEventWriter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PRIMITIVE_XHTML_HL7ORG: {
|
||||
IBaseXhtml dt = IBaseXhtml.class.cast(theElement);
|
||||
if (!dt.isEmpty()) {
|
||||
// TODO: this is probably not as efficient as it could be
|
||||
XhtmlDt hdt = new XhtmlDt();
|
||||
hdt.setValueAsString(dt.getValueAsString());
|
||||
encodeXhtml(hdt, theEventWriter);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EXTENSION_DECLARED:
|
||||
case UNDECL_EXT: {
|
||||
throw new IllegalStateException("state should not happen: " + childDef.getName());
|
||||
}
|
||||
}
|
||||
|
||||
writeCommentsPost(theEventWriter, theElement);
|
||||
|
||||
} finally {
|
||||
theEncodeContext.popPath();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, boolean theContainedResource, boolean theSubResource, CompositeChildElement theParent)
|
||||
throws XMLStreamException, DataFormatException {
|
||||
private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, boolean theContainedResource, CompositeChildElement theParent, EncodeContext theEncodeContext)
|
||||
throws XMLStreamException, DataFormatException {
|
||||
|
||||
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theSubResource, theParent)) {
|
||||
for (CompositeChildElement nextChildElem : super.compositeChildIterator(theElement, theContainedResource, theParent, theEncodeContext)) {
|
||||
|
||||
BaseRuntimeChildDefinition nextChild = nextChildElem.getDef();
|
||||
|
||||
|
@ -353,17 +364,17 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
|
||||
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
|
||||
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, narr, childName, type, null, theContainedResource, theSubResource, nextChildElem);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, narr, childName, type, null, theContainedResource, nextChildElem, theEncodeContext);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextChild instanceof RuntimeChildContainedResources) {
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, null, nextChild.getChildNameByDatatype(null), nextChild.getChildElementDefinitionByDatatype(null), null, theContainedResource, theSubResource, nextChildElem);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, null, nextChild.getChildNameByDatatype(null), nextChild.getChildElementDefinitionByDatatype(null), null, theContainedResource, nextChildElem, theEncodeContext);
|
||||
} else {
|
||||
|
||||
List<? extends IBase> values = nextChild.getAccessor().getValues(theElement);
|
||||
values = super.preProcessValues(nextChild, theResource, values, nextChildElem);
|
||||
values = super.preProcessValues(nextChild, theResource, values, nextChildElem, theEncodeContext);
|
||||
|
||||
if (values == null || values.isEmpty()) {
|
||||
continue;
|
||||
|
@ -383,7 +394,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
String extensionUrl = getExtensionUrl(nextChild.getExtensionUrl());
|
||||
|
||||
if (extensionUrl != null && childName.equals("extension") == false) {
|
||||
encodeExtension(theResource, theEventWriter, theContainedResource, theSubResource, nextChildElem, nextChild, nextValue, childName, extensionUrl, childDef);
|
||||
encodeExtension(theResource, theEventWriter, theContainedResource, nextChildElem, nextChild, nextValue, childName, extensionUrl, childDef, theEncodeContext);
|
||||
} else if (nextChild instanceof RuntimeChildExtension) {
|
||||
IBaseExtension<?, ?> extension = (IBaseExtension<?, ?>) nextValue;
|
||||
if ((extension.getValue() == null || extension.getValue().isEmpty())) {
|
||||
|
@ -391,19 +402,20 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, getExtensionUrl(extension.getUrl()), theContainedResource, theSubResource, nextChildElem);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, getExtensionUrl(extension.getUrl()), theContainedResource, nextChildElem, theEncodeContext);
|
||||
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theContainedResource) {
|
||||
// suppress narratives from contained resources
|
||||
} else {
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theContainedResource, theSubResource, nextChildElem);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theContainedResource, nextChildElem, theEncodeContext);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeExtension(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, boolean theSubResource, CompositeChildElement nextChildElem, BaseRuntimeChildDefinition nextChild, IBase nextValue, String childName, String extensionUrl, BaseRuntimeElementDefinition<?> childDef)
|
||||
throws XMLStreamException {
|
||||
private void encodeExtension(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, CompositeChildElement nextChildElem, BaseRuntimeChildDefinition nextChild, IBase nextValue, String childName, String extensionUrl, BaseRuntimeElementDefinition<?> childDef, EncodeContext theEncodeContext)
|
||||
throws XMLStreamException {
|
||||
BaseRuntimeDeclaredChildDefinition extDef = (BaseRuntimeDeclaredChildDefinition) nextChild;
|
||||
if (extDef.isModifier()) {
|
||||
theEventWriter.writeStartElement("modifierExtension");
|
||||
|
@ -417,27 +429,27 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
}
|
||||
|
||||
theEventWriter.writeAttribute("url", extensionUrl);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theContainedResource, theSubResource, nextChildElem);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theContainedResource, nextChildElem, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
|
||||
private void encodeExtensionsIfPresent(IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource, boolean theSubResource) throws XMLStreamException, DataFormatException {
|
||||
private void encodeExtensionsIfPresent(IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource, EncodeContext theEncodeContext) throws XMLStreamException, DataFormatException {
|
||||
if (theElement instanceof ISupportsUndeclaredExtensions) {
|
||||
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
|
||||
encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredExtensions()), "extension", theIncludedResource, theSubResource);
|
||||
encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredModifierExtensions()), "modifierExtension", theIncludedResource,theSubResource);
|
||||
encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredExtensions()), "extension", theIncludedResource, theEncodeContext);
|
||||
encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredModifierExtensions()), "modifierExtension", theIncludedResource, theEncodeContext);
|
||||
}
|
||||
if (theElement instanceof IBaseHasExtensions) {
|
||||
IBaseHasExtensions res = (IBaseHasExtensions) theElement;
|
||||
encodeUndeclaredExtensions(theResource, theWriter, res.getExtension(), "extension", theIncludedResource,theSubResource);
|
||||
encodeUndeclaredExtensions(theResource, theWriter, res.getExtension(), "extension", theIncludedResource, theEncodeContext);
|
||||
}
|
||||
if (theElement instanceof IBaseHasModifierExtensions) {
|
||||
IBaseHasModifierExtensions res = (IBaseHasModifierExtensions) theElement;
|
||||
encodeUndeclaredExtensions(theResource, theWriter, res.getModifierExtension(), "modifierExtension", theIncludedResource,theSubResource);
|
||||
encodeUndeclaredExtensions(theResource, theWriter, res.getModifierExtension(), "modifierExtension", theIncludedResource, theEncodeContext);
|
||||
}
|
||||
}
|
||||
|
||||
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource, boolean theSubResource) throws XMLStreamException, DataFormatException {
|
||||
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theIncludedResource, EncodeContext theEncodeContext) throws XMLStreamException, DataFormatException {
|
||||
IIdType resourceId = null;
|
||||
|
||||
if (StringUtils.isNotBlank(theResource.getIdElement().getIdPart())) {
|
||||
|
@ -448,17 +460,17 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
}
|
||||
|
||||
if (!theIncludedResource) {
|
||||
if (super.shouldEncodeResourceId(theResource, theSubResource) == false) {
|
||||
if (super.shouldEncodeResourceId(theResource, theEncodeContext) == false) {
|
||||
resourceId = null;
|
||||
} else if (theSubResource == false && getEncodeForceResourceId() != null) {
|
||||
} else if (theEncodeContext.getResourcePath().size() == 1 && getEncodeForceResourceId() != null) {
|
||||
resourceId = getEncodeForceResourceId();
|
||||
}
|
||||
}
|
||||
|
||||
encodeResourceToXmlStreamWriter(theResource, theEventWriter, theIncludedResource, theSubResource, resourceId);
|
||||
encodeResourceToXmlStreamWriter(theResource, theEventWriter, theIncludedResource, resourceId, theEncodeContext);
|
||||
}
|
||||
|
||||
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, boolean theSubResource, IIdType theResourceId) throws XMLStreamException {
|
||||
private void encodeResourceToXmlStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, boolean theContainedResource, IIdType theResourceId, EncodeContext theEncodeContext) throws XMLStreamException {
|
||||
if (!theContainedResource) {
|
||||
super.containResourcesForEncoding(theResource);
|
||||
}
|
||||
|
@ -473,32 +485,32 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
|
||||
if (theResource instanceof IAnyResource) {
|
||||
// HL7.org Structures
|
||||
if (theResourceId != null) {
|
||||
writeCommentsPre(theEventWriter, theResourceId);
|
||||
theEventWriter.writeStartElement("id");
|
||||
theEventWriter.writeAttribute("value", theResourceId.getIdPart());
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theResourceId, false, false);
|
||||
theEventWriter.writeEndElement();
|
||||
writeCommentsPost(theEventWriter, theResourceId);
|
||||
}
|
||||
if (theResourceId != null) {
|
||||
writeCommentsPre(theEventWriter, theResourceId);
|
||||
theEventWriter.writeStartElement("id");
|
||||
theEventWriter.writeAttribute("value", theResourceId.getIdPart());
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theResourceId, false, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
writeCommentsPost(theEventWriter, theResourceId);
|
||||
}
|
||||
|
||||
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, theContainedResource, new CompositeChildElement(resDef, theEncodeContext), theEncodeContext);
|
||||
|
||||
} else {
|
||||
|
||||
// DSTU2+
|
||||
|
||||
IResource resource = (IResource) theResource;
|
||||
if (theResourceId != null) {
|
||||
if (theResourceId != null) {
|
||||
/* writeCommentsPre(theEventWriter, theResourceId);
|
||||
writeOptionalTagWithValue(theEventWriter, "id", theResourceId.getIdPart());
|
||||
writeCommentsPost(theEventWriter, theResourceId);*/
|
||||
theEventWriter.writeStartElement("id");
|
||||
theEventWriter.writeAttribute("value", theResourceId.getIdPart());
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theResourceId, false,false);
|
||||
theEventWriter.writeEndElement();
|
||||
writeCommentsPost(theEventWriter, theResourceId);
|
||||
}
|
||||
theEventWriter.writeStartElement("id");
|
||||
theEventWriter.writeAttribute("value", theResourceId.getIdPart());
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, theResourceId, false, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
writeCommentsPost(theEventWriter, theResourceId);
|
||||
}
|
||||
|
||||
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
||||
IdDt resourceId = resource.getId();
|
||||
|
@ -510,7 +522,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
List<? extends IIdType> profiles = extractMetadataListNotNull(resource, ResourceMetadataKeyEnum.PROFILES);
|
||||
profiles = super.getProfileTagsForEncoding(resource, profiles);
|
||||
|
||||
TagList tags = getMetaTagsForEncoding((resource));
|
||||
TagList tags = getMetaTagsForEncoding((resource), theEncodeContext);
|
||||
|
||||
if (super.shouldEncodeResourceMeta(resource) && ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) {
|
||||
theEventWriter.writeStartElement("meta");
|
||||
|
@ -526,7 +538,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
}
|
||||
for (BaseCodingDt securityLabel : securityLabels) {
|
||||
theEventWriter.writeStartElement("security");
|
||||
encodeCompositeElementToStreamWriter(resource, securityLabel, theEventWriter, theContainedResource, theSubResource, null);
|
||||
encodeCompositeElementToStreamWriter(resource, securityLabel, theEventWriter, theContainedResource, null, theEncodeContext);
|
||||
theEventWriter.writeEndElement();
|
||||
}
|
||||
if (tags != null) {
|
||||
|
@ -549,7 +561,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
writeOptionalTagWithValue(theEventWriter, "contentType", bin.getContentType());
|
||||
writeOptionalTagWithValue(theEventWriter, "content", bin.getContentAsBase64());
|
||||
} else {
|
||||
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, theContainedResource, theSubResource, new CompositeChildElement(resDef, theSubResource));
|
||||
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, theContainedResource, new CompositeChildElement(resDef, theEncodeContext), theEncodeContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -557,8 +569,8 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
theEventWriter.writeEndElement();
|
||||
}
|
||||
|
||||
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theEventWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource, boolean theSubResource)
|
||||
throws XMLStreamException, DataFormatException {
|
||||
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theEventWriter, List<? extends IBaseExtension<?, ?>> theExtensions, String tagName, boolean theIncludedResource, EncodeContext theEncodeContext)
|
||||
throws XMLStreamException, DataFormatException {
|
||||
for (IBaseExtension<?, ?> next : theExtensions) {
|
||||
if (next == null || (ElementUtil.isEmpty(next.getValue()) && next.getExtension().isEmpty())) {
|
||||
continue;
|
||||
|
@ -593,11 +605,11 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
|
||||
}
|
||||
}
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, value, childName, childDef, null, theIncludedResource, theSubResource, null);
|
||||
encodeChildElementToStreamWriter(theResource, theEventWriter, value, childName, childDef, null, theIncludedResource, null, theEncodeContext);
|
||||
}
|
||||
|
||||
// child extensions
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, next, theIncludedResource,theSubResource);
|
||||
encodeExtensionsIfPresent(theResource, theEventWriter, next, theIncludedResource, theEncodeContext);
|
||||
|
||||
theEventWriter.writeEndElement();
|
||||
|
||||
|
@ -617,86 +629,86 @@ public class XmlParser extends BaseParser /* implements IParser */ {
|
|||
|
||||
for (XMLEvent event : events) {
|
||||
switch (event.getEventType()) {
|
||||
case XMLStreamConstants.ATTRIBUTE:
|
||||
Attribute attr = (Attribute) event;
|
||||
if (isBlank(attr.getName().getPrefix())) {
|
||||
if (isBlank(attr.getName().getNamespaceURI())) {
|
||||
theEventWriter.writeAttribute(attr.getName().getLocalPart(), attr.getValue());
|
||||
} else {
|
||||
theEventWriter.writeAttribute(attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue());
|
||||
}
|
||||
} else {
|
||||
theEventWriter.writeAttribute(attr.getName().getPrefix(), attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue());
|
||||
}
|
||||
|
||||
break;
|
||||
case XMLStreamConstants.CDATA:
|
||||
theEventWriter.writeCData(((Characters) event).getData());
|
||||
break;
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
String data = ((Characters) event).getData();
|
||||
theEventWriter.writeCharacters(data);
|
||||
break;
|
||||
case XMLStreamConstants.COMMENT:
|
||||
theEventWriter.writeComment(((Comment) event).getText());
|
||||
break;
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
case XMLStreamConstants.ENTITY_REFERENCE:
|
||||
EntityReference er = (EntityReference) event;
|
||||
theEventWriter.writeEntityRef(er.getName());
|
||||
break;
|
||||
case XMLStreamConstants.NAMESPACE:
|
||||
Namespace ns = (Namespace) event;
|
||||
theEventWriter.writeNamespace(ns.getPrefix(), ns.getNamespaceURI());
|
||||
break;
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
StartElement se = event.asStartElement();
|
||||
if (firstElement) {
|
||||
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
||||
String namespaceURI = se.getName().getNamespaceURI();
|
||||
if (StringUtils.isBlank(namespaceURI)) {
|
||||
namespaceURI = "http://www.w3.org/1999/xhtml";
|
||||
}
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
theEventWriter.writeDefaultNamespace(namespaceURI);
|
||||
} else {
|
||||
String prefix = se.getName().getPrefix();
|
||||
String namespaceURI = se.getName().getNamespaceURI();
|
||||
theEventWriter.writeStartElement(prefix, se.getName().getLocalPart(), namespaceURI);
|
||||
theEventWriter.writeNamespace(prefix, namespaceURI);
|
||||
}
|
||||
firstElement = false;
|
||||
} else {
|
||||
if (isBlank(se.getName().getPrefix())) {
|
||||
if (isBlank(se.getName().getNamespaceURI())) {
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
case XMLStreamConstants.ATTRIBUTE:
|
||||
Attribute attr = (Attribute) event;
|
||||
if (isBlank(attr.getName().getPrefix())) {
|
||||
if (isBlank(attr.getName().getNamespaceURI())) {
|
||||
theEventWriter.writeAttribute(attr.getName().getLocalPart(), attr.getValue());
|
||||
} else {
|
||||
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
// theEventWriter.writeDefaultNamespace(se.getName().getNamespaceURI());
|
||||
} else {
|
||||
theEventWriter.writeStartElement(se.getName().getNamespaceURI(), se.getName().getLocalPart());
|
||||
}
|
||||
theEventWriter.writeAttribute(attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue());
|
||||
}
|
||||
} else {
|
||||
theEventWriter.writeStartElement(se.getName().getPrefix(), se.getName().getLocalPart(), se.getName().getNamespaceURI());
|
||||
theEventWriter.writeAttribute(attr.getName().getPrefix(), attr.getName().getNamespaceURI(), attr.getName().getLocalPart(), attr.getValue());
|
||||
}
|
||||
for (Iterator<?> attrIter = se.getAttributes(); attrIter.hasNext();) {
|
||||
Attribute next = (Attribute) attrIter.next();
|
||||
theEventWriter.writeAttribute(next.getName().getLocalPart(), next.getValue());
|
||||
|
||||
break;
|
||||
case XMLStreamConstants.CDATA:
|
||||
theEventWriter.writeCData(((Characters) event).getData());
|
||||
break;
|
||||
case XMLStreamConstants.CHARACTERS:
|
||||
case XMLStreamConstants.SPACE:
|
||||
String data = ((Characters) event).getData();
|
||||
theEventWriter.writeCharacters(data);
|
||||
break;
|
||||
case XMLStreamConstants.COMMENT:
|
||||
theEventWriter.writeComment(((Comment) event).getText());
|
||||
break;
|
||||
case XMLStreamConstants.END_ELEMENT:
|
||||
theEventWriter.writeEndElement();
|
||||
break;
|
||||
case XMLStreamConstants.ENTITY_REFERENCE:
|
||||
EntityReference er = (EntityReference) event;
|
||||
theEventWriter.writeEntityRef(er.getName());
|
||||
break;
|
||||
case XMLStreamConstants.NAMESPACE:
|
||||
Namespace ns = (Namespace) event;
|
||||
theEventWriter.writeNamespace(ns.getPrefix(), ns.getNamespaceURI());
|
||||
break;
|
||||
case XMLStreamConstants.START_ELEMENT:
|
||||
StartElement se = event.asStartElement();
|
||||
if (firstElement) {
|
||||
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
||||
String namespaceURI = se.getName().getNamespaceURI();
|
||||
if (StringUtils.isBlank(namespaceURI)) {
|
||||
namespaceURI = "http://www.w3.org/1999/xhtml";
|
||||
}
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
theEventWriter.writeDefaultNamespace(namespaceURI);
|
||||
} else {
|
||||
String prefix = se.getName().getPrefix();
|
||||
String namespaceURI = se.getName().getNamespaceURI();
|
||||
theEventWriter.writeStartElement(prefix, se.getName().getLocalPart(), namespaceURI);
|
||||
theEventWriter.writeNamespace(prefix, namespaceURI);
|
||||
}
|
||||
firstElement = false;
|
||||
} else {
|
||||
if (isBlank(se.getName().getPrefix())) {
|
||||
if (isBlank(se.getName().getNamespaceURI())) {
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
} else {
|
||||
if (StringUtils.isBlank(se.getName().getPrefix())) {
|
||||
theEventWriter.writeStartElement(se.getName().getLocalPart());
|
||||
// theEventWriter.writeDefaultNamespace(se.getName().getNamespaceURI());
|
||||
} else {
|
||||
theEventWriter.writeStartElement(se.getName().getNamespaceURI(), se.getName().getLocalPart());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
theEventWriter.writeStartElement(se.getName().getPrefix(), se.getName().getLocalPart(), se.getName().getNamespaceURI());
|
||||
}
|
||||
for (Iterator<?> attrIter = se.getAttributes(); attrIter.hasNext(); ) {
|
||||
Attribute next = (Attribute) attrIter.next();
|
||||
theEventWriter.writeAttribute(next.getName().getLocalPart(), next.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case XMLStreamConstants.DTD:
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
case XMLStreamConstants.ENTITY_DECLARATION:
|
||||
case XMLStreamConstants.NOTATION_DECLARATION:
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION:
|
||||
case XMLStreamConstants.START_DOCUMENT:
|
||||
break;
|
||||
break;
|
||||
case XMLStreamConstants.DTD:
|
||||
case XMLStreamConstants.END_DOCUMENT:
|
||||
case XMLStreamConstants.ENTITY_DECLARATION:
|
||||
case XMLStreamConstants.NOTATION_DECLARATION:
|
||||
case XMLStreamConstants.PROCESSING_INSTRUCTION:
|
||||
case XMLStreamConstants.START_DOCUMENT:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ public class Constants {
|
|||
public static final String PARAM_COUNT = "_count";
|
||||
public static final String PARAM_DELETE = "_delete";
|
||||
public static final String PARAM_ELEMENTS = "_elements";
|
||||
public static final String PARAM_ELEMENTS_EXCLUDE_MODIFIER = ":exclude";
|
||||
public static final String PARAM_FORMAT = "_format";
|
||||
public static final String PARAM_HAS = "_has";
|
||||
public static final String PARAM_HISTORY = "_history";
|
||||
|
|
|
@ -106,6 +106,9 @@ public enum EncodingEnum {
|
|||
myFormatContentType = theFormatContentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>xml</code> or <code>json</code> as used on the <code>_format</code> search parameter
|
||||
*/
|
||||
public String getFormatContentType() {
|
||||
return myFormatContentType;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.util;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -55,6 +56,24 @@ public class PortUtil {
|
|||
server = new ServerSocket(0);
|
||||
server.setReuseAddress(true);
|
||||
int port = server.getLocalPort();
|
||||
|
||||
/*
|
||||
* Try to connect to the newly allocated port to make sure
|
||||
* it's free
|
||||
*/
|
||||
for (int i = 0; i < 10; i++) {
|
||||
try {
|
||||
Socket client = new Socket();
|
||||
client.connect(new InetSocketAddress(port), 1000);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (i == 9) {
|
||||
throw new InternalErrorException("Can not connect to port: " + port);
|
||||
}
|
||||
Thread.sleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
server.close();
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class PortUtilTest {
|
||||
|
||||
@Test
|
||||
public void testFindFreePort() throws IOException {
|
||||
int port = PortUtil.findFreePort();
|
||||
|
||||
// First bind should succeed, second bind should fail
|
||||
try (ServerSocket ss = new ServerSocket()) {
|
||||
ss.bind(new InetSocketAddress("0.0.0.0", port));
|
||||
|
||||
try (ServerSocket ss2 = new ServerSocket()) {
|
||||
ss2.bind(new InetSocketAddress("0.0.0.0", port));
|
||||
fail();
|
||||
} catch (IOException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -84,7 +84,7 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
|||
|
||||
/**
|
||||
* This method returns the server base, including the resource path.
|
||||
* {@link javax.ws.rs.core.UriInfo#getBaseUri() UriInfo#getBaseUri()}
|
||||
* {@link UriInfo#getBaseUri() UriInfo#getBaseUri()}
|
||||
*
|
||||
* @return the ascii string for the base resource provider path
|
||||
*/
|
||||
|
@ -119,6 +119,14 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
|||
return ETagSupportEnum.DISABLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT = {@link ElementsSupportEnum#STANDARD}
|
||||
*/
|
||||
@Override
|
||||
public ElementsSupportEnum getElementsSupport() {
|
||||
return ElementsSupportEnum.STANDARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FhirContext getFhirContext() {
|
||||
return CTX;
|
||||
|
@ -243,14 +251,6 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* DEFAULT = false
|
||||
*/
|
||||
@Override
|
||||
public boolean isUseBrowserFriendlyContentTypes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the headers
|
||||
*
|
||||
|
|
|
@ -150,11 +150,6 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseBrowserFriendlyContentTypes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}/$firstVersion")
|
||||
public Response operationFirstVersionUsingGet(@PathParam("id") String id) throws IOException {
|
||||
|
|
|
@ -151,11 +151,6 @@ public class JaxRsPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUseBrowserFriendlyContentTypes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("/{id}/$firstVersion")
|
||||
public Response operationFirstVersionUsingGet(@PathParam("id") String id) throws IOException {
|
||||
|
|
|
@ -102,10 +102,10 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
|||
|
||||
// Only delete if we don't have results left in this search
|
||||
if (resultPids.getNumberOfElements() < max) {
|
||||
ourLog.info("Deleting search {}/{} - Created[{}] -- Last returned[{}]", searchToDelete.getId(), searchToDelete.getUuid(), new InstantType(searchToDelete.getCreated()), new InstantType(searchToDelete.getSearchLastReturned()));
|
||||
ourLog.debug("Deleting search {}/{} - Created[{}] -- Last returned[{}]", searchToDelete.getId(), searchToDelete.getUuid(), new InstantType(searchToDelete.getCreated()), new InstantType(searchToDelete.getSearchLastReturned()));
|
||||
mySearchDao.deleteByPid(searchToDelete.getId());
|
||||
} else {
|
||||
ourLog.info("Purged {} search results for deleted search {}/{}", resultPids.getSize(), searchToDelete.getId(), searchToDelete.getUuid());
|
||||
ourLog.debug("Purged {} search results for deleted search {}/{}", resultPids.getSize(), searchToDelete.getId(), searchToDelete.getUuid());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -149,7 +149,7 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
|
|||
int count = toDelete.getContent().size();
|
||||
if (count > 0) {
|
||||
long total = tt.execute(t -> mySearchDao.count());
|
||||
ourLog.info("Deleted {} searches, {} remaining", count, total);
|
||||
ourLog.debug("Deleted {} searches, {} remaining", count, total);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ public class SystemProviderTransactionSearchDstu2Test extends BaseJpaDstu2Test {
|
|||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setMaximumSearchResultCountInTransaction(new DaoConfig().getMaximumSearchResultCountInTransaction());
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ public class SystemProviderTransactionSearchDstu3Test extends BaseJpaDstu3Test {
|
|||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setMaximumSearchResultCountInTransaction(new DaoConfig().getMaximumSearchResultCountInTransaction());
|
||||
}
|
||||
|
|
|
@ -62,7 +62,6 @@ public class EmptyIndexesR4Test extends BaseJpaR4Test {
|
|||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||
}
|
||||
|
|
|
@ -67,7 +67,6 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
}
|
||||
|
||||
|
@ -250,7 +249,6 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testResponseUsesCorrectContentType() throws Exception {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
myRestServer.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase);
|
||||
|
|
|
@ -51,7 +51,6 @@ public class SystemProviderTransactionSearchR4Test extends BaseJpaR4Test {
|
|||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
myDaoConfig.setMaximumSearchResultCountInTransaction(new DaoConfig().getMaximumSearchResultCountInTransaction());
|
||||
}
|
||||
|
|
|
@ -15,10 +15,7 @@ import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
|||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.BanUnsupportedHttpMethodsInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
|
@ -204,6 +201,11 @@ public class TestRestfulServer extends RestfulServer {
|
|||
setDefaultPrettyPrint(true);
|
||||
setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
/*
|
||||
* Use extended support for the _elements parameter
|
||||
*/
|
||||
setElementsSupport(ElementsSupportEnum.EXTENDED);
|
||||
|
||||
/*
|
||||
* The server's base URL (e.g. http://fhirtest.uhn.ca/baseDstu2) is
|
||||
* pulled from a system property, which is helpful if you want to try
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
/**
|
||||
* @see <a href="http://hapifhir.io/doc_rest_server.html#extended_elements_support">Extended Elements Support</a>
|
||||
*/
|
||||
public enum ElementsSupportEnum {
|
||||
|
||||
/**
|
||||
* The server will support only the FHIR standard features for the <code>_elements</code>
|
||||
* parameter.
|
||||
*
|
||||
* @see <a href="http://hl7.org/fhir/search.html#elements">http://hl7.org/fhir/search.html#elements</a>
|
||||
*/
|
||||
STANDARD,
|
||||
|
||||
/**
|
||||
* The server will support both the standard features as well as support for elements
|
||||
* exclusion.
|
||||
*/
|
||||
EXTENDED
|
||||
|
||||
}
|
|
@ -49,6 +49,13 @@ public interface IRestfulServerDefaults {
|
|||
*/
|
||||
ETagSupportEnum getETagSupport();
|
||||
|
||||
/**
|
||||
* @return Returns the support option for the <code>_elements</code> parameter on search
|
||||
* and read operations.
|
||||
* @see <a href="http://hapifhir.io/doc_rest_server.html#extended_elements_support">Extended Elements Support</a>
|
||||
*/
|
||||
ElementsSupportEnum getElementsSupport();
|
||||
|
||||
/**
|
||||
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain
|
||||
* providers should generally use this context if one is needed, as opposed to
|
||||
|
@ -78,12 +85,6 @@ public interface IRestfulServerDefaults {
|
|||
*/
|
||||
boolean isDefaultPrettyPrint();
|
||||
|
||||
/**
|
||||
* @return If <code>true</code> the server will use browser friendly content-types (instead of standard FHIR ones)
|
||||
* when it detects that the request is coming from a browser
|
||||
* instead of a FHIR
|
||||
*/
|
||||
boolean isUseBrowserFriendlyContentTypes();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
|
|||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ExceptionHandlingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.method.ConformanceMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
|
@ -126,10 +125,10 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
private String myServerVersion = createPoweredByHeaderProductVersion();
|
||||
private boolean myStarted;
|
||||
private boolean myUncompressIncomingContents = true;
|
||||
private boolean myUseBrowserFriendlyContentTypes;
|
||||
private ITenantIdentificationStrategy myTenantIdentificationStrategy;
|
||||
private Date myConformanceDate;
|
||||
private PreferReturnEnum myDefaultPreferReturn = DEFAULT_PREFER_RETURN;
|
||||
private ElementsSupportEnum myElementsSupport = ElementsSupportEnum.EXTENDED;
|
||||
|
||||
/**
|
||||
* Constructor. Note that if no {@link FhirContext} is passed in to the server (either through the constructor, or
|
||||
|
@ -500,6 +499,21 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
return myETagSupport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ElementsSupportEnum getElementsSupport() {
|
||||
return myElementsSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the elements support mode.
|
||||
*
|
||||
* @see <a href="http://hapifhir.io/doc_rest_server.html#extended_elements_support">Extended Elements Support</a>
|
||||
*/
|
||||
public void setElementsSupport(ElementsSupportEnum theElementsSupport) {
|
||||
Validate.notNull(theElementsSupport, "theElementsSupport must not be null");
|
||||
myElementsSupport = theElementsSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets (enables/disables) the server support for ETags. Must not be <code>null</code>. Default is
|
||||
* {@link #DEFAULT_ETAG_SUPPORT}
|
||||
|
@ -1025,6 +1039,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
*/
|
||||
requestDetails.removeParameter(Constants.PARAM_SUMMARY);
|
||||
requestDetails.removeParameter(Constants.PARAM_ELEMENTS);
|
||||
requestDetails.removeParameter(Constants.PARAM_ELEMENTS + Constants.PARAM_ELEMENTS_EXCLUDE_MODIFIER);
|
||||
|
||||
/*
|
||||
* If nobody handles it, default behaviour is to stream back the OperationOutcome to the client.
|
||||
|
@ -1251,26 +1266,6 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
|
|||
myUncompressIncomingContents = theUncompressIncomingContents;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This feature did not work well, and will be removed. Use {@link ResponseHighlighterInterceptor}
|
||||
* instead as an interceptor on your server and it will provide more useful syntax
|
||||
* highlighting. Deprocated in 1.4
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean isUseBrowserFriendlyContentTypes() {
|
||||
return myUseBrowserFriendlyContentTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This feature did not work well, and will be removed. Use {@link ResponseHighlighterInterceptor}
|
||||
* instead as an interceptor on your server and it will provide more useful syntax
|
||||
* highlighting. Deprocated in 1.4
|
||||
*/
|
||||
@Deprecated
|
||||
public void setUseBrowserFriendlyContentTypes(boolean theUseBrowserFriendlyContentTypes) {
|
||||
myUseBrowserFriendlyContentTypes = theUseBrowserFriendlyContentTypes;
|
||||
}
|
||||
|
||||
public void populateRequestDetailsFromRequestPath(RequestDetails theRequestDetails, String theRequestPath) {
|
||||
UrlPathTokenizer tok = new UrlPathTokenizer(theRequestPath);
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server;
|
|||
* 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.
|
||||
|
@ -46,6 +46,7 @@ import java.io.Writer;
|
|||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
|
@ -54,7 +55,7 @@ public class RestfulServerUtils {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulServerUtils.class);
|
||||
|
||||
private static final HashSet<String> TEXT_ENCODE_ELEMENTS = new HashSet<String>(Arrays.asList("Bundle", "*.text", "*.(mandatory)"));
|
||||
private static final HashSet<String> TEXT_ENCODE_ELEMENTS = new HashSet<>(Arrays.asList("*.text", "*.id", "*.meta", "*.(mandatory)"));
|
||||
private static Map<FhirVersionEnum, FhirContext> myFhirContextMap = Collections.synchronizedMap(new HashMap<FhirVersionEnum, FhirContext>());
|
||||
|
||||
private enum NarrativeModeEnum {
|
||||
|
@ -125,13 +126,15 @@ public class RestfulServerUtils {
|
|||
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequestDetails);
|
||||
|
||||
// _elements
|
||||
Set<String> elements = ElementsParameter.getElementsValueOrNull(theRequestDetails);
|
||||
Set<String> elements = ElementsParameter.getElementsValueOrNull(theRequestDetails, false);
|
||||
if (elements != null && summaryMode != null && !summaryMode.equals(Collections.singleton(SummaryEnum.FALSE))) {
|
||||
throw new InvalidRequestException("Cannot combine the " + Constants.PARAM_SUMMARY + " and " + Constants.PARAM_ELEMENTS + " parameters");
|
||||
}
|
||||
Set<String> elementsAppliesTo = null;
|
||||
if (elements != null && isNotBlank(theRequestDetails.getResourceName())) {
|
||||
elementsAppliesTo = Collections.singleton(theRequestDetails.getResourceName());
|
||||
|
||||
// _elements:exclude
|
||||
Set<String> elementsExclude = ElementsParameter.getElementsValueOrNull(theRequestDetails, true);
|
||||
if (elementsExclude != null) {
|
||||
parser.setDontEncodeElements(elementsExclude);
|
||||
}
|
||||
|
||||
if (summaryMode != null) {
|
||||
|
@ -139,15 +142,27 @@ public class RestfulServerUtils {
|
|||
parser.setEncodeElements(Collections.singleton("Bundle.total"));
|
||||
} else if (summaryMode.contains(SummaryEnum.TEXT) && summaryMode.size() == 1) {
|
||||
parser.setEncodeElements(TEXT_ENCODE_ELEMENTS);
|
||||
parser.setEncodeElementsAppliesToChildResourcesOnly(true);
|
||||
} else {
|
||||
parser.setSuppressNarratives(summaryMode.contains(SummaryEnum.DATA));
|
||||
parser.setSummaryMode(summaryMode.contains(SummaryEnum.TRUE));
|
||||
}
|
||||
}
|
||||
if (elements != null && elements.size() > 0) {
|
||||
String elementsAppliesTo = "*";
|
||||
if (isNotBlank(theRequestDetails.getResourceName())) {
|
||||
elementsAppliesTo = theRequestDetails.getResourceName();
|
||||
}
|
||||
|
||||
Set<String> newElements = new HashSet<>();
|
||||
for (String next : elements) {
|
||||
newElements.add("*." + next);
|
||||
if (isNotBlank(next)) {
|
||||
if (Character.isUpperCase(next.charAt(0))) {
|
||||
newElements.add(next);
|
||||
} else {
|
||||
newElements.add(elementsAppliesTo + "." + next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -158,6 +173,13 @@ public class RestfulServerUtils {
|
|||
* the client has explicitly scoped the Bundle
|
||||
* (i.e. with Bundle.total or something like that)
|
||||
*/
|
||||
boolean haveExplicitBundleElement = false;
|
||||
for (String next : newElements) {
|
||||
if (next.startsWith("Bundle.")) {
|
||||
haveExplicitBundleElement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (theRequestDetails.getRestOperationType()) {
|
||||
case SEARCH_SYSTEM:
|
||||
case SEARCH_TYPE:
|
||||
|
@ -165,13 +187,6 @@ public class RestfulServerUtils {
|
|||
case HISTORY_TYPE:
|
||||
case HISTORY_INSTANCE:
|
||||
case GET_PAGE:
|
||||
boolean haveExplicitBundleElement = false;
|
||||
for (String next : newElements) {
|
||||
if (next.startsWith("Bundle.")) {
|
||||
haveExplicitBundleElement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!haveExplicitBundleElement) {
|
||||
parser.setEncodeElementsAppliesToChildResourcesOnly(true);
|
||||
}
|
||||
|
@ -181,26 +196,28 @@ public class RestfulServerUtils {
|
|||
}
|
||||
|
||||
parser.setEncodeElements(newElements);
|
||||
parser.setEncodeElementsAppliesToResourceTypes(elementsAppliesTo);
|
||||
}
|
||||
}
|
||||
|
||||
public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, int theOffset, int theCount, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
|
||||
public static String createPagingLink(Set<Include> theIncludes, RequestDetails theRequestDetails, String theSearchId, int theOffset, int theCount, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
|
||||
BundleTypeEnum theBundleType) {
|
||||
return createPagingLink(theIncludes, theServerBase, theSearchId, theOffset, theCount, theRequestParameters, thePrettyPrint,
|
||||
return createPagingLink(theIncludes, theRequestDetails, theSearchId, theOffset, theCount, theRequestParameters, thePrettyPrint,
|
||||
theBundleType, null);
|
||||
}
|
||||
|
||||
public static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, String thePageId, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
|
||||
public static String createPagingLink(Set<Include> theIncludes, RequestDetails theRequestDetails, String theSearchId, String thePageId, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
|
||||
BundleTypeEnum theBundleType) {
|
||||
return createPagingLink(theIncludes, theServerBase, theSearchId, null, null, theRequestParameters, thePrettyPrint,
|
||||
return createPagingLink(theIncludes, theRequestDetails, theSearchId, null, null, theRequestParameters, thePrettyPrint,
|
||||
theBundleType, thePageId);
|
||||
}
|
||||
|
||||
private static String createPagingLink(Set<Include> theIncludes, String theServerBase, String theSearchId, Integer theOffset, Integer theCount, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
|
||||
private static String createPagingLink(Set<Include> theIncludes, RequestDetails theRequestDetails, String theSearchId, Integer theOffset, Integer theCount, Map<String, String[]> theRequestParameters, boolean thePrettyPrint,
|
||||
BundleTypeEnum theBundleType, String thePageId) {
|
||||
|
||||
String serverBase = theRequestDetails.getFhirServerBase();
|
||||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append(theServerBase);
|
||||
b.append(serverBase);
|
||||
b.append('?');
|
||||
b.append(Constants.PARAM_PAGINGACTION);
|
||||
b.append('=');
|
||||
|
@ -258,16 +275,33 @@ public class RestfulServerUtils {
|
|||
b.append(theBundleType.getCode());
|
||||
}
|
||||
|
||||
String paramName = Constants.PARAM_ELEMENTS;
|
||||
String[] params = theRequestParameters.get(paramName);
|
||||
if (params != null) {
|
||||
for (String nextValue : params) {
|
||||
if (isNotBlank(nextValue)) {
|
||||
b.append('&');
|
||||
b.append(paramName);
|
||||
b.append('=');
|
||||
b.append(UrlUtil.escapeUrlParam(nextValue));
|
||||
}
|
||||
// _elements
|
||||
Set<String> elements = ElementsParameter.getElementsValueOrNull(theRequestDetails, false);
|
||||
if (elements != null) {
|
||||
b.append('&');
|
||||
b.append(Constants.PARAM_ELEMENTS);
|
||||
b.append('=');
|
||||
String nextValue = elements
|
||||
.stream()
|
||||
.sorted()
|
||||
.map(UrlUtil::escapeUrlParam)
|
||||
.collect(Collectors.joining(","));
|
||||
b.append(nextValue);
|
||||
}
|
||||
|
||||
// _elements:exclude
|
||||
if (theRequestDetails.getServer().getElementsSupport() == ElementsSupportEnum.EXTENDED) {
|
||||
Set<String> elementsExclude = ElementsParameter.getElementsValueOrNull(theRequestDetails, true);
|
||||
if (elementsExclude != null) {
|
||||
b.append('&');
|
||||
b.append(Constants.PARAM_ELEMENTS + Constants.PARAM_ELEMENTS_EXCLUDE_MODIFIER);
|
||||
b.append('=');
|
||||
String nextValue = elementsExclude
|
||||
.stream()
|
||||
.sorted()
|
||||
.map(UrlUtil::escapeUrlParam)
|
||||
.collect(Collectors.joining(","));
|
||||
b.append(nextValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -192,19 +192,19 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
// We're doing named pages
|
||||
searchId = theResult.getUuid();
|
||||
if (isNotBlank(theResult.getNextPageId())) {
|
||||
linkNext = RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, theResult.getNextPageId(), theRequest.getParameters(), prettyPrint, theBundleType);
|
||||
linkNext = RestfulServerUtils.createPagingLink(theIncludes, theRequest, searchId, theResult.getNextPageId(), theRequest.getParameters(), prettyPrint, theBundleType);
|
||||
}
|
||||
if (isNotBlank(theResult.getPreviousPageId())) {
|
||||
linkPrev = RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, theResult.getPreviousPageId(), theRequest.getParameters(), prettyPrint, theBundleType);
|
||||
linkPrev = RestfulServerUtils.createPagingLink(theIncludes, theRequest, searchId, theResult.getPreviousPageId(), theRequest.getParameters(), prettyPrint, theBundleType);
|
||||
}
|
||||
} else if (searchId != null) {
|
||||
// We're doing offset pages
|
||||
if (numTotalResults == null || theOffset + numToReturn < numTotalResults) {
|
||||
linkNext = (RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, theOffset + numToReturn, numToReturn, theRequest.getParameters(), prettyPrint, theBundleType));
|
||||
linkNext = (RestfulServerUtils.createPagingLink(theIncludes, theRequest, searchId, theOffset + numToReturn, numToReturn, theRequest.getParameters(), prettyPrint, theBundleType));
|
||||
}
|
||||
if (theOffset > 0) {
|
||||
int start = Math.max(0, theOffset - theLimit);
|
||||
linkPrev = RestfulServerUtils.createPagingLink(theIncludes, serverBase, searchId, start, theLimit, theRequest.getParameters(), prettyPrint, theBundleType);
|
||||
linkPrev = RestfulServerUtils.createPagingLink(theIncludes, theRequest, searchId, start, theLimit, theRequest.getParameters(), prettyPrint, theBundleType);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.rest.server.method;
|
|||
* 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.
|
||||
|
@ -19,20 +19,24 @@ package ca.uhn.fhir.rest.server.method;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.binder.CollectionBinder;
|
||||
import ca.uhn.fhir.rest.server.ElementsSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class ElementsParameter implements IParameter {
|
||||
|
||||
|
@ -40,9 +44,9 @@ public class ElementsParameter implements IParameter {
|
|||
private Class<? extends Collection> myInnerCollectionType;
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
||||
Set<String> value = getElementsValueOrNull(theRequest);
|
||||
Set<String> value = getElementsValueOrNull(theRequest, false);
|
||||
if (value == null || value.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -62,8 +66,28 @@ public class ElementsParameter implements IParameter {
|
|||
}
|
||||
}
|
||||
|
||||
public static Set<String> getElementsValueOrNull(RequestDetails theRequest) {
|
||||
String[] summary = theRequest.getParameters().get(Constants.PARAM_ELEMENTS);
|
||||
@Override
|
||||
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
|
||||
if (theOuterCollectionType != null) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
|
||||
+ " but can not be a collection of collections");
|
||||
}
|
||||
if (theInnerCollectionType != null) {
|
||||
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
public static Set<String> getElementsValueOrNull(RequestDetails theRequest, boolean theExclude) {
|
||||
boolean standardMode = theRequest.getServer().getElementsSupport() != ElementsSupportEnum.EXTENDED;
|
||||
if (theExclude && standardMode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String paramName = Constants.PARAM_ELEMENTS;
|
||||
if (theExclude) {
|
||||
paramName = Constants.PARAM_ELEMENTS + Constants.PARAM_ELEMENTS_EXCLUDE_MODIFIER;
|
||||
}
|
||||
String[] summary = theRequest.getParameters().get(paramName);
|
||||
|
||||
if (summary != null && summary.length > 0) {
|
||||
Set<String> retVal = new HashSet<String>();
|
||||
|
@ -72,6 +96,9 @@ public class ElementsParameter implements IParameter {
|
|||
while (tok.hasMoreTokens()) {
|
||||
String token = tok.nextToken();
|
||||
if (isNotBlank(token)) {
|
||||
if (token.contains(".") && standardMode) {
|
||||
continue;
|
||||
}
|
||||
retVal.add(token);
|
||||
}
|
||||
}
|
||||
|
@ -81,22 +108,13 @@ public class ElementsParameter implements IParameter {
|
|||
}
|
||||
|
||||
// Always include the meta element even for subsetted values
|
||||
retVal.add("meta");
|
||||
if (!theExclude) {
|
||||
retVal.add("meta");
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
|
||||
if (theOuterCollectionType != null) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
|
||||
+ " but can not be a collection of collections");
|
||||
}
|
||||
if (theInnerCollectionType != null) {
|
||||
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1011,6 +1011,7 @@ public class JsonParserDstu2_1Test {
|
|||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
assertThat(out, not(containsString("SUBSETTED")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1630,7 +1630,7 @@ public class XmlParserDstu2_1Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setDontEncodeElements(Sets.newHashSet("Patient.meta"));
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Patient.name")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(patient);
|
||||
ourLog.info(out);
|
||||
|
@ -1639,6 +1639,7 @@ public class XmlParserDstu2_1Test {
|
|||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
assertThat(out, not(containsString("SUBSETTED")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1667,7 +1668,6 @@ public class XmlParserDstu2_1Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1679,7 +1679,6 @@ public class XmlParserDstu2_1Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -2701,12 +2700,6 @@ public class XmlParserDstu2_1Test {
|
|||
assertTrue(d.toString(), !d.hasDifferences());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
IGenericClient c = ourCtx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
|
||||
// c.registerInterceptor(new LoggingInterceptor(true));
|
||||
c.read().resource("Patient").withId("324").execute();
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient")
|
||||
public static class TestPatientFor327 extends Patient {
|
||||
|
||||
|
|
|
@ -1769,7 +1769,7 @@ public class XmlParserDstu2Test {
|
|||
|
||||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name", "Bundle.entry")));
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Patient.name", "Bundle.entry")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1780,8 +1780,7 @@ public class XmlParserDstu2Test {
|
|||
}
|
||||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Patient.name")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1792,8 +1791,7 @@ public class XmlParserDstu2Test {
|
|||
}
|
||||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1818,7 +1816,7 @@ public class XmlParserDstu2Test {
|
|||
|
||||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Bundle.entry", "*.text", "*.(mandatory)")));
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Bundle.entry", "*.text", "*.(mandatory)")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ElementsParamTest {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static Set<String> ourLastElements;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ElementsParamTest.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastElements = null;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadSummaryData() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_elements=name,maritalStatus");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML + Constants.CHARSET_UTF8_CTSUFFIX.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patien")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name", "maritalStatus"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSummaryTrue() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_elements=name");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML + Constants.CHARSET_UTF8_CTSUFFIX.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patien")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryData() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_elements=name,maritalStatus");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name", "maritalStatus"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryText() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_elements=text");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "text"));
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public Patient read(@IdParam IdDt theId, @Elements Set<String> theElements) {
|
||||
ourLastElements = theElements;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDiv("<div>THE DIV</div>");
|
||||
patient.addName().addFamily("FAMILY");
|
||||
patient.setMaritalStatus(MaritalStatusCodesEnum.D);
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient search(@Elements Set<String> theElements) {
|
||||
ourLastElements = theElements;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDiv("<div>THE DIV</div>");
|
||||
patient.addName().addFamily("FAMILY");
|
||||
patient.setMaritalStatus(MaritalStatusCodesEnum.D);
|
||||
return patient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1232,6 +1232,7 @@ public class JsonParserDstu3Test {
|
|||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
assertThat(out, not(containsString("SUBSETTED")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1862,6 +1862,7 @@ public class XmlParserDstu3Test {
|
|||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
assertThat(out, not(containsString("SUBSETTED")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1890,7 +1891,6 @@ public class XmlParserDstu3Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1902,7 +1902,6 @@ public class XmlParserDstu3Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.apache.commons.lang.StringUtils;
|
||||
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;
|
||||
|
@ -252,6 +253,7 @@ public class JsonParserR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testExcludeRootStuff() {
|
||||
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
|
||||
Set<String> excludes = new HashSet<>();
|
||||
|
|
|
@ -0,0 +1,320 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ElementsParamR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ElementsParamR4Test.class);
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static Set<String> ourLastElements;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static Procedure ourNextProcedure;
|
||||
private static RestfulServer ourServlet;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastElements = null;
|
||||
ourNextProcedure = null;
|
||||
ourServlet.setElementsSupport(new RestfulServer().getElementsSupport());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSummaryData() throws Exception {
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Patient/1?_elements=name,maritalStatus",
|
||||
Patient.class,
|
||||
patient -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patient")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name", "maritalStatus"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSummaryTrue() throws Exception {
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Patient/1?_elements=name",
|
||||
Patient.class,
|
||||
patient -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryData() throws Exception {
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Patient?_elements=name,maritalStatus",
|
||||
bundle -> {
|
||||
assertEquals("1", bundle.getTotalElement().getValueAsString());
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle.getEntry().get(0).getResource());
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name", "maritalStatus"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryText() throws Exception {
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Patient?_elements=text&_pretty=true",
|
||||
bundle -> {
|
||||
assertEquals("1", bundle.getTotalElement().getValueAsString());
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle.getEntry().get(0).getResource());
|
||||
assertThat(responseContent, containsString("THE DIV"));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "text"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default the elements apply only to the focal resource in a search
|
||||
* and not any included resources
|
||||
*/
|
||||
@Test
|
||||
public void testStandardElementsFilter() throws IOException {
|
||||
createProcedureWithLongChain();
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Procedure?_include=*&_elements=reasonCode,status",
|
||||
bundle -> {
|
||||
Procedure procedure = (Procedure) bundle.getEntry().get(0).getResource();
|
||||
assertEquals("SUBSETTED", procedure.getMeta().getTag().get(0).getCode());
|
||||
assertEquals("REASON_CODE", procedure.getReasonCode().get(0).getCoding().get(0).getCode());
|
||||
assertEquals(0, procedure.getUsedCode().size());
|
||||
|
||||
DiagnosticReport dr = (DiagnosticReport) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(0, dr.getMeta().getTag().size());
|
||||
assertEquals("Observation/OBSA", dr.getResult().get(0).getReference());
|
||||
|
||||
Observation obs = (Observation ) bundle.getEntry().get(2).getResource();
|
||||
assertEquals(0, obs.getMeta().getTag().size());
|
||||
assertEquals(Observation.ObservationStatus.FINAL, obs.getStatus());
|
||||
assertEquals("1234-5", obs.getCode().getCoding().get(0).getCode());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiResourceElementsFilter() throws IOException {
|
||||
createProcedureWithLongChain();
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Procedure?_include=*&_elements=Procedure.reasonCode,Observation.status,Observation.subject,Observation.value",
|
||||
bundle -> {
|
||||
Procedure procedure = (Procedure) bundle.getEntry().get(0).getResource();
|
||||
assertEquals("SUBSETTED", procedure.getMeta().getTag().get(0).getCode());
|
||||
assertEquals("REASON_CODE", procedure.getReasonCode().get(0).getCoding().get(0).getCode());
|
||||
assertEquals(0, procedure.getUsedCode().size());
|
||||
|
||||
DiagnosticReport dr = (DiagnosticReport) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(0, dr.getMeta().getTag().size());
|
||||
|
||||
Observation obs = (Observation ) bundle.getEntry().get(2).getResource();
|
||||
assertEquals("SUBSETTED", obs.getMeta().getTag().get(0).getCode());
|
||||
assertEquals(Observation.ObservationStatus.FINAL, obs.getStatus());
|
||||
assertEquals(0, obs.getCode().getCoding().size());
|
||||
assertEquals("STRING VALUE", obs.getValueStringType().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiResourceElementsFilterWithMetadataExcluded() throws IOException {
|
||||
createProcedureWithLongChain();
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Procedure?_include=*&_elements=Procedure.reasonCode,Observation.status,Observation.subject,Observation.value&_elements:exclude=*.meta",
|
||||
bundle -> {
|
||||
Procedure procedure = (Procedure) bundle.getEntry().get(0).getResource();
|
||||
assertEquals(true, procedure.getMeta().isEmpty());
|
||||
assertEquals("REASON_CODE", procedure.getReasonCode().get(0).getCoding().get(0).getCode());
|
||||
assertEquals(0, procedure.getUsedCode().size());
|
||||
|
||||
DiagnosticReport dr = (DiagnosticReport) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(true, dr.getMeta().isEmpty());
|
||||
|
||||
Observation obs = (Observation ) bundle.getEntry().get(2).getResource();
|
||||
assertEquals(true, obs.getMeta().isEmpty());
|
||||
assertEquals(Observation.ObservationStatus.FINAL, obs.getStatus());
|
||||
assertEquals(0, obs.getCode().getCoding().size());
|
||||
assertEquals("STRING VALUE", obs.getValueStringType().getValue());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testElementsFilterWithComplexPath() throws IOException {
|
||||
createProcedureWithLongChain();
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Procedure?_elements=Procedure.reasonCode.coding.code",
|
||||
bundle -> {
|
||||
Procedure procedure = (Procedure) bundle.getEntry().get(0).getResource();
|
||||
assertEquals("SUBSETTED", procedure.getMeta().getTag().get(0).getCode());
|
||||
assertEquals("REASON_CODE", procedure.getReasonCode().get(0).getCoding().get(0).getCode());
|
||||
assertEquals(null, procedure.getReasonCode().get(0).getCoding().get(0).getSystem());
|
||||
assertEquals(null, procedure.getReasonCode().get(0).getCoding().get(0).getDisplay());
|
||||
assertEquals(0, procedure.getUsedCode().size());
|
||||
});
|
||||
}
|
||||
|
||||
private void createProcedureWithLongChain() {
|
||||
ourNextProcedure = new Procedure();
|
||||
ourNextProcedure.setId("Procedure/PROC");
|
||||
ourNextProcedure.addReasonCode().addCoding().setCode("REASON_CODE").setSystem("REASON_SYSTEM").setDisplay("REASON_DISPLAY");
|
||||
ourNextProcedure.addUsedCode().addCoding().setCode("USED_CODE");
|
||||
|
||||
DiagnosticReport dr = new DiagnosticReport();
|
||||
dr.setId("DiagnosticReport/DRA");
|
||||
ourNextProcedure.addReport().setResource(dr);
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.setId("Observation/OBSA");
|
||||
obs.setStatus(Observation.ObservationStatus.FINAL);
|
||||
obs.setSubject(new Reference("Patient/123"));
|
||||
obs.getCode().addCoding().setSystem("http://loinc.org").setCode("1234-5");
|
||||
obs.setValue(new StringType("STRING VALUE"));
|
||||
dr.addResult().setResource(obs);
|
||||
}
|
||||
|
||||
private void verifyXmlAndJson(String theUri, Consumer<Bundle> theVerifier) throws IOException {
|
||||
verifyXmlAndJson(theUri, Bundle.class, theVerifier);
|
||||
}
|
||||
|
||||
private <T extends IBaseResource> void verifyXmlAndJson(String theUri, Class<T> theType, Consumer<T> theVerifier) throws IOException {
|
||||
EncodingEnum encodingEnum;
|
||||
HttpGet httpGet;
|
||||
|
||||
encodingEnum = EncodingEnum.JSON;
|
||||
httpGet = new HttpGet(theUri + "&_pretty=true&_format=" + encodingEnum.getFormatContentType());
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
T response = encodingEnum.newParser(ourCtx).parseResource(theType, responseContent);
|
||||
theVerifier.accept(response);
|
||||
}
|
||||
|
||||
encodingEnum = EncodingEnum.XML;
|
||||
httpGet = new HttpGet(theUri + "&_pretty=true&_format=" + encodingEnum.getFormatContentType());
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
T response = encodingEnum.newParser(ourCtx).parseResource(theType, responseContent);
|
||||
theVerifier.accept(response);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DummyProcedureResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Procedure.class;
|
||||
}
|
||||
|
||||
@Search
|
||||
public Procedure search(@IncludeParam(allow = {"*"}) Collection<Include> theIncludes) {
|
||||
return ourNextProcedure;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public Patient read(@IdParam IdType theId, @Elements Set<String> theElements) {
|
||||
ourLastElements = theElements;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().getDiv().setValueAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient search(@Elements Set<String> theElements) {
|
||||
ourLastElements = theElements;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().getDiv().setValueAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
ourServlet = new RestfulServer(ourCtx);
|
||||
|
||||
ourServlet.registerProvider(new DummyPatientResourceProvider());
|
||||
ourServlet.registerProvider(new DummyProcedureResourceProvider());
|
||||
ServletHolder servletHolder = new ServletHolder(ourServlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -89,36 +89,39 @@ public class SearchR4Test {
|
|||
String linkSelf;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_elements=name");
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_elements=name&_elements:exclude=birthDate,active");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkSelf = bundle.getLink(Constants.LINK_SELF).getUrl();
|
||||
assertThat(linkSelf, containsString("_elements=name"));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
|
||||
ourLog.info(toJson(bundle));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements:exclude=active,birthDate"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements:exclude=active,birthDate"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements:exclude=active,birthDate"));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -5,11 +5,13 @@ import ca.uhn.fhir.rest.annotation.IdParam;
|
|||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
@ -18,18 +20,17 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.MedicationRequest;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -37,11 +38,11 @@ import static org.junit.Assert.assertThat;
|
|||
|
||||
public class SummaryParamR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SummaryParamR4Test.class);
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static SummaryEnum ourLastSummary;
|
||||
private static List<SummaryEnum> ourLastSummaryList;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SummaryParamR4Test.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
|
@ -51,219 +52,316 @@ public class SummaryParamR4Test {
|
|||
ourLastSummary = null;
|
||||
ourLastSummaryList = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSummaryData() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.DATA.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW + Constants.CHARSET_UTF8_CTSUFFIX.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patien")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.DATA, ourLastSummary);
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.DATA.getCode(),
|
||||
Patient.class,
|
||||
patient -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patien")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.DATA, ourLastSummary);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadSummaryText() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.TEXT.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, not(containsString("<Medic")));
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">THE DIV</div>", responseContent);
|
||||
assertThat(responseContent, not(containsString("efer")));
|
||||
assertEquals(SummaryEnum.TEXT, ourLastSummary);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, not(containsString("<Medic")));
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">THE DIV</div>", responseContent);
|
||||
assertThat(responseContent, not(containsString("efer")));
|
||||
assertEquals(SummaryEnum.TEXT, ourLastSummary);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSummaryTextWithMandatory() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/MedicationRequest/1?_summary=" + SummaryEnum.TEXT.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, not(containsString("<Patien")));
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">TEXT</div>", responseContent);
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_HTML_WITH_UTF8.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, not(containsString("<Patien")));
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">TEXT</div>", responseContent);
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadSummaryTrue() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.TRUE.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
String url = "http://localhost:" + ourPort + "/Patient/1?_summary=" + SummaryEnum.TRUE.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
Patient.class,
|
||||
patient -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patien")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.TRUE, ourLastSummary);
|
||||
}
|
||||
);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertEquals(Constants.CT_FHIR_XML_NEW + Constants.CHARSET_UTF8_CTSUFFIX.replace(" ", "").toLowerCase(), status.getEntity().getContentType().getValue().replace(" ", "").replace("UTF", "utf"));
|
||||
assertThat(responseContent, not(containsString("<Bundle")));
|
||||
assertThat(responseContent, (containsString("<Patien")));
|
||||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.TRUE, ourLastSummary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryCount() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true&_summary=" + SummaryEnum.COUNT.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, not(containsString("entry")));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.COUNT, ourLastSummary);
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_pretty=true&_summary=" + SummaryEnum.COUNT.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, not(containsString("entry")));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.COUNT, ourLastSummary);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryCountAndData() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true&_summary=" + SummaryEnum.COUNT.getCode() + "," + SummaryEnum.DATA.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_pretty=true&_summary=" + SummaryEnum.COUNT.getCode() + "," + SummaryEnum.DATA.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryData() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.DATA.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.DATA.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertEquals(SummaryEnum.DATA, ourLastSummary);
|
||||
}
|
||||
);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertEquals(SummaryEnum.DATA, ourLastSummary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryFalse() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=false");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, containsString("THE DIV"));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertEquals(SummaryEnum.FALSE, ourLastSummary);
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_summary=false";
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, containsString("THE DIV"));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertEquals(SummaryEnum.FALSE, ourLastSummary);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryText() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.TEXT.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.TEXT, ourLastSummary);
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.TEXT.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.TEXT, ourLastSummary);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryTextWithMandatory() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/MedicationRequest?_summary=" + SummaryEnum.TEXT.getCode() + "&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
String url = "http://localhost:" + ourPort + "/MedicationRequest?_summary=" + SummaryEnum.TEXT.getCode() + "&_pretty=true";
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
assertEquals(0, bundle.getMeta().getTag().size());
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString(">TEXT<")));
|
||||
assertThat(responseContent, (containsString("Medication/123")));
|
||||
assertThat(responseContent, not(containsStringIgnoringCase("note")));
|
||||
}
|
||||
);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString(">TEXT<")));
|
||||
assertThat(responseContent, (containsString("Medication/123")));
|
||||
assertThat(responseContent, not(containsStringIgnoringCase("note")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryTextMulti() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=multi&_summary=" + SummaryEnum.TEXT.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastSummaryList, contains(SummaryEnum.TEXT));
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_query=multi&_summary=" + SummaryEnum.TEXT.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, (containsString("<total value=\"1\"/>")));
|
||||
assertThat(responseContent, (containsString("entry")));
|
||||
assertThat(responseContent, (containsString("THE DIV")));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastSummaryList, contains(SummaryEnum.TEXT));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryTrue() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.TRUE.getCode());
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_summary=" + SummaryEnum.TRUE.getCode();
|
||||
verifyXmlAndJson(
|
||||
url,
|
||||
bundle -> {
|
||||
String responseContent = ourCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.TRUE, ourLastSummary);
|
||||
}
|
||||
);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("<Patient"));
|
||||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertEquals(SummaryEnum.TRUE, ourLastSummary);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchSummaryWithTextAndOthers() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_summary=text&_summary=data");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
String url = "http://localhost:" + ourPort + "/Patient?_summary=text&_summary=data";
|
||||
try (CloseableHttpResponse status = ourClient.execute(new HttpGet(url))) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("Can not combine _summary=text with other values for _summary"));
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyXmlAndJson(String theUri, Consumer<Bundle> theVerifier) throws IOException {
|
||||
verifyXmlAndJson(theUri, Bundle.class, theVerifier);
|
||||
}
|
||||
|
||||
private <T extends IBaseResource> void verifyXmlAndJson(String theUri, Class<T> theType, Consumer<T> theVerifier) throws IOException {
|
||||
EncodingEnum encodingEnum;
|
||||
HttpGet httpGet;
|
||||
|
||||
encodingEnum = EncodingEnum.JSON;
|
||||
httpGet = new HttpGet(theUri + "&_pretty=true&_format=" + encodingEnum.getFormatContentType());
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
T response = encodingEnum.newParser(ourCtx).parseResource(theType, responseContent);
|
||||
theVerifier.accept(response);
|
||||
}
|
||||
|
||||
encodingEnum = EncodingEnum.XML;
|
||||
httpGet = new HttpGet(theUri + "&_pretty=true&_format=" + encodingEnum.getFormatContentType());
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), Charsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
T response = encodingEnum.newParser(ourCtx).parseResource(theType, responseContent);
|
||||
theVerifier.accept(response);
|
||||
}
|
||||
}
|
||||
|
||||
public static class DummyMedicationRequestProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return MedicationRequest.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public MedicationRequest read(@IdParam IdType theId) {
|
||||
MedicationRequest retVal = new MedicationRequest();
|
||||
retVal.getText().setDivAsString("<div>TEXT</div>");
|
||||
retVal.addNote().setText("NOTE");
|
||||
retVal.setMedication(new Reference("Medication/123"));
|
||||
retVal.setId(theId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<MedicationRequest> read() {
|
||||
return Collections.singletonList(read(new IdType("999")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public Patient read(@IdParam IdType theId, SummaryEnum theSummary) {
|
||||
ourLastSummary = theSummary;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Search(queryName = "multi")
|
||||
public Patient search(List<SummaryEnum> theSummary) {
|
||||
ourLastSummaryList = theSummary;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient search(SummaryEnum theSummary) {
|
||||
ourLastSummary = theSummary;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, containsString("Can not combine _summary=text with other values for _summary"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
@ -293,70 +391,4 @@ public class SummaryParamR4Test {
|
|||
|
||||
}
|
||||
|
||||
public static class DummyMedicationRequestProvider implements IResourceProvider{
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return MedicationRequest.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public MedicationRequest read(@IdParam IdType theId) {
|
||||
MedicationRequest retVal = new MedicationRequest();
|
||||
retVal.getText().setDivAsString("<div>TEXT</div>");
|
||||
retVal.addNote().setText("NOTE");
|
||||
retVal.setMedication(new Reference("Medication/123"));
|
||||
retVal.setId(theId);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<MedicationRequest> read() {
|
||||
return Arrays.asList(read(new IdType("999")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Read
|
||||
public Patient read(@IdParam IdType theId, SummaryEnum theSummary) {
|
||||
ourLastSummary = theSummary;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Search(queryName = "multi")
|
||||
public Patient search(List<SummaryEnum> theSummary) {
|
||||
ourLastSummaryList = theSummary;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public Patient search(SummaryEnum theSummary) {
|
||||
ourLastSummary = theSummary;
|
||||
Patient patient = new Patient();
|
||||
patient.setId("Patient/1/_history/1");
|
||||
patient.getText().setDivAsString("<div>THE DIV</div>");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.getMaritalStatus().addCoding().setCode("D");
|
||||
return patient;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -940,7 +940,6 @@ public class JsonParserDstu2_1Test {
|
|||
assertThat(out, containsString("name"));
|
||||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1568,7 +1568,6 @@ public class XmlParserDstu2_1Test {
|
|||
assertThat(out, containsString("name"));
|
||||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1597,7 +1596,6 @@ public class XmlParserDstu2_1Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1609,7 +1607,6 @@ public class XmlParserDstu2_1Test {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
|
|
@ -1143,7 +1143,6 @@ public class Dstu3JsonParserTest {
|
|||
assertThat(out, containsString("name"));
|
||||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1938,7 +1938,6 @@ public class Dstu3XmlParserTest {
|
|||
assertThat(out, containsString("name"));
|
||||
assertThat(out, containsString("id"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
assertThat(out, not(containsString("meta")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1967,7 +1966,6 @@ public class Dstu3XmlParserTest {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1979,7 +1977,6 @@ public class Dstu3XmlParserTest {
|
|||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
|
|
@ -151,57 +151,6 @@ public class R4JsonParserTest {
|
|||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExcludeRootStuff() {
|
||||
IParser parser = ourCtx.newJsonParser().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", ((Patient) b.getEntry().get(0).getResource()).getId());
|
||||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExcludeStarDotStuff() {
|
||||
IParser parser = ourCtx.newJsonParser().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", ((Patient) 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
|
||||
|
|
|
@ -106,32 +106,6 @@ public class R4XmlParserTest {
|
|||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExcludeRootStuff() {
|
||||
IParser parser = ourCtx.newXmlParser().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, IsNot.not(containsString("BUNDLEID")));
|
||||
assertThat(encoded, IsNot.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", ((Patient) b.getEntry().get(0).getResource()).getId());
|
||||
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExcludeStarDotStuff() {
|
||||
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||
|
|
|
@ -688,6 +688,55 @@
|
|||
</subsection>
|
||||
|
||||
</section>
|
||||
|
||||
<section name="Extended Elements Support" id="extended_elements_support">
|
||||
|
||||
<p>
|
||||
The HAPI FHIR server may be configured using the
|
||||
<code>RestfulServer#setElementsSupport</code> to enable extended
|
||||
support for the <code>_elements</code> filter.
|
||||
</p>
|
||||
<p>
|
||||
In standard mode, elements are supported exactly as described in the
|
||||
<a href="http://hl7.org/fhir/search.html#elements">Elements Documentation</a>
|
||||
in the FHIR specification.
|
||||
</p>
|
||||
<p>
|
||||
In extended mode, HAPI FHIR provides the same behaviour as described in the
|
||||
FHIR specification, but also enabled the following additional options:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Values may be prepended using Resource names in order to apply the
|
||||
elements filter to multiple resources. For example, the following
|
||||
parameter could be used to apply elements filtering to both the
|
||||
DiagnosticReport and Observation resource in a search result:<br/>
|
||||
<code>_elements=DiagnosticReport.subject,DiagnosticReport.result,Observation.value</code>
|
||||
</li>
|
||||
<li>
|
||||
Values may be prepended with a wildcard star in order to apply them
|
||||
to all resource types. For example, the following parameter could
|
||||
be used to include the <code>subject</code> field in all resource
|
||||
types:<br/>
|
||||
<code>_elements=*.subject</code>
|
||||
</li>
|
||||
<li>
|
||||
Values may include complex paths. For example, the following parameter could
|
||||
be used to include only the code on a coded element:<br/>
|
||||
<code>_elements=Procedure.reasonCode.coding.code</code>
|
||||
</li>
|
||||
<li>
|
||||
Elements may be excluded using the <code>:exclude</code> modifier
|
||||
on the elements parameter. For example, the following parameter
|
||||
could be used to remove the resource metadata (meta) element from
|
||||
all resources in the response:<br/>
|
||||
<code>_elements:exclude=*.meta</code><br/>
|
||||
Note that this can be used to suppress the <code>SUBSETTED</code> tag
|
||||
which is automatically added to resources when an <code>_elements</code>
|
||||
parameter is applied.
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
|
||||
|
|
Loading…
Reference in New Issue