A few cleanups to allow example resources to commit cleanly

This commit is contained in:
James Agnew 2015-07-07 17:27:10 -04:00
parent 70a26c6d2d
commit d20b7e2c94
15 changed files with 529 additions and 96 deletions

View File

@ -87,7 +87,6 @@ public abstract class BaseParser implements IParser {
}
private void containResourcesForEncoding(ContainedResources theContained, IBaseResource theResource, IBaseResource theTarget) {
Set<String> allIds = new HashSet<String>();
Map<String, IBaseResource> existingIdToContainedResource = null;
@ -131,6 +130,10 @@ public abstract class BaseParser implements IParser {
IBaseResource resource = next.getResource();
if (resource != null) {
if (resource.getIdElement().isEmpty() || resource.getIdElement().isLocal()) {
if (theContained.getResourceId(resource) != null) {
// Prevent infinite recursion if there are circular loops in the contained resources
continue;
}
theContained.addContained(resource);
} else {
continue;

View File

@ -1684,7 +1684,7 @@ class ParserState<T> {
@Override
public void endingElement() throws DataFormatException {
if (myExtension.getValue() != null && myExtension.getExtension().size() > 0) {
throw new DataFormatException("Extension must not have both a value and other contained extensions");
throw new DataFormatException("Extension (URL='" + myExtension.getUrl() + "') must not have both a value and other contained extensions");
}
pop();
}

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
@ -68,29 +69,26 @@ public class FhirTerser {
}
/**
* Returns a list containing all child elements (including the resource itself) which are <b>non-empty</b> and are
* either of the exact type specified, or are a subclass of that type.
* Returns a list containing all child elements (including the resource itself) which are <b>non-empty</b> and are either of the exact type specified, or are a subclass of that type.
* <p>
* For example, specifying a type of {@link StringDt} would return all non-empty string instances within the
* message. Specifying a type of {@link IResource} would return the resource itself, as well as any contained
* resources.
* For example, specifying a type of {@link StringDt} would return all non-empty string instances within the message. Specifying a type of {@link IResource} would return the resource itself, as
* well as any contained resources.
* </p>
* <p>
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well,
* but will not descend into linked resources (e.g. {@link BaseResourceReferenceDt#getResource()}) or embedded
* resources (e.g. Bundle.entry.resource)
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not descend into linked resources (e.g.
* {@link BaseResourceReferenceDt#getResource()}) or embedded resources (e.g. Bundle.entry.resource)
* </p>
*
* @param theResource
* The resource instance to search. Must not be null.
* The resource instance to search. Must not be null.
* @param theType
* The type to search for. Must not be null.
* The type to search for. Must not be null.
* @return Returns a list of all matching elements
*/
public <T extends IBase> List<T> getAllPopulatedChildElementsOfType(IBaseResource theResource, final Class<T> theType) {
final ArrayList<T> retVal = new ArrayList<T>();
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, null, def, new IModelVisitor() {
visit(new IdentityHashMap<Object, Object>(), theResource, null, null, def, new IModelVisitor() {
@SuppressWarnings("unchecked")
@Override
public void acceptElement(IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition) {
@ -105,8 +103,8 @@ public class FhirTerser {
@SuppressWarnings("unchecked")
@Override
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition,
ExtensionDt theNextExt) {
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
if (theType.isAssignableFrom(theNextExt.getClass())) {
retVal.add((T) theNextExt);
}
@ -118,32 +116,32 @@ public class FhirTerser {
return retVal;
}
public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) {
final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<ResourceReferenceInfo>();
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, null, def, new IModelVisitor() {
@Override
public void acceptElement(IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition) {
if (theElement == null || theElement.isEmpty()) {
return;
}
if (IBaseReference.class.isAssignableFrom(theElement.getClass())) {
retVal.add(new ResourceReferenceInfo(myContext, theResource, thePathToElement, (IBaseReference)theElement));
}
}
public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) {
final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<ResourceReferenceInfo>();
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(new IdentityHashMap<Object, Object>(),theResource, null, null, def, new IModelVisitor() {
@Override
public void acceptElement(IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition) {
if (theElement == null || theElement.isEmpty()) {
return;
}
if (IBaseReference.class.isAssignableFrom(theElement.getClass())) {
retVal.add(new ResourceReferenceInfo(myContext, theResource, thePathToElement, (IBaseReference) theElement));
}
}
@Override
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition,
ExtensionDt theNextExt) {
if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) {
retVal.add(new ResourceReferenceInfo(myContext, theResource, thePathToElement, (BaseResourceReferenceDt)theNextExt.getValue()));
}
}
});
return retVal;
}
@Override
public void acceptUndeclaredExtension(ISupportsUndeclaredExtensions theContainingElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
BaseRuntimeElementDefinition<?> theDefinition, ExtensionDt theNextExt) {
if (theNextExt.getValue() != null && BaseResourceReferenceDt.class.isAssignableFrom(theNextExt.getValue().getClass())) {
retVal.add(new ResourceReferenceInfo(myContext, theResource, thePathToElement, (BaseResourceReferenceDt) theNextExt.getValue()));
}
}
});
return retVal;
}
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
private BaseRuntimeChildDefinition getDefinition(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));
if (theSubList.size() == 1) {
@ -214,7 +212,7 @@ public class FhirTerser {
public List<Object> getValues(IBaseResource theResource, String thePath) {
Class<Object> wantedClass = Object.class;
return getValues(theResource, thePath, wantedClass);
}
@ -233,24 +231,30 @@ public class FhirTerser {
return getValues(currentDef, currentObj, subList, theWantedClass);
}
private List<String> addNameToList(List<String> theCurrentList, BaseRuntimeChildDefinition theChildDefinition) {
if (theChildDefinition == null)
return null;
if (theCurrentList== null || theCurrentList.isEmpty())
return new ArrayList<String>(Arrays.asList(theChildDefinition.getElementName()));
List<String> newList = new ArrayList<String>(theCurrentList);
newList.add(theChildDefinition.getElementName());
return newList;
}
private List<String> addNameToList(List<String> theCurrentList, BaseRuntimeChildDefinition theChildDefinition) {
if (theChildDefinition == null)
return null;
if (theCurrentList == null || theCurrentList.isEmpty())
return new ArrayList<String>(Arrays.asList(theChildDefinition.getElementName()));
List<String> newList = new ArrayList<String>(theCurrentList);
newList.add(theChildDefinition.getElementName());
return newList;
}
private void visit(IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
List<String> pathToElement = addNameToList(thePathToElement, theChildDefinition);
private void visit(IdentityHashMap<Object, Object> theStack, IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor theCallback) {
List<String> pathToElement = addNameToList(thePathToElement, theChildDefinition);
if (theStack.put(theElement, theElement) != null) {
return;
}
theCallback.acceptElement(theElement, pathToElement, theChildDefinition, theDefinition);
addUndeclaredExtensions(theElement, theDefinition, theChildDefinition, theCallback);
// if (theElement.isEmpty()) {
// return;
// }
if (theElement.isEmpty()) {
return;
}
switch (theDefinition.getChildType()) {
case ID_DATATYPE:
@ -265,7 +269,7 @@ public class FhirTerser {
IBaseResource theResource = resRefDt.getResource();
if (theResource.getIdElement() == null || theResource.getIdElement().isEmpty() || theResource.getIdElement().isLocal()) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, pathToElement, null, def, theCallback);
visit(theStack, theResource, pathToElement, null, def, theCallback);
}
}
break;
@ -287,14 +291,14 @@ public class FhirTerser {
childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
if (childElementDef == null) {
childElementDef = myContext.getElementDefinition(nextValue.getClass());
childElementDef = myContext.getElementDefinition(nextValue.getClass());
}
if (nextChild instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
theCallback.acceptElement(nextValue, null, nextChild, childElementDef);
} else {
visit(nextValue, pathToElement, nextChild, childElementDef, theCallback);
visit(theStack, nextValue, pathToElement, nextChild, childElementDef, theCallback);
}
}
}
@ -305,7 +309,7 @@ public class FhirTerser {
BaseContainedDt value = (BaseContainedDt) theElement;
for (IResource next : value.getContainedResources()) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(next);
visit(next, pathToElement, null, def, theCallback);
visit(theStack, next, pathToElement, null, def, theCallback);
}
break;
}
@ -316,21 +320,25 @@ public class FhirTerser {
case CONTAINED_RESOURCE_LIST:
if (theElement != null) {
BaseRuntimeElementDefinition<?> def = myContext.getElementDefinition(theElement.getClass());
visit(theElement, pathToElement, null, def, theCallback);
visit(theStack, theElement, pathToElement, null, def, theCallback);
}
break;
}
theStack.remove(theElement);
}
private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor2 theCallback, List<IBase> theContainingElementPath, List<BaseRuntimeChildDefinition> theChildDefinitionPath,
List<BaseRuntimeElementDefinition<?>> theElementDefinitionPath) {
private void visit(IBase theElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition<?> theDefinition, IModelVisitor2 theCallback, List<IBase> theContainingElementPath,
List<BaseRuntimeChildDefinition> theChildDefinitionPath, List<BaseRuntimeElementDefinition<?>> theElementDefinitionPath) {
if (theChildDefinition != null) {
theChildDefinitionPath.add(theChildDefinition);
}
theContainingElementPath.add(theElement);
theElementDefinitionPath.add(theDefinition);
theCallback.acceptElement(theElement, Collections.unmodifiableList(theContainingElementPath), Collections.unmodifiableList(theChildDefinitionPath), Collections.unmodifiableList(theElementDefinitionPath));
theCallback.acceptElement(theElement, Collections.unmodifiableList(theContainingElementPath), Collections.unmodifiableList(theChildDefinitionPath),
Collections.unmodifiableList(theElementDefinitionPath));
/*
* Visit undeclared extensions
@ -405,7 +413,8 @@ public class FhirTerser {
theContainingElementPath.add(nextValue);
theChildDefinitionPath.add(nextChild);
theElementDefinitionPath.add(myContext.getElementDefinition(nextValue.getClass()));
theCallback.acceptElement(nextValue, Collections.unmodifiableList(theContainingElementPath), Collections.unmodifiableList(theChildDefinitionPath), Collections.unmodifiableList(theElementDefinitionPath));
theCallback.acceptElement(nextValue, Collections.unmodifiableList(theContainingElementPath), Collections.unmodifiableList(theChildDefinitionPath),
Collections.unmodifiableList(theElementDefinitionPath));
theChildDefinitionPath.remove(theChildDefinitionPath.size() - 1);
theContainingElementPath.remove(theContainingElementPath.size() - 1);
theElementDefinitionPath.remove(theElementDefinitionPath.size() - 1);
@ -449,19 +458,18 @@ public class FhirTerser {
* Visit all elements in a given resource
*
* <p>
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well,
* but will not descend into linked resources (e.g. {@link BaseResourceReferenceDt#getResource()}) or embedded
* resources (e.g. Bundle.entry.resource)
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not descend into linked resources (e.g.
* {@link BaseResourceReferenceDt#getResource()}) or embedded resources (e.g. Bundle.entry.resource)
* </p>
*
* @param theResource
* The resource to visit
* The resource to visit
* @param theVisitor
* The visitor
* The visitor
*/
public void visit(IBaseResource theResource, IModelVisitor theVisitor) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
visit(theResource, null, null, def, theVisitor);
visit(new IdentityHashMap<Object, Object>(), theResource, null, null, def, theVisitor);
}
/**
@ -470,15 +478,14 @@ public class FhirTerser {
* THIS ALTERNATE METHOD IS STILL EXPERIMENTAL
*
* <p>
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well,
* but will not descend into linked resources (e.g. {@link BaseResourceReferenceDt#getResource()}) or embedded
* resources (e.g. Bundle.entry.resource)
* Note on scope: This method will descend into any contained resources ({@link IResource#getContained()}) as well, but will not descend into linked resources (e.g.
* {@link BaseResourceReferenceDt#getResource()}) or embedded resources (e.g. Bundle.entry.resource)
* </p>
*
* @param theResource
* The resource to visit
* The resource to visit
* @param theVisitor
* The visitor
* The visitor
*/
void visit(IBaseResource theResource, IModelVisitor2 theVisitor) {
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
@ -487,7 +494,7 @@ public class FhirTerser {
public Object getSingleValueOrNull(IBase theTarget, String thePath) {
Class<Object> wantedType = Object.class;
return getSingleValueOrNull(theTarget, thePath, wantedType);
}
@ -512,5 +519,4 @@ public class FhirTerser {
}
}
}

View File

@ -87,6 +87,9 @@ public interface IIdType {
IIdType withServerBase(String theServerBase, String theResourceName);
/**
* Returns <code>true</code> if this ID contains an absolute URL (in other words, a URL starting with "http://" or "https://"
*/
boolean isAbsolute();
boolean isIdPartValidLong();

View File

@ -0,0 +1 @@
/build/

View File

@ -0,0 +1,128 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--
Note: HAPI projects use the "hapi-fhir" POM as their base to provide
easy management.
You do not need to use this in your own projects, so the
"parent" tag and it's contents below may be removed if you
are using this file as a basis for your own project.
-->
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>ca.uhn.hapi.example</groupId>
<artifactId>hapi-fhir-examples-uploader</artifactId>
<version>1.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>HAPI FHIR - Examples Uploader</name>
<dependencies>
<!-- This dependency includes the core HAPI-FHIR classes -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!--
Tells Maven to name the generated WAR file as
hapi-fhir-jpaserver-example.war
-->
<finalName>hapi-fhir-jpaserver-example</finalName>
<!--
The following is not required for the application to build, but
allows you to test it by issuing "mvn jetty:run" from the command
line.
-->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.1.v20140108</version>
<configuration>
<webApp>
<contextPath>/hapi-fhir-jpaserver-example</contextPath>
</webApp>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!--
Tell Maven which Java source version you want to use
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<!--
The configuration here tells the WAR plugin to include the FHIR Tester
overlay. You can omit it if you are not using that feature.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<overlays>
<overlay>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
<!--
This plugin is just a part of the HAPI internal build process, you do not
need to incude it in your own projects
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,149 @@
package ca.uhn.fhir.exampleuploader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.ClientProtocolException;
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.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryTransaction;
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.util.ResourceReferenceInfo;
public class Uploader {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Uploader.class);
public static void main(String[] args) throws Exception {
ourLog.info("Starting...");
FhirContext ctx = FhirContext.forDstu2();
HttpGet get = new HttpGet("http://hl7.org/fhir/2015May/examples-json.zip");
CloseableHttpClient client = HttpClientBuilder.create().build();
CloseableHttpResponse result = client.execute(get);
byte[] bytes = IOUtils.toByteArray(result.getEntity().getContent());
IOUtils.closeQuietly(result.getEntity().getContent());
ourLog.info("Loaded examples ({} bytes)", bytes.length);
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));
byte[] buffer = new byte[2048];
Bundle bundle = new Bundle();
while (true) {
ZipEntry nextEntry = zis.getNextEntry();
if (nextEntry == null) {
break;
}
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = zis.read(buffer)) > 0) {
bos.write(buffer, 0, len);
}
byte[] exampleBytes = bos.toByteArray();
String exampleString = new String(exampleBytes, "UTF-8");
IBaseResource parsed;
try {
parsed = ctx.newJsonParser().parseResource(exampleString);
} catch (DataFormatException e) {
ourLog.info("FAILED to parse example {}", nextEntry.getName(), e);
continue;
}
ourLog.info("Found example {} - {} - {} chars", nextEntry.getName(), parsed.getClass().getSimpleName(), exampleString.length());
if (parsed instanceof Bundle) {
Bundle b = (Bundle) parsed;
for (Entry nextEntry1 : b.getEntry()) {
if (nextEntry1.getResource() == null) {
continue;
}
if (nextEntry1.getResource() instanceof Bundle) {
continue;
}
if (nextEntry1.getResource() instanceof SearchParameter) {
continue;
}
bundle.addEntry().setTransaction(new EntryTransaction().setMethod(HTTPVerbEnum.POST)).setResource(nextEntry1.getResource());
}
} else {
if (parsed instanceof SearchParameter) {
continue;
}
bundle.addEntry().setTransaction(new EntryTransaction().setMethod(HTTPVerbEnum.POST)).setResource((IResource) parsed);
}
}
Set<String> ids = new HashSet<String>();
for (int i = 0; i < bundle.getEntry().size(); i++) {
Entry next = bundle.getEntry().get(i);
if (next.getResource().getId().getIdPart() != null) {
String nextId = next.getResource().getResourceName() + '/' + next.getResource().getId().getIdPart();
if (!ids.add(nextId)) {
ourLog.info("Discarding duplicate resource with ID: " + nextId);
bundle.getEntry().remove(i);
i--;
}
}
}
int goodRefs = 0;
for (Entry next : bundle.getEntry()) {
List<ResourceReferenceInfo> refs = ctx.newTerser().getAllResourceReferences(next.getResource());
for (ResourceReferenceInfo nextRef : refs) {
// if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) {
// ourLog.info("Discarding absolute reference: {}", nextRef.getResourceReference().getReferenceElement().getValue());
// nextRef.getResourceReference().getReferenceElement().setValue(null);
// }
nextRef.getResourceReference().getReferenceElement().setValue(nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue());
String value = nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue();
if (!ids.contains(value) && !nextRef.getResourceReference().getReferenceElement().isLocal()) {
ourLog.info("Discarding unknown reference: {}", value);
nextRef.getResourceReference().getReferenceElement().setValue(null);
} else {
goodRefs++;
}
}
}
// for (Entry next : bundle.getEntry()) {
// if (next.getResource().getId().hasIdPart() && Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) {
// next.getTransaction().setUrl(next.getResource().getResourceName() + '/' + next.getResource().getId().getIdPart());
// next.getTransaction().setMethod(HTTPVerbEnum.PUT);
// }
// }
ourLog.info("{} good references", goodRefs);
String encoded = ctx.newJsonParser().encodeResourceToString(bundle);
ourLog.info("Final bundle: {} entries", bundle.getEntry().size());
ourLog.info("Final bundle: {} chars", encoded.length());
IGenericClient fhirClient = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
fhirClient.transaction().withBundle(bundle).execute();
}
}

View File

@ -0,0 +1,30 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.eclipse" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.apache" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.thymeleaf" additivity="false" level="warn">
<appender-ref ref="STDOUT" />
</logger>
<!--
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="trace">
<appender-ref ref="STDOUT" />
</logger>
-->
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -50,6 +50,7 @@ import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.composite.BaseHumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.AddressDt;
import ca.uhn.fhir.model.dstu2.composite.BoundCodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.ContactPointDt;
@ -58,9 +59,11 @@ import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestSecurity;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Patient.Communication;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.valueset.RestfulSecurityServiceEnum;
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
@ -469,28 +472,21 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea
} else if (nextObject instanceof CodeableConceptDt) {
CodeableConceptDt nextCC = (CodeableConceptDt) nextObject;
if (!nextCC.getTextElement().isEmpty()) {
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), BaseFhirDao.normalizeString(nextCC.getTextElement().getValue()), nextCC.getTextElement().getValue());
String value = nextCC.getTextElement().getValue();
if (value.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
value = value.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
}
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), BaseFhirDao.normalizeString(value), value);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
for (CodingDt nextCoding : nextCC.getCoding()) {
if (nextCoding.isEmpty()) {
continue;
}
String nextSystem = nextCoding.getSystemElement().getValueAsString();
String nextCode = nextCoding.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
systems.add(nextSystem);
codes.add(nextCode);
}
if (!nextCoding.getDisplayElement().isEmpty()) {
systems.add(null);
codes.add(nextCoding.getDisplayElement().getValue());
}
extractTokensFromCodeableConcept(systems, codes, nextCC);
} else if (nextObject instanceof RestSecurity) {
// Conformance.security search param points to something kind of useless right now - This should probably be fixed.
RestSecurity sec = (RestSecurity)nextObject;
for (BoundCodeableConceptDt<RestfulSecurityServiceEnum> nextCC : sec.getService()) {
extractTokensFromCodeableConcept(systems, codes, nextCC);
}
} else {
if (!multiType) {
@ -538,4 +534,25 @@ class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implements ISea
return retVal;
}
private void extractTokensFromCodeableConcept(List<String> systems, List<String> codes, CodeableConceptDt nextCC) {
for (CodingDt nextCoding : nextCC.getCoding()) {
if (nextCoding.isEmpty()) {
continue;
}
String nextSystem = nextCoding.getSystemElement().getValueAsString();
String nextCode = nextCoding.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
systems.add(nextSystem);
codes.add(nextCode);
}
if (!nextCoding.getDisplayElement().isEmpty()) {
systems.add(null);
codes.add(nextCoding.getDisplayElement().getValue());
}
}
}
}

View File

@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -37,6 +38,8 @@ import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jmx.access.InvalidInvocationException;
import com.ctc.wstx.util.StringUtil;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
@ -1715,6 +1718,37 @@ public class FhirResourceDaoDstu2Test extends BaseJpaTest {
}
@Test
public void testSearchStringParamReallyLong() {
String methodName = "testSearchStringParamReallyLong";
String value = StringUtils.rightPad(methodName, 200, 'a');
IIdType longId;
IIdType shortId;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily(value);
longId = (IdDt) ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
shortId = (IdDt) ourPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
Map<String, IQueryParameterType> params = new HashMap<String, IQueryParameterType>();
String substring = value.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
params.put(Patient.SP_FAMILY, new StringParam(substring));
IBundleProvider found = ourPatientDao.search(params);
assertEquals(1, toList(found).size());
assertThat(toUnqualifiedVersionlessIds(found), contains(longId));
assertThat(toUnqualifiedVersionlessIds(found), not(contains(shortId)));
}
@Test
public void testSearchStringParamWithNonNormalized() {
{

View File

@ -25,11 +25,12 @@ public class UhnFhirTestApp {
int myPort = 8888;
String base = "http://localhost:" + myPort + "/base";
// new File("target/testdb").mkdirs();
System.setProperty("fhir.db.location", "./target/testdb");
System.setProperty("fhir.db.location.dstu2", "./target/testdb_dstu2");
System.setProperty("fhir.baseurl", base);
System.setProperty("fhir.baseurl.dstu1", base + "Dstu1");
System.setProperty("fhir.baseurl.dstu2", base + "Dstu1");
Server server = new Server(myPort);

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.context;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.DiagnosticReport;
public class Perf {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Perf.class);
public static void main(String[] args) throws Exception {
FhirContext ctx = FhirContext.forDstu1();
String str = IOUtils.toString(Perf.class.getResourceAsStream("/contained-diagnosticreport-singlecontainedelement.xml"));
DiagnosticReport rept = ctx.newXmlParser().parseResource(DiagnosticReport.class, str);
long start = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
if (i % 10 == 0) {
ourLog.info("Rep: " + i);
}
ctx.newTerser().getAllPopulatedChildElementsOfType(rept, BaseResourceReferenceDt.class);
}
long delay = System.currentTimeMillis() - start;
ourLog.info("Took: {} ms", delay);
}
}

View File

@ -23,6 +23,7 @@ public class IdDtTest {
id = new IdDt("#123");
assertEquals("#123", id.getValue());
assertEquals("#123", id.toUnqualifiedVersionless().getValue());
assertTrue(id.isLocal());
id = new IdDt("#Medication/499059CE-CDD4-48BC-9014-528A35D15CED/_history/1");

View File

@ -500,6 +500,28 @@ public class XmlParserTest {
}
@Test
public void testEncodeContainedWithSelfReference() {
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
// Create an organization, note that the organization does not have an ID
Organization org = new Organization();
org.getName().setValue("Contained Test Organization");
org.setPartOf(new ResourceReferenceDt(org));
// Create a patient
Patient patient = new Patient();
patient.getManagingOrganization().setResource(org);
String encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
assertThat(encoded, containsString("<contained>"));
assertThat(encoded, containsString("<reference value=\"#1\"/>"));
}
@Test
public void testEncodeContained() {
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);

View File

@ -146,6 +146,10 @@
e.g. "Location.partof.partof.organization". Thanks to Ismael Sarmento Jr for
reporting!
</action>
<action type="fix">
Prevent crash when encoding resources with contained resources
if the contained resources contained a circular reference to each other
</action>
</release>
<release version="1.0" date="2015-May-8">
<action type="add">