This commit is contained in:
b.debeaubien 2015-02-26 08:42:07 -05:00
commit e190659fcf
287 changed files with 10998 additions and 6622 deletions

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@ -36,6 +37,9 @@ public class PlainProvider {
//START SNIPPET: plainProviderServer
public class ExampleServlet extends RestfulServer {
/**
* Constructor
*/
public ExampleServlet() {
/*
* Plain providers are passed to the server in the same way
@ -54,5 +58,25 @@ public class ExampleServlet extends RestfulServer {
}
//END SNIPPET: plainProviderServer
//START SNIPPET: addressStrategy
public class MyServlet extends RestfulServer {
/**
* Constructor
*/
public MyServlet() {
String serverBaseUrl = "http://foo.com/fhir";
setServerAddressStrategy(new HardcodedServerAddressStrategy(serverBaseUrl));
// ...add some resource providers, etc...
List<IResourceProvider> resourceProviders = new ArrayList<IResourceProvider>();
setResourceProviders(resourceProviders);
}
}
//END SNIPPET: addressStrategy
}

View File

@ -10,6 +10,7 @@ import ca.uhn.fhir.model.base.resource.BaseConformance;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
@ -68,6 +69,30 @@ public class GenericClientExample {
System.out.println("Got ID: " + id.getValue());
// END SNIPPET: create
}
{
Patient patient = new Patient();
// START SNIPPET: createConditional
// One form
MethodOutcome outcome = client.create()
.resource(patient)
.conditionalByUrl("Patient?identifier=system%7C00001")
.execute();
// Another form
MethodOutcome outcome2 = client.create()
.resource(patient)
.conditional()
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
.execute();
// This will return true if the server responded with an HTTP 201 created,
// otherwise it will return null.
Boolean created = outcome.getCreated();
// The ID of the created, or the pre-existing resource
IdDt id = outcome.getId();
// END SNIPPET: createConditional
}
{
// START SNIPPET: update
Patient patient = new Patient();
@ -95,6 +120,21 @@ public class GenericClientExample {
System.out.println("Got ID: " + id.getValue());
// END SNIPPET: update
}
{
Patient patient = new Patient();
// START SNIPPET: updateConditional
client.update()
.resource(patient)
.conditionalByUrl("Patient?identifier=system%7C00001")
.execute();
client.update()
.resource(patient)
.conditional()
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
.execute();
// END SNIPPET: updateConditional
}
{
// START SNIPPET: etagupdate
// First, let's retrive the latest version of a resource
@ -132,16 +172,27 @@ public class GenericClientExample {
}
{
// START SNIPPET: delete
// Retrieve the server's conformance statement and print its
// description
BaseOperationOutcome outcome = client.delete().resourceById(new IdDt("Patient", "1234")).execute();
BaseOperationOutcome resp = client.delete().resourceById(new IdDt("Patient", "1234")).execute();
// outcome may be null if the server didn't return one
if (outcome != null) {
if (resp != null) {
OperationOutcome outcome = (OperationOutcome) resp;
System.out.println(outcome.getIssueFirstRep().getDetailsElement().getValue());
}
// END SNIPPET: delete
}
{
// START SNIPPET: deleteConditional
client.delete()
.resourceConditionalByUrl("Patient?identifier=system%7C00001")
.execute();
client.delete()
.resourceConditionalByType("Patient")
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
.execute();
// END SNIPPET: deleteConditional
}
{
// START SNIPPET: search
Bundle response = client.search()

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
@SuppressWarnings("null")
//START SNIPPET: provider
public class PagingPatientProvider implements IResourceProvider {
@ -21,8 +22,19 @@ public class PagingPatientProvider implements IResourceProvider {
@Search
public IBundleProvider search(@RequiredParam(name = Patient.SP_FAMILY) StringParam theFamily) {
final InstantDt searchTime = InstantDt.withCurrentTime();
final List<String> matchingResourceIds = findIdsByFamily(theFamily);
/*
* First, we'll search the database for a set of database row IDs that
* match the given search criteria. That way we can keep just the
* row IDs around, and load the actual resources on demand later
* as the client pages through them.
*/
final List<Long> matchingResourceIds = null; // <-- implement this
/*
* Return a bundle provider which can page through the IDs and
* return the resources that go with them.
*/
return new IBundleProvider() {
@Override
@ -33,7 +45,7 @@ public class PagingPatientProvider implements IResourceProvider {
@Override
public List<IResource> getResources(int theFromIndex, int theToIndex) {
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
List<String> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
return loadResourcesByIds(idsToReturn);
}
@ -44,18 +56,10 @@ public class PagingPatientProvider implements IResourceProvider {
};
}
/**
* Get a list of resource IDs which match a given family name
*/
private List<String> findIdsByFamily(StringParam theFamily) {
// .. implement this search against the database ..
return null;
}
/**
* Load a list of patient resources given their IDs
*/
private List<IResource> loadResourcesByIds(List<String> theFamily) {
private List<IResource> loadResourcesByIds(List<Long> theIdsToReturn) {
// .. implement this search against the database ..
return null;
}

View File

@ -34,6 +34,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.AddTags;
import ca.uhn.fhir.rest.annotation.ConditionalOperationParam;
import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.DeleteTags;
@ -324,6 +325,23 @@ public void deletePatient(@IdParam IdDt theId) {
//END SNIPPET: delete
//START SNIPPET: deleteConditional
@Read()
public void deletePatientConditional(@IdParam IdDt theId, @ConditionalOperationParam String theConditionalUrl) {
// Only one of theId or theConditionalUrl will have a value depending
// on whether the URL receieved was a logical ID, or a conditional
// search string
if (theId != null) {
// do a normal delete
} else {
// do a conditional delete
}
// otherwise, delete was successful
return; // can also return MethodOutcome
}
//END SNIPPET: deleteConditional
//START SNIPPET: history
@History()
public List<Patient> getPatientHistory(@IdParam IdDt theId) {
@ -681,6 +699,25 @@ public MethodOutcome createPatient(@ResourceParam Patient thePatient) {
public abstract MethodOutcome createNewPatient(@ResourceParam Patient thePatient);
//END SNIPPET: createClient
//START SNIPPET: updateConditional
@Update
public MethodOutcome updatePatientConditional(
@ResourceParam Patient thePatient,
@IdParam IdDt theId,
@ConditionalOperationParam String theConditional) {
// Only one of theId or theConditional will have a value and the other will be null,
// depending on the URL passed into the server.
if (theConditional != null) {
// Do a conditional update. theConditional will have a value like "Patient?identifier=system%7C00001"
} else {
// Do a normal update. theId will have the identity of the resource to update
}
return new MethodOutcome(); // populate this
}
//END SNIPPET: updateConditional
//START SNIPPET: update
@Update
public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) {

View File

@ -12,7 +12,7 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src/main/resources"/>
<classpathentry including="**/*.java" kind="src" path="src/main/resources"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<attributes>
<attribute name="maven.pomderived" value="true"/>

View File

@ -195,69 +195,6 @@
</plugins>
</reporting>
</profile>
<profile>
<id>ANDROID</id>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>0.9-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-android</artifactId>
<version>${slf4j_version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>false</shadedArtifactAttached>
<createDependencyReducedPom>true</createDependencyReducedPom>
<artifactSet>
<includes>
<!--
<include>javax.json:javax.json-api</include>
-->
<include>ca.uhn.hapi.fhir:hapi-fhir-structures-dstu</include>
<include>ca.uhn.hapi.fhir:hapi-fhir-structures-dstu</include>
<include>org.glassfish:javax.json</include>
<include>org.codehaus.woodstox:woodstox-core-asl</include>
<include>javax.xml.stream:stax-api</include>
<include>org.codehaus.woodstox:stax2-api</include>
<include>org.slf4j:slf4j*</include>
<include>org.apache.commons:*</include>
<include>org.apache.httpcomponents:*</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>javax.xml.stream</pattern>
<shadedPattern>ca.uhn.fhir.repackage.javax.xml.stream</shadedPattern>
</relocation>
<relocation>
<pattern>javax.json</pattern>
<shadedPattern>ca.uhn.fhir.repackage.javax.json</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.context;
*/
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@ -28,7 +29,6 @@ import java.util.Set;
import org.hl7.fhir.instance.model.IBase;
import ca.uhn.fhir.model.api.ICodeEnum;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
@ -41,7 +41,7 @@ public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDecl
public BaseRuntimeChildDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class<? extends IBase> theDatatype) {
super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName);
assert theDatatype != IDatatype.class; // should use RuntimeChildAny
assert Modifier.isInterface(theDatatype.getModifiers()) == false : "Type of " + theDatatype + " shouldn't be here"; // should use RuntimeChildAny
myDatatype = theDatatype;
}

View File

@ -45,9 +45,6 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
if (theNext == null) {
throw new NullPointerException();
}
// if (theNext.getValidChildNames().contains("performetPractitioner")) {
// throw new NullPointerException();
// }
if (theNext.getExtensionUrl() != null) {
throw new IllegalArgumentException("Shouldn't haven an extension URL, use addExtension instead");
}

View File

@ -29,6 +29,7 @@ import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBase;
import org.hl7.fhir.instance.model.api.IBaseEnumFactory;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
@ -102,8 +103,10 @@ public abstract class BaseRuntimeElementDefinition<T extends IBase> {
try {
if (theArgument == null) {
return getImplementingClass().newInstance();
} else {
} else if (theArgument instanceof IValueSetEnumBinder) {
return getImplementingClass().getConstructor(IValueSetEnumBinder.class).newInstance(theArgument);
} else {
return getImplementingClass().getConstructor(IBaseEnumFactory.class).newInstance(theArgument);
}
} catch (InstantiationException e) {
throw new ConfigurationException("Failed to instantiate type:" + getImplementingClass().getName(), e);

View File

@ -28,6 +28,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.WordUtils;
import org.hl7.fhir.instance.model.IBase;
@ -72,6 +73,7 @@ import ca.uhn.fhir.validation.FhirValidator;
public class FhirContext {
private static final List<Class<? extends IBaseResource>> EMPTY_LIST = Collections.emptyList();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContext.class);
private volatile Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> myClassToElementDefinition = Collections.emptyMap();
private volatile Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = Collections.emptyMap();
private HapiLocalizer myLocalizer = new HapiLocalizer();
@ -81,6 +83,7 @@ public class FhirContext {
private volatile IRestfulClientFactory myRestfulClientFactory;
private volatile RuntimeChildUndeclaredExtensionDefinition myRuntimeChildUndeclaredExtensionDefinition;
private final IFhirVersion myVersion;
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
/**
@ -123,7 +126,9 @@ public class FhirContext {
} else {
throw new IllegalStateException(getLocalizer().getMessage(FhirContext.class, "noStructures"));
}
ourLog.info("Creating new FHIR context for FHIR version [{}]", myVersion.getVersion().name());
scanResourceTypes(toElementList(theResourceTypes));
}
@ -176,7 +181,7 @@ public class FhirContext {
if (Modifier.isAbstract(theResourceType.getModifiers())) {
throw new IllegalArgumentException("Can not scan abstract or interface class (resource definitions must be concrete classes): " + theResourceType.getName());
}
RuntimeResourceDefinition retVal = (RuntimeResourceDefinition) myClassToElementDefinition.get(theResourceType);
if (retVal == null) {
retVal = scanResourceType((Class<? extends IResource>) theResourceType);
@ -186,7 +191,7 @@ public class FhirContext {
public RuntimeResourceDefinition getResourceDefinition(FhirVersionEnum theVersion, String theResourceName) {
Validate.notNull(theVersion, "theVersion can not be null");
if (theVersion.equals(myVersion.getVersion())) {
return getResourceDefinition(theResourceName);
}
@ -195,18 +200,18 @@ public class FhirContext {
if (nameToType == null) {
nameToType = new HashMap<String, Class<? extends IBaseResource>>();
ModelScanner.scanVersionPropertyFile(null, nameToType, theVersion);
Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> newVersionToNameToResourceType = new HashMap<FhirVersionEnum, Map<String,Class<? extends IBaseResource>>>();
Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> newVersionToNameToResourceType = new HashMap<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>>();
newVersionToNameToResourceType.putAll(myVersionToNameToResourceType);
newVersionToNameToResourceType.put(theVersion, nameToType);
myVersionToNameToResourceType = newVersionToNameToResourceType;
}
Class<? extends IBaseResource> resourceType = nameToType.get(theResourceName.toLowerCase());
if (resourceType==null) {
if (resourceType == null) {
throw new DataFormatException(createUnknownResourceNameError(theResourceName, theVersion));
}
return getResourceDefinition(resourceType);
}
@ -457,6 +462,10 @@ public class FhirContext {
return new FhirContext(FhirVersionEnum.DSTU2);
}
public static FhirContext forDstu2Hl7Org() {
return new FhirContext(FhirVersionEnum.DSTU2_HL7ORG);
}
private static Collection<Class<? extends IBaseResource>> toCollection(Class<? extends IBaseResource> theResourceType) {
ArrayList<Class<? extends IBaseResource>> retVal = new ArrayList<Class<? extends IBaseResource>>(1);
retVal.add(theResourceType);
@ -475,8 +484,4 @@ public class FhirContext {
return retVal;
}
public static FhirContext forDstu2Hl7Org() {
return new FhirContext(FhirVersionEnum.DSTU2_HL7ORG);
}
}

View File

@ -20,7 +20,7 @@ package ca.uhn.fhir.context;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.IOException;
import java.io.InputStream;
@ -55,6 +55,7 @@ import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBackboneElement;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseEnumFactory;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IDatatypeElement;
import org.hl7.fhir.instance.model.api.IDomainResource;
@ -65,7 +66,6 @@ import ca.uhn.fhir.model.api.CodeableConceptElement;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IBoundCodeableConcept;
import ca.uhn.fhir.model.api.ICodeEnum;
import ca.uhn.fhir.model.api.ICompositeElement;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
@ -216,7 +216,7 @@ class ModelScanner {
long time = System.currentTimeMillis() - start;
int size = myClassToElementDefinitions.size() - startSize;
ourLog.info("Done scanning FHIR library, found {} model entries in {}ms", size, time);
ourLog.debug("Done scanning FHIR library, found {} model entries in {}ms", size, time);
}
/**
@ -321,7 +321,7 @@ class ModelScanner {
}
private void scanCompositeDatatype(Class<? extends ICompositeType> theClass, DatatypeDef theDatatypeDefinition) {
ourLog.debug("Scanning resource class: {}", theClass.getName());
ourLog.debug("Scanning datatype class: {}", theClass.getName());
RuntimeCompositeDatatypeDefinition resourceDef;
if (theClass.equals(ExtensionDt.class)) {
@ -556,7 +556,7 @@ class ModelScanner {
RuntimeChildResourceBlockDefinition def = new RuntimeChildResourceBlockDefinition(next, childAnnotation, descriptionAnnotation, elementName, blockDef);
orderMap.put(order, def);
} else if (IDatatype.class.equals(nextElementType) || IElement.class.equals(nextElementType) || "org.hl7.fhir.instance.model.Type".equals(nextElementType.getName())) {
} else if (IDatatype.class.equals(nextElementType) || IElement.class.equals(nextElementType) || "org.hl7.fhir.instance.model.Type".equals(nextElementType.getName()) || IBaseDatatype.class.equals(nextElementType)) {
RuntimeChildAny def = new RuntimeChildAny(next, elementName, childAnnotation, descriptionAnnotation);
orderMap.put(order, def);
@ -566,10 +566,13 @@ class ModelScanner {
addScanAlso(nextDatatype);
BaseRuntimeChildDatatypeDefinition def;
if (IPrimitiveDatatype.class.isAssignableFrom(nextElementType)) {
if (IPrimitiveType.class.isAssignableFrom(nextElementType)) {
if (nextElementType.equals(BoundCodeDt.class)) {
IValueSetEnumBinder<Enum<?>> binder = getBoundCodeBinder(next);
def = new RuntimeChildPrimitiveBoundCodeDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, binder);
} else if (childAnnotation.enumFactory().getSimpleName().equals("NoEnumFactory") == false) {
Class<? extends IBaseEnumFactory<?>> enumFactory = childAnnotation.enumFactory();
def = new RuntimeChildEnumerationDatatypeDefinition(next, elementName, childAnnotation, descriptionAnnotation, nextDatatype, enumFactory);
} else {
def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, descriptionAnnotation, childAnnotation, nextDatatype);
}

View File

@ -0,0 +1,58 @@
package ca.uhn.fhir.context;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Field;
import org.hl7.fhir.instance.model.IBase;
import org.hl7.fhir.instance.model.api.IBaseEnumFactory;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
public class RuntimeChildEnumerationDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition {
private Class<? extends IBaseEnumFactory<?>> myBinderType;
private volatile IBaseEnumFactory<?> myBinder;
public RuntimeChildEnumerationDatatypeDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, Class<? extends IBase> theDatatype, Class<? extends IBaseEnumFactory<?>> theBinderType) {
super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype);
myBinderType = theBinderType;
}
@Override
public IBaseEnumFactory<?> getInstanceConstructorArguments() {
IBaseEnumFactory<?> retVal = myBinder;
if (retVal == null) {
try {
retVal = myBinderType.newInstance();
} catch (InstantiationException e) {
throw new IllegalStateException("Failed to instantiate " + myBinderType, e);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to instantiate " + myBinderType, e);
}
myBinder = retVal;
}
return retVal;
}
}

View File

@ -33,4 +33,5 @@ public class RuntimeChildPrimitiveDatatypeDefinition extends BaseRuntimeChildDat
super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation, theDatatype);
}
}

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.context;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IBaseResource;
public class RuntimeElementDirectResource extends BaseRuntimeElementDefinition<IBaseResource> {

View File

@ -25,6 +25,7 @@ import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
public abstract class BaseElement implements IElement, ISupportsUndeclaredExtensions {
@ -32,7 +33,7 @@ public abstract class BaseElement implements IElement, ISupportsUndeclaredExtens
private List<ExtensionDt> myUndeclaredModifierExtensions;
@Override
public ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IDatatype theValue) {
public ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IBaseDatatype theValue) {
Validate.notEmpty(theUrl, "URL must be populated");
Validate.notNull(theValue, "Value must not be null");
ExtensionDt retVal = new ExtensionDt(theIsModifier, theUrl, theValue);

View File

@ -24,21 +24,23 @@ import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.primitive.StringDt;
@DatatypeDef(name="Extension")
public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDatatype {
@DatatypeDef(name = "Extension")
public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDatatype, IBaseExtension<ExtensionDt> {
private boolean myModifier;
@Child(name="url", type=StringDt.class, order=0, min=1, max=1)
private StringDt myUrl;
@Child(name="value", type=IDatatype.class, order=1, min=0, max=1)
private IElement myValue;
@Child(name = "value", type = IDatatype.class, order = 1, min = 0, max = 1)
private IBaseDatatype myValue;
public ExtensionDt() {
}
@ -54,7 +56,7 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
myUrl = new StringDt(theUrl);
}
public ExtensionDt(boolean theIsModifier, String theUrl, IDatatype theValue) {
public ExtensionDt(boolean theIsModifier, String theUrl, IBaseDatatype theValue) {
Validate.notEmpty(theUrl, "URL must be populated");
Validate.notNull(theValue, "Value must not be null");
@ -63,15 +65,25 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
myValue=theValue;
}
public StringDt getUrl() {
if (myUrl==null) {
myUrl=new StringDt();
}
return myUrl;
/**
* Returns the URL for this extension.
* <p>
* Note that before HAPI 0.9 this method returned a {@link StringDt} but as of
* HAPI 0.9 this method returns a plain string. This was changed because it does not make sense to use a StringDt here
* since the URL itself can not contain extensions and it was therefore misleading.
* </p>
*/
public String getUrl() {
return myUrl != null ? myUrl.getValue() : null;
}
/**
* Retained for backward compatibility
*
* @see ExtensionDt#getUrl()
*/
public String getUrlAsString() {
return getUrl().getValue();
return getUrl();
}
/**
@ -81,7 +93,7 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
* {@link #getUndeclaredModifierExtensions()} to retrieve the child extensions.
* </p>
*/
public IElement getValue() {
public IBaseDatatype getValue() {
return myValue;
}
@ -117,7 +129,7 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
}
public ExtensionDt setUrl(String theUrl) {
myUrl = new StringDt(theUrl);
myUrl = theUrl != null ? new StringDt(theUrl) : myUrl;
return this;
}
@ -126,8 +138,9 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
return this;
}
public void setValue(IElement theValue) {
public ExtensionDt setValue(IBaseDatatype theValue) {
myValue = theValue;
return this;
}
@Override
@ -135,4 +148,9 @@ public class ExtensionDt extends BaseIdentifiableElement implements ICompositeDa
return new ArrayList<T>();
}
@Override
public List<ExtensionDt> getExtension() {
return getAllUndeclaredExtensions();
}
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.model.api;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
/*
* #%L
* HAPI FHIR - Core Library
@ -20,6 +22,6 @@ package ca.uhn.fhir.model.api;
* #L%
*/
public interface IDatatype extends IElement {
public interface IDatatype extends IElement, IBaseDatatype {
}

View File

@ -27,6 +27,7 @@ import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@ -49,4 +50,7 @@ public interface IFhirVersion {
Class<?> getContainedType();
BaseCodingDt newCodingDt();
}

View File

@ -22,6 +22,8 @@ package ca.uhn.fhir.model.api;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
public interface ISupportsUndeclaredExtensions extends IElement {
/**
@ -52,7 +54,7 @@ public interface ISupportsUndeclaredExtensions extends IElement {
* <li>{@link ExtensionDt#setUrl(String) URL}</li>
* <li>And one of:
* <ul>
* <li>{@link ExtensionDt#setValue(IElement) A datatype value}</li>
* <li>{@link ExtensionDt#setValue(IBaseDatatype) A datatype value}</li>
* <li>{@link #addUndeclaredExtension(ExtensionDt) Further sub-extensions}</li>
* </ul>
* </ul>
@ -64,7 +66,7 @@ public interface ISupportsUndeclaredExtensions extends IElement {
/**
* Adds an extension to this object
*/
ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IDatatype theValue);
ExtensionDt addUndeclaredExtension(boolean theIsModifier, String theUrl, IBaseDatatype theValue);
/**
* Adds an extension to this object. This method is intended for use when

View File

@ -28,6 +28,7 @@ import java.util.Date;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.model.primitive.DecimalDt;
@ -62,6 +63,36 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
*/
public abstract class ResourceMetadataKeyEnum<T> {
public static final ResourceMetadataKeyEnum<List<BaseCodingDt>> SECURITY_LABELS = new ResourceMetadataKeyEnum<List<BaseCodingDt>>("SECURITY_LABELS") {
@Override
public List<BaseCodingDt> get(IResource resource) {
Object obj = resource.getResourceMetadata().get(SECURITY_LABELS);
if (obj == null) {
return null;
} else {
try {
List<BaseCodingDt> securityLabels = (List<BaseCodingDt>) obj;
if (securityLabels.isEmpty())
return null;
else
return securityLabels;
} catch (ClassCastException e) {
throw new InternalErrorException("Found an object of type '" + obj.getClass().getCanonicalName() + "' in resource metadata for key SECURITY_LABELS - Expected "
+ BaseCodingDt.class.getCanonicalName());
}
}
}
@Override
public void put(IResource iResource, List<BaseCodingDt> labels) {
iResource.getResourceMetadata().put(SECURITY_LABELS, labels);
}
};
/**
* If present and populated with a date/time (as an instance of {@link InstantDt}), this value is an indication that the resource is in the deleted state. This key is only used in a limited number
* of scenarios, such as POSTing transaction bundles to a server, or returning resource history.

View File

@ -28,6 +28,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.instance.model.IBase;
/**
* A collection of tags present on a single resource. TagList is backed by a {@link LinkedHashSet}, so the order of added tags will be consistent, but duplicates will not be preserved.
*
@ -35,7 +37,7 @@ import java.util.Set;
* <b>Thread safety:</b> This class is not thread safe
* </p>
*/
public class TagList implements Set<Tag>, Serializable {
public class TagList implements Set<Tag>, Serializable, IBase {
public static final String ATTR_CATEGORY = "category";
public static final String ELEMENT_NAME = "TagList";

View File

@ -24,6 +24,9 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Enumeration;
import org.hl7.fhir.instance.model.api.IBaseEnumFactory;
import ca.uhn.fhir.model.api.IElement;
@ -96,5 +99,29 @@ public @interface Child {
// * HumanNameDt which adds extensions of your choosing) you could do that using a replacement field.
// */
// String replaces() default "";
/**
* For children which accept an {@link Enumeration} as the type, this
* field indicates the type to use for the enum factory
*/
Class<? extends IBaseEnumFactory<?>> enumFactory() default NoEnumFactory.class;
public static class NoEnumFactory implements IBaseEnumFactory<Enum<?>> {
private NoEnumFactory() {
// non instantiable
}
@Override
public Enum<?> fromCode(String theCodeString) throws IllegalArgumentException {
return null;
}
@Override
public String toCode(Enum<?> theCode) {
return null;
}
}
}

View File

@ -25,6 +25,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.hl7.fhir.instance.model.IBaseResource;
@Target(value=ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SearchParamDefinition {
@ -57,5 +59,11 @@ public @interface SearchParamDefinition {
* </p>
*/
String[] compositeOf() default {};
/**
* For search params of type "reference", this can optionally be used to
* specify the resource type(s) that this parameter applies to.
*/
Class<? extends IBaseResource>[] target() default {};
}

View File

@ -65,10 +65,17 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC
* A representation of the meaning of the code in the system, following the rules of the system.
* </p>
*/
public abstract StringDt getDisplayElement();
public abstract StringDt getDisplayElement();
public abstract BaseCodingDt setDisplay( String theString);
/*
todo: handle version
public abstract StringDt getVersion();
public abstract BaseCodingDt setVersion ( String theString);
*/
/**
* {@inheritDoc}
*/

View File

@ -22,14 +22,12 @@ package ca.uhn.fhir.model.base.composite;
import java.io.IOException;
import java.io.Reader;
import java.util.List;
import javax.json.JsonValue;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
@ -40,7 +38,7 @@ import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.client.BaseClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
public abstract class BaseResourceReferenceDt extends BaseIdentifiableElement {
public abstract class BaseResourceReferenceDt extends BaseIdentifiableElement implements IBaseDatatype {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseResourceReferenceDt.class);
private IResource myResource;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.model.base.resource;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.api.IResource;
public interface BaseBinary extends IResource {

View File

@ -118,6 +118,18 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String> {
*
* @param theResourceType
* The resource type (e.g. "Patient")
* @param theIdPart
* The ID (e.g. "123")
*/
public IdDt(String theResourceType, Long theIdPart) {
this(theResourceType, toPlainStringWithNpeThrowIfNeeded(theIdPart));
}
/**
* Constructor
*
* @param theResourceType
* The resource type (e.g. "Patient")
* @param theId
* The ID (e.g. "123")
*/
@ -515,6 +527,13 @@ public class IdDt extends UriDt implements IPrimitiveDatatype<String> {
return theIdPart.toPlainString();
}
private static String toPlainStringWithNpeThrowIfNeeded(Long theIdPart) {
if (theIdPart == null) {
throw new NullPointerException("Long ID can not be null");
}
return theIdPart.toString();
}
@Override
public boolean isEmpty() {
return isBlank(getValue());

View File

@ -20,7 +20,9 @@ package ca.uhn.fhir.parser;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.Reader;
@ -47,6 +49,8 @@ import javax.json.stream.JsonGenerator;
import javax.json.stream.JsonGeneratorFactory;
import javax.json.stream.JsonParsingException;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.primitive.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.IBase;
@ -54,7 +58,11 @@ import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseBooleanDatatype;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseDecimalDatatype;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
import org.hl7.fhir.instance.model.api.IBaseIntegerDatatype;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
@ -85,7 +93,6 @@ import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.BaseBinary;
import ca.uhn.fhir.model.primitive.BooleanDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
@ -127,7 +134,7 @@ public class JsonParser extends BaseParser implements IParser {
myContext = theContext;
}
private void addToHeldExtensions(int valueIdx, List<ExtensionDt> ext, ArrayList<ArrayList<HeldExtension>> list) {
private void addToHeldExtensions(int valueIdx, List<? extends IBaseExtension<?>> ext, ArrayList<ArrayList<HeldExtension>> list, boolean theIsModifier) {
if (ext.size() > 0) {
list.ensureCapacity(valueIdx);
while (list.size() <= valueIdx) {
@ -136,8 +143,8 @@ public class JsonParser extends BaseParser implements IParser {
if (list.get(valueIdx) == null) {
list.set(valueIdx, new ArrayList<JsonParser.HeldExtension>());
}
for (ExtensionDt next : ext) {
list.get(valueIdx).add(new HeldExtension(next));
for (IBaseExtension<?> next : ext) {
list.get(valueIdx).add(new HeldExtension(next, theIsModifier));
}
}
}
@ -283,7 +290,7 @@ public class JsonParser extends BaseParser implements IParser {
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(resource);
encodeResourceToJsonStreamWriter(resDef, resource, theEventWriter, "resource", false);
}
if (nextEntry.getSearchMode().isEmpty() == false || nextEntry.getScore().isEmpty() == false) {
theEventWriter.writeStartObject("search");
writeOptionalTagWithTextNode(theEventWriter, "mode", nextEntry.getSearchMode().getValueAsString());
@ -325,7 +332,6 @@ public class JsonParser extends BaseParser implements IParser {
//
// writeAuthor(nextEntry, theEventWriter);
if (nextEntry.getSummary().isEmpty() == false) {
theEventWriter.write("summary", nextEntry.getSummary().getValueAsString());
}
@ -411,8 +417,7 @@ public class JsonParser extends BaseParser implements IParser {
}
case CONTAINED_RESOURCES: {
/*
* Disabled per #103
* ContainedDt value = (ContainedDt) theNextValue; for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) {
* Disabled per #103 ContainedDt value = (ContainedDt) theNextValue; for (IResource next : value.getContainedResources()) { if (getContainedResources().getResourceId(next) != null) {
* continue; } encodeResourceToJsonStreamWriter(theResDef, next, theWriter, null, true, fixContainedResourceId(next.getId().getValue())); }
*/
List<IBaseResource> containedResources = getContainedResources().getContainedResources();
@ -460,11 +465,15 @@ public class JsonParser extends BaseParser implements IParser {
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theNextValue, JsonGenerator theEventWriter,
List<? extends BaseRuntimeChildDefinition> theChildren, boolean theIsSubElementWithinResource) throws IOException {
for (BaseRuntimeChildDefinition nextChild : theChildren) {
if (nextChild.getElementName().equals("extension") || nextChild.getElementName().equals("modifierExtension")) {
continue;
}
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
INarrativeGenerator gen = myContext.getNarrativeGenerator();
if (gen != null) {
BaseNarrativeDt<?> narr = ((IResource)theResource).getText();
BaseNarrativeDt<?> narr = ((IResource) theResource).getText();
gen.generateNarrative(theResDef.getResourceProfile(), theResource, narr);
if (narr != null) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
@ -540,12 +549,25 @@ public class JsonParser extends BaseParser implements IParser {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childDef, null, theIsSubElementWithinResource);
}
if (nextValue instanceof ISupportsUndeclaredExtensions && primitive) {
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
addToHeldExtensions(valueIdx, ext, extensions);
if (primitive) {
if (nextValue instanceof ISupportsUndeclaredExtensions) {
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredExtensions();
addToHeldExtensions(valueIdx, ext, extensions, false);
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
addToHeldExtensions(valueIdx, ext, modifierExtensions);
ext = ((ISupportsUndeclaredExtensions) nextValue).getUndeclaredModifierExtensions();
addToHeldExtensions(valueIdx, ext, modifierExtensions, true);
} else {
if (nextValue instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) nextValue;
List<? extends IBaseExtension<?>> ext = element.getExtension();
addToHeldExtensions(valueIdx, ext, extensions, false);
}
if (nextValue instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
List<? extends IBaseExtension<?>> ext = element.getModifierExtension();
addToHeldExtensions(valueIdx, ext, extensions, true);
}
}
}
}
@ -648,11 +670,26 @@ public class JsonParser extends BaseParser implements IParser {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1) && theResource instanceof IResource) {
IResource resource = (IResource) theResource;
if (!ElementUtil.isEmpty(resource.getId().getVersionIdPart(), ResourceMetadataKeyEnum.UPDATED.get(resource))) {
List<BaseCodingDt> securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(resource);
if (securityLabels == null) {
securityLabels = Collections.emptyList();
}
if (!ElementUtil.isEmpty(resource.getId().getVersionIdPart(), ResourceMetadataKeyEnum.UPDATED.get(resource), securityLabels)) {
theEventWriter.writeStartObject("meta");
writeOptionalTagWithTextNode(theEventWriter, "versionId", resource.getId().getVersionIdPart());
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", ResourceMetadataKeyEnum.UPDATED.get(resource));
theEventWriter.writeEnd();
if (securityLabels.isEmpty()==false) {
theEventWriter.writeStartArray("security");
for (BaseCodingDt securityLabel : securityLabels) {
theEventWriter.writeStartObject();
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
encodeCompositeElementChildrenToStreamWriter(resDef, resource, securityLabel, theEventWriter, def.getChildren(), theIsSubElementWithinResource);
theEventWriter.writeEnd();
}
theEventWriter.writeEnd();
}
theEventWriter.writeEnd(); //end meta
}
}
@ -663,7 +700,7 @@ public class JsonParser extends BaseParser implements IParser {
} else {
encodeCompositeElementToStreamWriter(theResDef, theResource, theResource, theEventWriter, resDef, theIsSubElementWithinResource);
}
theEventWriter.writeEnd();
}
@ -751,22 +788,44 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void extractUndeclaredExtensions(IBase theResource, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
if (theResource instanceof ISupportsUndeclaredExtensions) {
List<ExtensionDt> ext = ((ISupportsUndeclaredExtensions) theResource).getUndeclaredExtensions();
private void extractUndeclaredExtensions(IBase theElement, List<HeldExtension> extensions, List<HeldExtension> modifierExtensions) {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions element = (ISupportsUndeclaredExtensions) theElement;
List<ExtensionDt> ext = element.getUndeclaredExtensions();
for (ExtensionDt next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
extensions.add(new HeldExtension(next));
extensions.add(new HeldExtension(next, false));
}
ext = ((ISupportsUndeclaredExtensions) theResource).getUndeclaredModifierExtensions();
ext = element.getUndeclaredModifierExtensions();
for (ExtensionDt next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
modifierExtensions.add(new HeldExtension(next));
modifierExtensions.add(new HeldExtension(next, true));
}
} else {
if (theElement instanceof IBaseHasExtensions) {
IBaseHasExtensions element = (IBaseHasExtensions) theElement;
List<? extends IBaseExtension<?>> ext = element.getExtension();
for (IBaseExtension<?> next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
extensions.add(new HeldExtension(next, false));
}
}
if (theElement instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) theElement;
List<? extends IBaseExtension<?>> ext = element.getModifierExtension();
for (IBaseExtension<?> next : ext) {
if (next == null || next.isEmpty()) {
continue;
}
modifierExtensions.add(new HeldExtension(next, true));
}
}
}
}
@ -788,16 +847,15 @@ public class JsonParser extends BaseParser implements IParser {
return;
}
boolean newerThanDstu1 = myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1);
JsonObject alternate = (JsonObject) theAlternateVal;
for (Entry<String, JsonValue> nextEntry : alternate.entrySet()) {
String nextKey = nextEntry.getKey();
JsonValue nextVal = nextEntry.getValue();
if (!newerThanDstu1 && "extension".equals(nextKey)) {
if ("extension".equals(nextKey)) {
boolean isModifier = false;
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier);
} else if (!newerThanDstu1 && "modifierExtension".equals(nextKey)) {
} else if ("modifierExtension".equals(nextKey)) {
boolean isModifier = true;
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtension(theState, array, isModifier);
@ -811,12 +869,6 @@ public class JsonParser extends BaseParser implements IParser {
default:
break;
}
} else if (newerThanDstu1) {
if (nextKey.indexOf(':') > -1 && newerThanDstu1) {
JsonArray array = (JsonArray) nextEntry.getValue();
parseExtensionInDstu2Style(false, theState, null, nextKey, array);
continue;
}
}
}
}
@ -935,7 +987,6 @@ public class JsonParser extends BaseParser implements IParser {
private void parseChildren(JsonObject theObject, ParserState<?> theState) {
String elementId = null;
boolean newerThanDstu1 = myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1);
for (String nextName : theObject.keySet()) {
if ("resourceType".equals(nextName)) {
continue;
@ -948,29 +999,16 @@ public class JsonParser extends BaseParser implements IParser {
// _id is incorrect, but some early examples in the FHIR spec used it
elementId = theObject.getString(nextName);
continue;
} else if (!newerThanDstu1 && "extension".equals(nextName)) {
} else if ("extension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, false);
continue;
} else if (!newerThanDstu1 && "modifierExtension".equals(nextName)) {
} else if ("modifierExtension".equals(nextName)) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtension(theState, array, true);
continue;
} else if (newerThanDstu1 && "modifier".equals(nextName)) {
JsonObject obj = theObject.getJsonObject(nextName);
for (String nextUrl : obj.keySet()) {
JsonArray array = obj.getJsonArray(nextUrl);
parseExtensionInDstu2Style(true, theState, null, nextUrl, array);
}
continue;
} else if (nextName.charAt(0) == '_') {
continue;
} else {
if (newerThanDstu1 && nextName.indexOf(':') > -1) {
JsonArray array = theObject.getJsonArray(nextName);
parseExtensionInDstu2Style(false, theState, null, nextName, array);
continue;
}
}
JsonValue nextVal = theObject.get(nextName);
@ -1210,42 +1248,18 @@ public class JsonParser extends BaseParser implements IParser {
private void writeExtensionsAsDirectChild(IBaseResource theResource, JsonGenerator theEventWriter, RuntimeResourceDefinition resDef, List<HeldExtension> extensions,
List<HeldExtension> modifierExtensions, String theParentExtensionUrl) throws IOException {
if (extensions.isEmpty() == false) {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
Collections.sort(extensions);
String currentlyWritingExtensionUrl = null;
for (HeldExtension next : extensions) {
currentlyWritingExtensionUrl = next.writeExtensionInDstu2Format(resDef, theResource, theEventWriter, currentlyWritingExtensionUrl, theParentExtensionUrl);
}
if (currentlyWritingExtensionUrl != null) {
theEventWriter.writeEnd();
}
} else {
theEventWriter.writeStartArray("extension");
for (HeldExtension next : extensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
theEventWriter.writeStartArray("extension");
for (HeldExtension next : extensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
}
if (modifierExtensions.isEmpty() == false) {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
Collections.sort(modifierExtensions);
theEventWriter.writeStartObject("modifier");
String currentlyWritingExtensionUrl = null;
for (HeldExtension next : modifierExtensions) {
currentlyWritingExtensionUrl = next.writeExtensionInDstu2Format(resDef, theResource, theEventWriter, currentlyWritingExtensionUrl, theParentExtensionUrl);
}
if (currentlyWritingExtensionUrl != null) {
theEventWriter.writeEnd();
}
theEventWriter.writeEnd();
} else {
theEventWriter.writeStartArray("modifierExtension");
for (HeldExtension next : modifierExtensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
theEventWriter.writeStartArray("modifierExtension");
for (HeldExtension next : modifierExtensions) {
next.write(resDef, theResource, theEventWriter);
}
theEventWriter.writeEnd();
}
}
@ -1283,14 +1297,6 @@ public class JsonParser extends BaseParser implements IParser {
}
}
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, String theValue) {
if (theValue != null && !theValue.isEmpty()) {
theEventWriter.write(theElementName, theValue);
} else {
theEventWriter.writeNull(theElementName);
}
}
private void writeTagWithTextNode(JsonGenerator theEventWriter, String theElementName, StringDt theStringDt) {
if (StringUtils.isNotBlank(theStringDt.getValue())) {
theEventWriter.write(theElementName, theStringDt.getValue());
@ -1303,12 +1309,14 @@ public class JsonParser extends BaseParser implements IParser {
private class HeldExtension implements Comparable<HeldExtension> {
private RuntimeChildDeclaredExtensionDefinition myDef;
private ExtensionDt myUndeclaredExtension;
private IBaseExtension<?> myUndeclaredExtension;
private IBase myValue;
private boolean myModifier;
public HeldExtension(ExtensionDt theUndeclaredExtension) {
public HeldExtension(IBaseExtension<?> theUndeclaredExtension, boolean theModifier) {
assert theUndeclaredExtension != null;
myUndeclaredExtension = theUndeclaredExtension;
myModifier = theModifier;
}
public HeldExtension(RuntimeChildDeclaredExtensionDefinition theDef, IBase theValue) {
@ -1337,66 +1345,38 @@ public class JsonParser extends BaseParser implements IParser {
}
}
public String writeExtensionInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, String theCurrentlyWritingExtensionUrl,
String theParentExtensionUrl) throws IOException {
if (myUndeclaredExtension != null) {
return writeUndeclaredExtInDstu2Format(theResDef, theResource, theEventWriter, myUndeclaredExtension, theCurrentlyWritingExtensionUrl, theParentExtensionUrl);
} else {
String extensionUrl = myDef.getExtensionUrl();
checkIfNewExtensionUrlArrayIsNeeded(theEventWriter, extensionUrl, theCurrentlyWritingExtensionUrl, theParentExtensionUrl);
theEventWriter.writeStartObject();
BaseRuntimeElementDefinition<?> def = myDef.getChildElementDefinitionByDatatype(myValue.getClass());
if (def.getChildType() == ChildTypeEnum.RESOURCE_BLOCK) {
extractAndWriteExtensionsAsDirectChild(myValue, theEventWriter, def, theResDef, theResource, extensionUrl);
} else {
String childName = myDef.getChildNameByDatatype(myValue.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, myValue, def, childName, false);
}
theEventWriter.writeEnd();
return extensionUrl;
}
}
private void checkIfNewExtensionUrlArrayIsNeeded(JsonGenerator theEventWriter, String theExtensionUrl, String theCurrentlyWritingExtensionUrl, String theParentExtensionUrl) {
if (StringUtils.equals(theCurrentlyWritingExtensionUrl, theExtensionUrl) == false) {
if (isNotBlank(theCurrentlyWritingExtensionUrl)) {
theEventWriter.writeEnd();
}
String urlToWrite = UrlUtil.constructRelativeUrl(theParentExtensionUrl, theExtensionUrl);
theEventWriter.writeStartArray(urlToWrite);
}
}
private void writeUndeclaredExtInDstu1Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, ExtensionDt ext) throws IOException {
IElement value = ext.getValue();
String extensionUrl = ext.getUrl().getValue();
private void writeUndeclaredExtInDstu1Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, IBaseExtension<?> ext) throws IOException {
IBaseDatatype value = ext.getValue();
String extensionUrl = ext.getUrl();
theEventWriter.writeStartObject();
theEventWriter.write("url", extensionUrl);
boolean noValue = value == null || value.isEmpty();
if (noValue && ext.getAllUndeclaredExtensions().isEmpty()) {
if (noValue && ext.getExtension().isEmpty()) {
ourLog.debug("Extension with URL[{}] has no value", extensionUrl);
} else if (noValue) {
theEventWriter.writeStartArray("extension");
if (myModifier) {
theEventWriter.writeStartArray("modifierExtension");
} else {
theEventWriter.writeStartArray("extension");
}
for (ExtensionDt next : ext.getUndeclaredExtensions()) {
writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, next);
for (Object next : ext.getExtension()) {
writeUndeclaredExtInDstu1Format(theResDef, theResource, theEventWriter, (IBaseExtension<?>) next);
}
theEventWriter.writeEnd();
} else {
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
if (childName == null) {
childName = "value" + myContext.getElementDefinition(value.getClass()).getName();
}
BaseRuntimeElementDefinition<?> childDef = myContext.getElementDefinition(value.getClass());
if (childDef == null) {
throw new ConfigurationException("Unable to encode extension, unregognized child element type: " + value.getClass().getCanonicalName());
}
BaseRuntimeElementDefinition<?> childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true);
}
@ -1405,53 +1385,10 @@ public class JsonParser extends BaseParser implements IParser {
theEventWriter.writeEnd();
}
private String writeUndeclaredExtInDstu2Format(RuntimeResourceDefinition theResDef, IBaseResource theResource, JsonGenerator theEventWriter, ExtensionDt ext,
String theCurrentlyWritingExtensionUrl, String theParentExtensionUrl) throws IOException {
IElement value = ext.getValue();
String extensionUrl = ext.getUrl().getValue();
checkIfNewExtensionUrlArrayIsNeeded(theEventWriter, extensionUrl, theCurrentlyWritingExtensionUrl, theParentExtensionUrl);
theEventWriter.writeStartObject();
boolean noValue = value == null || value.isEmpty();
if (noValue && ext.getAllUndeclaredExtensions().isEmpty()) {
ourLog.debug("Extension with URL[{}] has no value", extensionUrl);
} else if (noValue) {
BaseRuntimeElementDefinition<?> elemDef = null;
RuntimeResourceDefinition resDef = myContext.getResourceDefinition(theResource);
extractAndWriteExtensionsAsDirectChild(ext, theEventWriter, elemDef, resDef, theResource, extensionUrl);
} else {
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
BaseRuntimeElementDefinition<?> childDef;
if (childName == null) {
childDef = myContext.getElementDefinition(value.getClass());
if (childDef == null) {
throw new ConfigurationException("Unable to encode extension, unrecognized child element type: " + value.getClass().getCanonicalName());
} else {
childName = RuntimeChildUndeclaredExtensionDefinition.createExtensionChildName(childDef);
}
} else {
childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
}
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, value, childDef, childName, true);
}
theEventWriter.writeEnd();
return extensionUrl;
}
@Override
public int compareTo(HeldExtension theArg0) {
String url1 = myDef != null ? myDef.getExtensionUrl() : myUndeclaredExtension.getUrlAsString();
String url2 = theArg0.myDef != null ? theArg0.myDef.getExtensionUrl() : theArg0.myUndeclaredExtension.getUrlAsString();
String url1 = myDef != null ? myDef.getExtensionUrl() : myUndeclaredExtension.getUrl();
String url2 = theArg0.myDef != null ? theArg0.myDef.getExtensionUrl() : theArg0.myUndeclaredExtension.getUrl();
url1 = defaultString(url1);
url2 = defaultString(url2);
return url1.compareTo(url2);

View File

@ -30,6 +30,8 @@ import java.util.Map;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.IBase;
@ -37,7 +39,11 @@ import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.ICompositeType;
import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseElement;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
import org.hl7.fhir.instance.model.api.IReference;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
@ -48,29 +54,25 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition;
import ca.uhn.fhir.context.RuntimeElemContainedResources;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeNarrativeDefinition;
import ca.uhn.fhir.context.RuntimeResourceBlockDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeResourceReferenceDefinition;
import ca.uhn.fhir.model.api.BaseBundle;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.ICompositeElement;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IExtension;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.api.IIdentifiableElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.IResourceBlock;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.BaseBinary;
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
@ -819,11 +821,29 @@ class ParserState<T> {
ExtensionState newState = new ExtensionState(myPreResourceState, newExtension);
push(newState);
} else {
throw new DataFormatException("Type " + getCurrentElement() + " does not support undeclared extentions, and found an extension with URL: " + theUrlAttr);
if (theIsModifier == false) {
if (getCurrentElement() instanceof IBaseHasExtensions) {
IBaseExtension<?> ext = ((IBaseHasExtensions) getCurrentElement()).addExtension();
ext.setUrl(theUrlAttr);
ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
push(newState);
} else {
throw new DataFormatException("Type " + getCurrentElement() + " does not support undeclared extentions, and found an extension with URL: " + theUrlAttr);
}
} else {
if (getCurrentElement() instanceof IBaseHasModifierExtensions) {
IBaseExtension<?> ext = ((IBaseHasModifierExtensions) getCurrentElement()).addModifierExtension();
ext.setUrl(theUrlAttr);
ParserState<T>.ExtensionState newState = new ExtensionState(myPreResourceState, ext);
push(newState);
} else {
throw new DataFormatException("Type " + getCurrentElement() + " does not support undeclared extentions, and found an extension with URL: " + theUrlAttr);
}
}
}
}
protected Object getCurrentElement() {
protected IBase getCurrentElement() {
return null;
}
@ -879,7 +899,7 @@ class ParserState<T> {
if ("id".equals(theName)) {
if (myInstance instanceof IIdentifiableElement) {
((IIdentifiableElement) myInstance).setElementSpecificId((theValue));
} else if (myInstance instanceof IBaseResource) {
} else {
(myInstance).setId(new IdDt(theValue));
}
} else if ("contentType".equals(theName)) {
@ -1578,16 +1598,16 @@ class ParserState<T> {
private class ExtensionState extends BaseState {
private ExtensionDt myExtension;
private IBaseExtension<?> myExtension;
public ExtensionState(PreResourceState thePreResourceState, ExtensionDt theExtension) {
public ExtensionState(PreResourceState thePreResourceState, IBaseExtension<?> theExtension) {
super(thePreResourceState);
myExtension = theExtension;
}
@Override
public void endingElement() throws DataFormatException {
if (myExtension.getValue() != null && myExtension.getUndeclaredExtensions().size() > 0) {
if (myExtension.getValue() != null && myExtension.getExtension().size() > 0) {
throw new DataFormatException("Extension must not have both a value and other contained extensions");
}
pop();
@ -1612,7 +1632,7 @@ class ParserState<T> {
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance();
myExtension.setValue((IElement) newChildInstance);
myExtension.setValue(newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
@ -1635,12 +1655,27 @@ class ParserState<T> {
}
@Override
protected IElement getCurrentElement() {
protected IBaseExtension<?> getCurrentElement() {
return myExtension;
}
}
private class SecurityLabelElementStateHapi extends ElementCompositeState<BaseCodingDt> {
public SecurityLabelElementStateHapi(ParserState<T>.PreResourceState thePreResourceState,BaseRuntimeElementCompositeDefinition<?> theDef, BaseCodingDt codingDt) {
super(thePreResourceState, theDef, codingDt);
}
@Override
public void endingElement() throws DataFormatException {
pop();
}
}
private class MetaElementState extends BaseState {
private ResourceMetadataMap myMap;
@ -1664,6 +1699,17 @@ class ParserState<T> {
InstantDt updated = new InstantDt();
push(new PrimitiveState(getPreResourceState(), updated));
myMap.put(ResourceMetadataKeyEnum.UPDATED, updated);
} else if (theLocalPart.equals("security")) {
@SuppressWarnings("unchecked")
List<BaseCodingDt> securityLabels = (List<BaseCodingDt>) myMap.get(ResourceMetadataKeyEnum.SECURITY_LABELS);
if (securityLabels == null) {
securityLabels = new ArrayList<BaseCodingDt>();
myMap.put(ResourceMetadataKeyEnum.SECURITY_LABELS, securityLabels);
}
BaseCodingDt securityLabel= myContext.getVersion().newCodingDt();
BaseRuntimeElementCompositeDefinition<?> codinfDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
push(new SecurityLabelElementStateHapi(getPreResourceState(), codinfDef, securityLabel));
securityLabels.add(securityLabel);
} else {
throw new DataFormatException("Unexpected element '" + theLocalPart + "' found in 'meta' element");
}
@ -1805,6 +1851,15 @@ class ParserState<T> {
super(theResourceType);
}
@SuppressWarnings("unchecked")
@Override
public void wereBack() {
super.wereBack();
if (myTarget == null) {
myObject = (T) getCurrentElement();
}
}
@Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
super.enteringNewElement(theNamespaceURI, theLocalPart);
@ -1896,7 +1951,6 @@ class ParserState<T> {
return true;
}
@SuppressWarnings("unchecked")
@Override
public void wereBack() {
myContext.newTerser().visit(myInstance, new IModelVisitor() {
@ -1953,7 +2007,7 @@ class ParserState<T> {
}
@Override
protected TagList getCurrentElement() {
protected IBase getCurrentElement() {
return myTagList;
}
@ -2237,6 +2291,11 @@ class ParserState<T> {
pop();
}
@Override
protected IBase getCurrentElement() {
return myTagList;
}
@Override
public void enteringNewElement(String theNamespaceURI, String theLocalPart) throws DataFormatException {
if (TagList.ATTR_CATEGORY.equals(theLocalPart)) {

View File

@ -27,6 +27,7 @@ import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@ -47,7 +48,12 @@ import javax.xml.stream.events.XMLEvent;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.IBase;
import org.hl7.fhir.instance.model.IBaseResource;
import org.hl7.fhir.instance.model.IPrimitiveType;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
import org.hl7.fhir.instance.model.api.IDomainResource;
import org.hl7.fhir.instance.model.api.INarrative;
@ -64,14 +70,12 @@ import ca.uhn.fhir.context.RuntimeChildUndeclaredExtensionDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.BundleEntry;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
@ -81,7 +85,6 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.util.NonPrettyPrintWriterWrapper;
import ca.uhn.fhir.util.PrettyPrintWriterWrapper;
import ca.uhn.fhir.util.XmlUtil;
@ -171,7 +174,6 @@ public class XmlParser extends BaseParser implements IParser {
throw new DataFormatException("Extension element has no 'url' attribute");
}
parserState.enteringNewElementExtension(elem, urlAttr.getValue(), true);
} else {
String elementName = elem.getName().getLocalPart();
@ -390,7 +392,7 @@ public class XmlParser extends BaseParser implements IParser {
if (nextEntry.getDeletedAt() != null && nextEntry.getDeletedAt().isEmpty() == false) {
deleted = true;
}
writeOptionalTagWithValue(theEventWriter, "base", determineResourceBaseUrl(bundleBaseUrl, nextEntry));
IResource resource = nextEntry.getResource();
@ -433,8 +435,7 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.close();
}
private void encodeChildElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl, boolean theIncludedResource)
throws XMLStreamException, DataFormatException {
private void encodeChildElementToStreamWriter(IBaseResource theResource, XMLStreamWriter theEventWriter, IBase nextValue, String childName, BaseRuntimeElementDefinition<?> childDef, String theExtensionUrl, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
if (nextValue.isEmpty()) {
if (childDef.getChildType() == ChildTypeEnum.CONTAINED_RESOURCES && getContainedResources().isEmpty() == false && theIncludedResource == false) {
// We still want to go in..
@ -445,12 +446,12 @@ public class XmlParser extends BaseParser implements IParser {
switch (childDef.getChildType()) {
case PRIMITIVE_DATATYPE: {
IPrimitiveDatatype<?> pd = (IPrimitiveDatatype<?>) nextValue;
IPrimitiveType<?> pd = (IPrimitiveType<?>) nextValue;
String value = pd.getValueAsString();
if (value != null) {
theEventWriter.writeStartElement(childName);
theEventWriter.writeAttribute("value", value);
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, nextValue, theIncludedResource);
encodeExtensionsIfPresent(theResource, theEventWriter, nextValue, theIncludedResource);
theEventWriter.writeEndElement();
}
break;
@ -462,7 +463,7 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.writeAttribute("url", theExtensionUrl);
}
BaseRuntimeElementCompositeDefinition<?> childCompositeDef = (BaseRuntimeElementCompositeDefinition<?>) childDef;
encodeCompositeElementToStreamWriter(theResDef, theResource, nextValue, theEventWriter, childCompositeDef, theIncludedResource);
encodeCompositeElementToStreamWriter(theResource, nextValue, theEventWriter, childCompositeDef, theIncludedResource);
theEventWriter.writeEndElement();
break;
}
@ -513,21 +514,25 @@ public class XmlParser extends BaseParser implements IParser {
}
private void encodeCompositeElementChildrenToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> children, boolean theIncludedResource) throws XMLStreamException,
DataFormatException {
private void encodeCompositeElementChildrenToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, List<? extends BaseRuntimeChildDefinition> children, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
for (BaseRuntimeChildDefinition nextChild : children) {
if (nextChild.getElementName().equals("extension") || nextChild.getElementName().equals("modifierExtension")) {
continue;
}
if (nextChild instanceof RuntimeChildNarrativeDefinition && !theIncludedResource) {
INarrativeGenerator gen = myContext.getNarrativeGenerator();
if (theResource instanceof IResource) {
BaseNarrativeDt<?> narr = ((IResource) theResource).getText();
if (gen != null && narr.isEmpty()) {
gen.generateNarrative(theResDef.getResourceProfile(), theResource, narr);
String resourceProfile = myContext.getResourceDefinition(theResource).getResourceProfile();
gen.generateNarrative(resourceProfile, theResource, narr);
}
if (narr.isEmpty()==false) {
if (narr.isEmpty() == false) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr, childName, type, null, theIncludedResource);
encodeChildElementToStreamWriter(theResource, theEventWriter, narr, childName, type, null, theIncludedResource);
continue;
}
} else {
@ -535,13 +540,14 @@ public class XmlParser extends BaseParser implements IParser {
BaseNarrativeDt<?> narr2 = null;
if (gen != null && narr1.isEmpty()) {
// TODO: need to implement this
gen.generateNarrative(theResDef.getResourceProfile(), theResource, null);
String resourceProfile = myContext.getResourceDefinition(theResource).getResourceProfile();
gen.generateNarrative(resourceProfile, theResource, null);
}
if (narr2 != null) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
String childName = nextChild.getChildNameByDatatype(child.getDatatype());
BaseRuntimeElementDefinition<?> type = child.getChildByName(childName);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, narr2, childName, type, null, theIncludedResource);
encodeChildElementToStreamWriter(theResource, theEventWriter, narr2, childName, type, null, theIncludedResource);
continue;
}
}
@ -564,10 +570,10 @@ public class XmlParser extends BaseParser implements IParser {
super.throwExceptionForUnknownChildType(nextChild, type);
}
if (nextValue instanceof ExtensionDt) {
extensionUrl = ((ExtensionDt) nextValue).getUrlAsString();
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource);
if (nextValue instanceof IBaseExtension && myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
// This is called for the Query resource in DSTU1 only
extensionUrl = ((IBaseExtension<?>) nextValue).getUrl();
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource);
} else if (extensionUrl != null && childName.equals("extension") == false) {
RuntimeChildDeclaredExtensionDefinition extDef = (RuntimeChildDeclaredExtensionDefinition) nextChild;
@ -578,29 +584,48 @@ public class XmlParser extends BaseParser implements IParser {
}
theEventWriter.writeAttribute("url", extensionUrl);
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childName, childDef, null, theIncludedResource);
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, null, theIncludedResource);
theEventWriter.writeEndElement();
} else if (nextChild instanceof RuntimeChildNarrativeDefinition && theIncludedResource) {
// suppress narratives from contained resources
} else {
encodeChildElementToStreamWriter(theResDef, theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource);
encodeChildElementToStreamWriter(theResource, theEventWriter, nextValue, childName, childDef, extensionUrl, theIncludedResource);
}
}
}
}
private void encodeCompositeElementToStreamWriter(RuntimeResourceDefinition theResDef, IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> resDef, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getChildren(), theIncludedResource);
private void encodeCompositeElementToStreamWriter(IBaseResource theResource, IBase theElement, XMLStreamWriter theEventWriter, BaseRuntimeElementCompositeDefinition<?> theElementDefinition, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getExtensions(), theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, theElementDefinition.getChildren(), theIncludedResource);
}
private void encodeExtensionsIfPresent(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
private void encodeExtensionsIfPresent(IBaseResource theResource, XMLStreamWriter theWriter, IBase theElement, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
if (theElement instanceof ISupportsUndeclaredExtensions) {
ISupportsUndeclaredExtensions res = (ISupportsUndeclaredExtensions) theElement;
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredExtensions(), "extension", theIncludedResource);
encodeUndeclaredExtensions(theResDef, theResource, theWriter, res.getUndeclaredModifierExtensions(), "modifierExtension", theIncludedResource);
encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredExtensions()), "extension", theIncludedResource);
encodeUndeclaredExtensions(theResource, theWriter, toBaseExtensionList(res.getUndeclaredModifierExtensions()), "modifierExtension", theIncludedResource);
}
if (theElement instanceof IBaseHasExtensions) {
IBaseHasExtensions res = (IBaseHasExtensions) theElement;
encodeUndeclaredExtensions(theResource, theWriter, res.getExtension(), "extension", theIncludedResource);
}
if (theElement instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions res = (IBaseHasModifierExtensions) theElement;
encodeUndeclaredExtensions(theResource, theWriter, res.getModifierExtension(), "modifierExtension", theIncludedResource);
}
}
/**
* This is just to work around the fact that casting java.util.List<ca.uhn.fhir.model.api.ExtensionDt> to
* java.util.List<? extends org.hl7.fhir.instance.model.api.IBaseExtension<?>> seems to be rejected by the compiler
* some of the time.
*/
private <Q extends IBaseExtension<?>> List<IBaseExtension<?>> toBaseExtensionList(final List<Q> theList) {
List<IBaseExtension<?>> retVal = new ArrayList<IBaseExtension<?>>(theList.size());
retVal.addAll(theList);
return retVal;
}
private void encodeResourceReferenceToStreamWriter(XMLStreamWriter theEventWriter, BaseResourceReferenceDt theRef) throws XMLStreamException {
@ -636,12 +661,12 @@ public class XmlParser extends BaseParser implements IParser {
postExtensionChildren.add(next);
}
}
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, preExtensionChildren, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, preExtensionChildren, theIncludedResource);
encodeExtensionsIfPresent(theResDef, theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
encodeExtensionsIfPresent(theResource, theEventWriter, theElement, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, resDef.getExtensions(), theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResDef, theResource, theElement, theEventWriter, postExtensionChildren, theIncludedResource);
encodeCompositeElementChildrenToStreamWriter(theResource, theElement, theEventWriter, postExtensionChildren, theIncludedResource);
}
@ -701,54 +726,70 @@ public class XmlParser extends BaseParser implements IParser {
theEventWriter.writeStartElement(resDef.getName());
theEventWriter.writeDefaultNamespace(FHIR_NS);
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
if (theResource instanceof IAnyResource) {
// DSTU2+
IResource resource = (IResource) theResource;
writeOptionalTagWithValue(theEventWriter, "id", theResourceId);
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
if (resourceId != null && isNotBlank(resourceId.getVersionIdPart()) || (updated != null && !updated.isEmpty())) {
theEventWriter.writeStartElement("meta");
String versionIdPart = resourceId.getVersionIdPart();
if (isBlank(versionIdPart)) {
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
}
writeOptionalTagWithValue(theEventWriter, "versionId", versionIdPart);
if (updated != null) {
writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString());
}
theEventWriter.writeEndElement();
}
// HL7.org Structures
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource);
} else {
// DSTU1
if (theResourceId != null && theContainedResource) {
theEventWriter.writeAttribute("id", theResourceId);
}
}
if (theResource instanceof BaseBinary) {
BaseBinary bin = (BaseBinary) theResource;
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
writeOptionalTagWithValue(theEventWriter, "contentType", bin.getContentType());
writeOptionalTagWithValue(theEventWriter, "content", bin.getContentAsBase64());
} else {
if (bin.getContentType() != null) {
theEventWriter.writeAttribute("contentType", bin.getContentType());
}
theEventWriter.writeCharacters(bin.getContentAsBase64());
}
} else {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU1)) {
// DSTU2+
encodeResourceToStreamWriterInDstu2Format(resDef, theResource, theResource, theEventWriter, resDef, theContainedResource);
IResource resource = (IResource) theResource;
writeOptionalTagWithValue(theEventWriter, "id", theResourceId);
InstantDt updated = (InstantDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
IdDt resourceId = resource.getId();
List<BaseCodingDt> securityLabels = ResourceMetadataKeyEnum.SECURITY_LABELS.get(resource);
if (securityLabels == null) {
securityLabels = Collections.emptyList();
}
if ((resourceId != null && isNotBlank(resourceId.getVersionIdPart())) || (updated != null && !updated.isEmpty()) || !securityLabels.isEmpty()) {
theEventWriter.writeStartElement("meta");
String versionIdPart = resourceId.getVersionIdPart();
if (isBlank(versionIdPart)) {
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
}
writeOptionalTagWithValue(theEventWriter, "versionId", versionIdPart);
if (updated != null) {
writeOptionalTagWithValue(theEventWriter, "lastUpdated", updated.getValueAsString());
}
for (BaseCodingDt securityLabel : securityLabels) {
theEventWriter.writeStartElement("security");
BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(securityLabel.getClass());
encodeCompositeElementChildrenToStreamWriter(resource, securityLabel, theEventWriter, def.getChildren(), theContainedResource);
theEventWriter.writeEndElement();
}
theEventWriter.writeEndElement();
}
if (theResource instanceof BaseBinary) {
BaseBinary bin = (BaseBinary) theResource;
writeOptionalTagWithValue(theEventWriter, "contentType", bin.getContentType());
writeOptionalTagWithValue(theEventWriter, "content", bin.getContentAsBase64());
} else {
encodeResourceToStreamWriterInDstu2Format(resDef, theResource, theResource, theEventWriter, resDef, theContainedResource);
}
} else {
// DSTU1
encodeCompositeElementToStreamWriter(resDef, theResource, theResource, theEventWriter, resDef, theContainedResource);
if (theResourceId != null && theContainedResource) {
theEventWriter.writeAttribute("id", theResourceId);
}
if (theResource instanceof BaseBinary) {
BaseBinary bin = (BaseBinary) theResource;
if (bin.getContentType() != null) {
theEventWriter.writeAttribute("contentType", bin.getContentType());
}
theEventWriter.writeCharacters(bin.getContentAsBase64());
} else {
encodeCompositeElementToStreamWriter(theResource, theResource, theEventWriter, resDef, theContainedResource);
}
}
}
@ -787,24 +828,19 @@ public class XmlParser extends BaseParser implements IParser {
}
}
private void encodeUndeclaredExtensions(RuntimeResourceDefinition theResDef, IBaseResource theResource, XMLStreamWriter theWriter, List<ExtensionDt> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
for (ExtensionDt next : theExtensions) {
private void encodeUndeclaredExtensions(IBaseResource theResource, XMLStreamWriter theWriter, List<? extends IBaseExtension<?>> theExtensions, String tagName, boolean theIncludedResource) throws XMLStreamException, DataFormatException {
for (IBaseExtension<?> next : theExtensions) {
if (next == null) {
continue;
}
theWriter.writeStartElement(tagName);
theWriter.writeAttribute("url", next.getUrl().getValue());
String url = next.getUrl();
theWriter.writeAttribute("url", url);
if (next.getValue() != null) {
IElement value = next.getValue();
// RuntimeChildUndeclaredExtensionDefinition extDef =
// myContext.getRuntimeChildUndeclaredExtensionDefinition();
// String childName = extDef.getChildNameByDatatype(nextValue.getClass());
// if (childName == null) {
// throw new ConfigurationException("Unable to encode extension, unregognized child element type: " +
// nextValue.getClass().getCanonicalName());
// }
// BaseRuntimeElementDefinition<?> childDef =
// extDef.getChildElementDefinitionByDatatype(nextValue.getClass());
//
//
IBaseDatatype value = next.getValue();
RuntimeChildUndeclaredExtensionDefinition extDef = myContext.getRuntimeChildUndeclaredExtensionDefinition();
String childName = extDef.getChildNameByDatatype(value.getClass());
BaseRuntimeElementDefinition<?> childDef;
@ -818,11 +854,11 @@ public class XmlParser extends BaseParser implements IParser {
} else {
childDef = extDef.getChildElementDefinitionByDatatype(value.getClass());
}
encodeChildElementToStreamWriter(theResDef, theResource, theWriter, value, childName, childDef, null, theIncludedResource);
encodeChildElementToStreamWriter(theResource, theWriter, value, childName, childDef, null, theIncludedResource);
}
// child extensions
encodeExtensionsIfPresent(theResDef, theResource, theWriter, next, theIncludedResource);
encodeExtensionsIfPresent(theResource, theWriter, next, theIncludedResource);
theWriter.writeEndElement();
}

View File

@ -0,0 +1,32 @@
package ca.uhn.fhir.rest.annotation;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ConditionalOperationParam {
// just a marker
}

View File

@ -131,6 +131,10 @@ public class MethodOutcome {
return myVersionId;
}
/**
* This will be set to {@link Boolean#TRUE} for instance of MethodOutcome which are
* returned to client instances, if the server has responded with an HTTP 201 Created.
*/
public Boolean getCreated() {
return myCreated;
}
@ -146,8 +150,9 @@ public class MethodOutcome {
* If not null, indicates whether the resource was created (as opposed to being updated). This is generally not needed, since the server can assume based on the method being called
* whether the result was a creation or an update. However, it can be useful if you are implementing an update method that does a create if the ID doesn't already exist.
*/
public void setCreated(Boolean theCreated) {
public MethodOutcome setCreated(Boolean theCreated) {
myCreated = theCreated;
return this;
}
/**

View File

@ -182,9 +182,14 @@ public abstract class BaseClient {
}
try {
ContentType ct = ContentType.get(response.getEntity());
String mimeType = ct != null ? ct.getMimeType() : null;
String mimeType;
if (Constants.STATUS_HTTP_204_NO_CONTENT == response.getStatusLine().getStatusCode()) {
mimeType = null;
} else {
ContentType ct = ContentType.get(response.getEntity());
mimeType = ct != null ? ct.getMimeType() : null;
}
Map<String, List<String>> headers = new HashMap<String, List<String>>();
if (response.getAllHeaders() != null) {
for (Header next : response.getAllHeaders()) {
@ -398,7 +403,9 @@ public abstract class BaseClient {
charset = ct.getCharset();
}
if (charset == null) {
ourLog.warn("Response did not specify a charset.");
if (Constants.STATUS_HTTP_204_NO_CONTENT != theResponse.getStatusLine().getStatusCode()) {
ourLog.warn("Response did not specify a charset.");
}
charset = Charset.forName("UTF-8");
}

View File

@ -59,6 +59,9 @@ public abstract class BaseHttpClientInvocation {
public abstract HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding);
protected static void appendExtraParamsWithQuestionMark(Map<String, List<String>> theExtraParams, StringBuilder theUrlBuilder, boolean theWithQuestionMark) {
if (theExtraParams == null) {
return;
}
boolean first = theWithQuestionMark;
if (theExtraParams != null && theExtraParams.isEmpty() == false) {

View File

@ -56,10 +56,14 @@ import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.gclient.IClientExecutable;
import ca.uhn.fhir.rest.gclient.ICreate;
import ca.uhn.fhir.rest.gclient.ICreateTyped;
import ca.uhn.fhir.rest.gclient.ICreateWithQuery;
import ca.uhn.fhir.rest.gclient.ICreateWithQueryTyped;
import ca.uhn.fhir.rest.gclient.ICriterion;
import ca.uhn.fhir.rest.gclient.ICriterionInternal;
import ca.uhn.fhir.rest.gclient.IDelete;
import ca.uhn.fhir.rest.gclient.IDeleteTyped;
import ca.uhn.fhir.rest.gclient.IDeleteWithQuery;
import ca.uhn.fhir.rest.gclient.IDeleteWithQueryTyped;
import ca.uhn.fhir.rest.gclient.IGetPage;
import ca.uhn.fhir.rest.gclient.IGetPageTyped;
import ca.uhn.fhir.rest.gclient.IGetTags;
@ -76,6 +80,8 @@ import ca.uhn.fhir.rest.gclient.IUntypedQuery;
import ca.uhn.fhir.rest.gclient.IUpdate;
import ca.uhn.fhir.rest.gclient.IUpdateExecutable;
import ca.uhn.fhir.rest.gclient.IUpdateTyped;
import ca.uhn.fhir.rest.gclient.IUpdateWithQuery;
import ca.uhn.fhir.rest.gclient.IUpdateWithQueryTyped;
import ca.uhn.fhir.rest.method.DeleteMethodBinding;
import ca.uhn.fhir.rest.method.HistoryMethodBinding;
import ca.uhn.fhir.rest.method.HttpDeleteClientInvocation;
@ -237,10 +243,10 @@ public class GenericClient extends BaseClient implements IGenericClient {
return new LoadPageInternal();
}
// @Override
// public <T extends IBaseResource> T read(final Class<T> theType, IdDt theId) {
// return doReadOrVRead(theType, theId, false, null, null);
// }
// @Override
// public <T extends IBaseResource> T read(final Class<T> theType, IdDt theId) {
// return doReadOrVRead(theType, theId, false, null, null);
// }
@Override
public <T extends IBaseResource> T read(Class<T> theType, String theId) {
@ -249,7 +255,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public <T extends IBaseResource> T read(final Class<T> theType, UriDt theUrl) {
IdDt id = theUrl instanceof IdDt ? ((IdDt)theUrl) : new IdDt(theUrl);
IdDt id = theUrl instanceof IdDt ? ((IdDt) theUrl) : new IdDt(theUrl);
return doReadOrVRead(theType, id, false, null, null);
}
@ -447,7 +453,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
if (theIfVersionMatches != null) {
invocation.addHeader(Constants.HEADER_IF_NONE_MATCH, '"' + theIfVersionMatches + '"');
}
ResourceResponseHandler<T> binding = new ResourceResponseHandler<T>(theType, id);
if (theNotModifiedHandler == null) {
@ -475,18 +481,18 @@ public class GenericClient extends BaseClient implements IGenericClient {
return vread(theType, resId);
}
private static void addParam(Map<String, List<String>> params, String parameterName, String parameterValue) {
if (!params.containsKey(parameterName)) {
params.put(parameterName, new ArrayList<String>());
}
params.get(parameterName).add(parameterValue);
}
private abstract class BaseClientExecutable<T extends IClientExecutable<?, ?>, Y> implements IClientExecutable<T, Y> {
private EncodingEnum myParamEncoding;
private Boolean myPrettyPrint;
private boolean myQueryLogRequestAndResponse;
protected void addParam(Map<String, List<String>> params, String parameterName, String parameterValue) {
if (!params.containsKey(parameterName)) {
params.put(parameterName, new ArrayList<String>());
}
params.get(parameterName).add(parameterValue);
}
@SuppressWarnings("unchecked")
@Override
public T andLogRequestAndResponse(boolean theLogRequestAndResponse) {
@ -575,11 +581,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
private class CreateInternal extends BaseClientExecutable<ICreateTyped, MethodOutcome> implements ICreate, ICreateTyped {
private class CreateInternal extends BaseClientExecutable<ICreateTyped, MethodOutcome> implements ICreate, ICreateTyped, ICreateWithQuery, ICreateWithQueryTyped {
private String myId;
private IResource myResource;
private String myResourceBody;
private String mySearchUrl;
private CriterionList myCriterionList;
@Override
public MethodOutcome execute() {
@ -593,7 +601,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
myResourceBody = null;
}
BaseHttpClientInvocation invocation = MethodUtil.createCreateInvocation(myResource, myResourceBody, myId, myContext);
BaseHttpClientInvocation invocation;
if (mySearchUrl != null) {
invocation = MethodUtil.createCreateInvocation(myResource, myResourceBody, myId, myContext, mySearchUrl);
} else if (myCriterionList != null) {
invocation = MethodUtil.createCreateInvocation(myResource, myResourceBody, myId, myContext, myCriterionList.toParamList());
} else {
invocation = MethodUtil.createCreateInvocation(myResource, myResourceBody, myId, myContext);
}
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
final String resourceName = def.getName();
@ -631,15 +646,50 @@ public class GenericClient extends BaseClient implements IGenericClient {
return this;
}
@Override
public ICreateTyped conditionalByUrl(String theSearchUrl) {
mySearchUrl = theSearchUrl;
return this;
}
@Override
public ICreateWithQuery conditional() {
myCriterionList = new CriterionList();
return this;
}
@Override
public ICreateWithQueryTyped where(ICriterion<?> theCriterion) {
myCriterionList.add((ICriterionInternal) theCriterion);
return this;
}
@Override
public ICreateWithQueryTyped and(ICriterion<?> theCriterion) {
myCriterionList.add((ICriterionInternal) theCriterion);
return this;
}
}
private class DeleteInternal extends BaseClientExecutable<IDeleteTyped, BaseOperationOutcome> implements IDelete, IDeleteTyped {
private class DeleteInternal extends BaseClientExecutable<IDeleteTyped, BaseOperationOutcome> implements IDelete, IDeleteTyped, IDeleteWithQuery, IDeleteWithQueryTyped {
private IdDt myId;
private String mySearchUrl;
private String myResourceType;
private CriterionList myCriterionList;
@Override
public BaseOperationOutcome execute() {
HttpDeleteClientInvocation invocation = DeleteMethodBinding.createDeleteInvocation(myId);
HttpDeleteClientInvocation invocation;
if (myId != null) {
invocation = DeleteMethodBinding.createDeleteInvocation(myId);
} else if (myCriterionList != null) {
Map<String, List<String>> params = myCriterionList.toParamList();
invocation = DeleteMethodBinding.createDeleteInvocation(myResourceType, params);
} else {
invocation = DeleteMethodBinding.createDeleteInvocation(mySearchUrl);
}
OperationOutcomeResponseHandler binding = new OperationOutcomeResponseHandler();
Map<String, List<String>> params = new HashMap<String, List<String>>();
return invoke(params, binding, invocation);
@ -680,6 +730,56 @@ public class GenericClient extends BaseClient implements IGenericClient {
myId = new IdDt(theResourceType, theLogicalId);
return this;
}
@Override
public IDeleteTyped resourceConditionalByUrl(String theSearchUrl) {
Validate.notBlank(theSearchUrl, "theSearchUrl can not be blank/null");
mySearchUrl = theSearchUrl;
return this;
}
@Override
public IDeleteWithQuery resourceConditionalByType(String theResourceType) {
Validate.notBlank(theResourceType, "theResourceType can not be blank/null");
if (myContext.getResourceDefinition(theResourceType) == null) {
throw new IllegalArgumentException("Unknown resource type: " + theResourceType);
}
myResourceType = theResourceType;
myCriterionList = new CriterionList();
return this;
}
@Override
public IDeleteWithQueryTyped where(ICriterion<?> theCriterion) {
myCriterionList.add((ICriterionInternal) theCriterion);
return this;
}
@Override
public IDeleteWithQueryTyped and(ICriterion<?> theCriterion) {
myCriterionList.add((ICriterionInternal) theCriterion);
return this;
}
}
private static class CriterionList extends ArrayList<ICriterionInternal> {
private static final long serialVersionUID = 1L;
public void populateParamList(Map<String, List<String>> theParams) {
for (ICriterionInternal next : this) {
String parameterName = next.getParameterName();
String parameterValue = next.getParameterValue();
addParam(theParams, parameterName, parameterValue);
}
}
public Map<String, List<String>> toParamList() {
LinkedHashMap<String, List<String>> retVal = new LinkedHashMap<String, List<String>>();
populateParamList(retVal);
return retVal;
}
}
private class GetPageInternal extends BaseClientExecutable<IGetPageTyped, Bundle> implements IGetPageTyped {
@ -996,7 +1096,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
private class SearchInternal extends BaseClientExecutable<IQuery, Bundle> implements IQuery, IUntypedQuery {
private String myCompartmentName;
private List<ICriterionInternal> myCriterion = new ArrayList<ICriterionInternal>();
private CriterionList myCriterion = new CriterionList();
private List<Include> myInclude = new ArrayList<Include>();
private Integer myParamLimit;
private String myResourceId;
@ -1025,11 +1125,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
// params.putAll(initial);
// }
for (ICriterionInternal next : myCriterion) {
String parameterName = next.getParameterName();
String parameterValue = next.getParameterValue();
addParam(params, parameterName, parameterValue);
}
myCriterion.populateParamList(params);
for (Include next : myInclude) {
addParam(params, Constants.PARAM_INCLUDE, next.getValue());
@ -1224,30 +1320,39 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
private class UpdateInternal extends BaseClientExecutable<IUpdateExecutable, MethodOutcome> implements IUpdate, IUpdateTyped, IUpdateExecutable {
private class UpdateInternal extends BaseClientExecutable<IUpdateExecutable, MethodOutcome> implements IUpdate, IUpdateTyped, IUpdateExecutable, IUpdateWithQuery, IUpdateWithQueryTyped {
private IdDt myId;
private IResource myResource;
private String myResourceBody;
private String mySearchUrl;
private CriterionList myCriterionList;
@Override
public MethodOutcome execute() {
if (myResource == null) {
myResource = parseResourceBody(myResourceBody);
}
if (myId == null) {
myId = myResource.getId();
}
if (myId == null || myId.hasIdPart() == false) {
throw new InvalidRequestException("No ID supplied for resource to update, can not invoke server");
}
// If an explicit encoding is chosen, we will re-serialize to ensure the right encoding
if (getParamEncoding() != null) {
myResourceBody = null;
}
BaseHttpClientInvocation invocation = MethodUtil.createUpdateInvocation(myResource, myResourceBody, myId, myContext);
BaseHttpClientInvocation invocation;
if (mySearchUrl != null) {
invocation = MethodUtil.createUpdateInvocation(myContext, myResource, myResourceBody, mySearchUrl);
} else if (myCriterionList != null) {
invocation = MethodUtil.createUpdateInvocation(myContext, myResource, myResourceBody, myCriterionList.toParamList());
} else {
if (myId == null) {
myId = myResource.getId();
}
if (myId == null || myId.hasIdPart() == false) {
throw new InvalidRequestException("No ID supplied for resource to update, can not invoke server");
}
invocation = MethodUtil.createUpdateInvocation(myResource, myResourceBody, myId, myContext);
}
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
final String resourceName = def.getName();
@ -1297,6 +1402,30 @@ public class GenericClient extends BaseClient implements IGenericClient {
return this;
}
@Override
public IUpdateTyped conditionalByUrl(String theSearchUrl) {
mySearchUrl = theSearchUrl;
return this;
}
@Override
public IUpdateWithQuery conditional() {
myCriterionList = new CriterionList();
return this;
}
@Override
public IUpdateWithQueryTyped where(ICriterion<?> theCriterion) {
myCriterionList.add((ICriterionInternal) theCriterion);
return this;
}
@Override
public IUpdateWithQueryTyped and(ICriterion<?> theCriterion) {
myCriterionList.add((ICriterionInternal) theCriterion);
return this;
}
}
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IBaseQuery<T> {
T where(ICriterion<?> theCriterion);
T and(ICriterion<?> theCriterion);
}

View File

@ -37,4 +37,19 @@ public interface ICreateTyped extends IClientExecutable<ICreateTyped, MethodOutc
*/
ICreateTyped withId(IdDt theId);
/**
* Specifies that the create should be performed as a conditional create
* against a given search URL.
*
* @param theSearchUrl The search URL to use. The format of this URL should be of the form <code>[ResourceType]?[Parameters]</code>,
* for example: <code>Patient?name=Smith&amp;identifier=13.2.4.11.4%7C847366</code>
* @since HAPI 0.9 / FHIR DSTU 2
*/
ICreateTyped conditionalByUrl(String theSearchUrl);
/**
* @since HAPI 0.9 / FHIR DSTU 2
*/
ICreateWithQuery conditional();
}

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface ICreateWithQuery extends IBaseQuery<ICreateWithQueryTyped> {
}

View File

@ -0,0 +1,25 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface ICreateWithQueryTyped extends ICreateTyped, ICreateWithQuery {
}

View File

@ -30,5 +30,20 @@ public interface IDelete {
IDeleteTyped resourceById(IdDt theId);
IDeleteTyped resourceById(String theResourceType, String theLogicalId);
/**
* Specifies that the delete should be performed as a conditional delete
* against a given search URL.
*
* @param theSearchUrl The search URL to use. The format of this URL should be of the form <code>[ResourceType]?[Parameters]</code>,
* for example: <code>Patient?name=Smith&amp;identifier=13.2.4.11.4%7C847366</code>
* @since HAPI 0.9 / FHIR DSTU 2
*/
IDeleteTyped resourceConditionalByUrl(String theSearchUrl);
/**
* @since HAPI 0.9 / FHIR DSTU 2
*/
IDeleteWithQuery resourceConditionalByType(String theResourceType);
}

View File

@ -0,0 +1,25 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IDeleteWithQuery extends IBaseQuery<IDeleteWithQueryTyped> {
}

View File

@ -0,0 +1,25 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IDeleteWithQueryTyped extends IDeleteTyped, IDeleteWithQuery {
}

View File

@ -24,11 +24,7 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.method.SearchStyleEnum;
public interface IQuery extends IClientExecutable<IQuery,Bundle> {
IQuery where(ICriterion<?> theCriterion);
IQuery and(ICriterion<?> theCriterion);
public interface IQuery extends IClientExecutable<IQuery, Bundle>, IBaseQuery<IQuery> {
IQuery include(Include theIncludeManagingorganization);

View File

@ -28,4 +28,19 @@ public interface IUpdateTyped extends IUpdateExecutable {
IUpdateExecutable withId(String theId);
/**
* Specifies that the update should be performed as a conditional create
* against a given search URL.
*
* @param theSearchUrl The search URL to use. The format of this URL should be of the form <code>[ResourceType]?[Parameters]</code>,
* for example: <code>Patient?name=Smith&amp;identifier=13.2.4.11.4%7C847366</code>
* @since HAPI 0.9 / FHIR DSTU 2
*/
IUpdateTyped conditionalByUrl(String theSearchUrl);
/**
* @since HAPI 0.9 / FHIR DSTU 2
*/
IUpdateWithQuery conditional();
}

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IUpdateWithQuery extends IBaseQuery<IUpdateWithQueryTyped> {
}

View File

@ -0,0 +1,25 @@
package ca.uhn.fhir.rest.gclient;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IUpdateWithQueryTyped extends IUpdateTyped, IUpdateWithQuery {
}

View File

@ -143,29 +143,55 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
myBundleType = null;
}
public BaseHttpClientInvocationWithContents(FhirContext theContext, String theContents, Map<String, List<String>> theParams, String... theUrlPath) {
myContext = theContext;
myResource = null;
myTagList = null;
myUrlPath = StringUtils.join(theUrlPath, '/');
myResources = null;
myBundle = null;
myContents = theContents;
myContentsIsBundle = false;
myParams = theParams;
myBundleType = null;
}
public BaseHttpClientInvocationWithContents(FhirContext theContext, IResource theResource, Map<String, List<String>> theParams, String... theUrlPath) {
myContext = theContext;
myResource = theResource;
myTagList = null;
myUrlPath = StringUtils.join(theUrlPath, '/');
myResources = null;
myBundle = null;
myContents = null;
myContentsIsBundle = false;
myParams = theParams;
myBundleType = null;
}
@Override
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) throws DataFormatException {
StringBuilder b = new StringBuilder();
StringBuilder url = new StringBuilder();
if (myUrlPath == null) {
b.append(theUrlBase);
url.append(theUrlBase);
} else {
if (!myUrlPath.contains("://")) {
b.append(theUrlBase);
url.append(theUrlBase);
if (!theUrlBase.endsWith("/")) {
b.append('/');
url.append('/');
}
}
b.append(myUrlPath);
url.append(myUrlPath);
}
appendExtraParamsWithQuestionMark(theExtraParams, b, b.indexOf("?") == -1);
String url = b.toString();
appendExtraParamsWithQuestionMark(theExtraParams, url, url.indexOf("?") == -1);
if (myResource != null && BaseBinary.class.isAssignableFrom(myResource.getClass())) {
BaseBinary binary = (BaseBinary) myResource;
ByteArrayEntity entity = new ByteArrayEntity(binary.getContent(), ContentType.parse(binary.getContentType()));
HttpRequestBase retVal = createRequest(url, entity);
addMatchHeaders(retVal, url);
return retVal;
}
@ -177,7 +203,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
if (myContents != null) {
encoding = MethodUtil.detectEncoding(myContents);
}
if (encoding == EncodingEnum.JSON) {
parser = myContext.newJsonParser();
} else {
@ -187,12 +213,12 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
AbstractHttpEntity entity;
if (myParams != null) {
contentType= null;
contentType = null;
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
for (Entry<String, List<String>> nextParam : myParams.entrySet()) {
List<String> value = nextParam.getValue();
for(String s: value){
parameters.add(new BasicNameValuePair(nextParam.getKey(), s));
for (String s : value) {
parameters.add(new BasicNameValuePair(nextParam.getKey(), s));
}
}
try {
@ -228,6 +254,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
HttpRequestBase retVal = createRequest(url, entity);
super.addHeadersToRequest(retVal);
addMatchHeaders(retVal, url);
if (contentType != null) {
retVal.addHeader(Constants.HEADER_CONTENT_TYPE, contentType + Constants.HEADER_SUFFIX_CT_UTF_8);
@ -236,6 +263,41 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
return retVal;
}
protected abstract HttpRequestBase createRequest(String url, AbstractHttpEntity theEntity);
private void addMatchHeaders(HttpRequestBase theHttpRequest, StringBuilder theUrlBase) {
if (myIfNoneExistParams != null) {
StringBuilder b = newHeaderBuilder(theUrlBase);
appendExtraParamsWithQuestionMark(myIfNoneExistParams, b, b.indexOf("?") == -1);
theHttpRequest.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
if (myIfNoneExistString != null) {
StringBuilder b = newHeaderBuilder(theUrlBase);
b.append(b.indexOf("?") == -1 ? '?' : '&');
b.append(myIfNoneExistString.substring(myIfNoneExistString.indexOf('?') + 1));
theHttpRequest.addHeader(Constants.HEADER_IF_NONE_EXIST, b.toString());
}
}
private StringBuilder newHeaderBuilder(StringBuilder theUrlBase) {
StringBuilder b = new StringBuilder();
b.append(theUrlBase);
if (theUrlBase.length() > 0 && theUrlBase.charAt(theUrlBase.length() - 1) == '/') {
b.deleteCharAt(b.length() - 1);
}
return b;
}
protected abstract HttpRequestBase createRequest(StringBuilder theUrl, AbstractHttpEntity theEntity);
private Map<String, List<String>> myIfNoneExistParams;
private String myIfNoneExistString;
public void setIfNoneExistParams(Map<String, List<String>> theIfNoneExist) {
myIfNoneExistParams = theIfNoneExist;
}
public void setIfNoneExistString(String theIfNoneExistString) {
myIfNoneExistString = theIfNoneExistString;
}
}

View File

@ -26,15 +26,12 @@ import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import ca.uhn.fhir.rest.annotation.*;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.IBaseResource;
@ -47,6 +44,18 @@ import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.AddTags;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.DeleteTags;
import ca.uhn.fhir.rest.annotation.GetTags;
import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
@ -61,9 +70,9 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionNotSpecifiedException;
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.ReflectionUtil;
@ -217,7 +226,7 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
ex = new ResourceVersionConflictException("Server responded with HTTP 409");
break;
case Constants.STATUS_HTTP_412_PRECONDITION_FAILED:
ex = new ResourceVersionNotSpecifiedException("Server responded with HTTP 412");
ex = new PreconditionFailedException("Server responded with HTTP 412");
break;
case Constants.STATUS_HTTP_422_UNPROCESSABLE_ENTITY:
IParser parser = createAppropriateParserForParsingResponse(theResponseMimeType, theResponseReader, theStatusCode);

View File

@ -273,11 +273,16 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
BufferedReader requestReader = theRequest.getServletRequest().getReader();
Class<? extends IBaseResource> wantedResourceType = requestContainsResourceType();
IResource retVal;
if (wantedResourceType != null) {
return (IResource) parser.parseResource(wantedResourceType, requestReader);
retVal = (IResource) parser.parseResource(wantedResourceType, requestReader);
} else {
return parser.parseResource(requestReader);
retVal = parser.parseResource(requestReader);
}
retVal.setId(theRequest.getId());
return retVal;
}
protected abstract Set<RequestType> provideAllowableRequestTypes();

View File

@ -0,0 +1,57 @@
package ca.uhn.fhir.rest.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
class ConditionalParamBinder implements IParameter {
ConditionalParamBinder() {
super();
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments) throws InternalErrorException {
throw new UnsupportedOperationException();
}
@Override
public Object translateQueryParametersIntoServerArgument(Request theRequest, Object theRequestContents) throws InternalErrorException, InvalidRequestException {
if (theRequest.getId() != null && theRequest.getId().hasIdPart()) {
return null;
}
int questionMarkIndex = theRequest.getCompleteUrl().indexOf('?');
return theRequest.getResourceName() + theRequest.getCompleteUrl().substring(questionMarkIndex);
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// nothing
}
}

View File

@ -22,6 +22,8 @@ package ca.uhn.fhir.rest.method;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import ca.uhn.fhir.context.ConfigurationException;
@ -154,5 +156,14 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBinding {
return null;
}
public static HttpDeleteClientInvocation createDeleteInvocation(String theSearchUrl) {
HttpDeleteClientInvocation retVal = new HttpDeleteClientInvocation(theSearchUrl);
return retVal;
}
public static HttpDeleteClientInvocation createDeleteInvocation(String theResourceType, Map<String, List<String>> theParams) {
return new HttpDeleteClientInvocation(theResourceType, theParams);
}
}

View File

@ -33,12 +33,22 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
private String myUrlPath;
private Map<String, List<String>> myParams;
public HttpDeleteClientInvocation(IdDt theId) {
super();
myUrlPath = theId.toUnqualifiedVersionless().getValue();
}
public HttpDeleteClientInvocation(String theSearchUrl) {
myUrlPath = theSearchUrl;
}
public HttpDeleteClientInvocation(String theResourceType, Map<String, List<String>> theParams) {
myUrlPath = theResourceType;
myParams = theParams;
}
@Override
public HttpRequestBase asHttpRequest(String theUrlBase, Map<String, List<String>> theExtraParams, EncodingEnum theEncoding) {
StringBuilder b = new StringBuilder();
@ -48,12 +58,12 @@ public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
}
b.append(myUrlPath);
appendExtraParamsWithQuestionMark(theExtraParams, b,b.indexOf("?") == -1);
appendExtraParamsWithQuestionMark(myParams, b, b.indexOf("?") == -1);
appendExtraParamsWithQuestionMark(theExtraParams, b, b.indexOf("?") == -1);
HttpDelete retVal = new HttpDelete(b.toString());
super.addHeadersToRequest(retVal);
return retVal;
}
}

View File

@ -34,38 +34,34 @@ import ca.uhn.fhir.model.valueset.BundleTypeEnum;
public class HttpPostClientInvocation extends BaseHttpClientInvocationWithContents {
public HttpPostClientInvocation(FhirContext theContext, IResource theResource, String theUrlExtension) {
super(theContext, theResource, theUrlExtension);
}
public HttpPostClientInvocation(FhirContext theContext, TagList theTagList, String... theUrlExtension) {
super(theContext, theTagList, theUrlExtension);
}
public HttpPostClientInvocation(FhirContext theContext, List<IResource> theResources, BundleTypeEnum theBundleType) {
super(theContext, theResources, theBundleType);
}
public HttpPostClientInvocation(FhirContext theContext, Bundle theBundle) {
super(theContext,theBundle);
super(theContext, theBundle);
}
public HttpPostClientInvocation(FhirContext theContext, String theContents, boolean theIsBundle, String theUrlExtension) {
super(theContext,theContents, theIsBundle, theUrlExtension);
super(theContext, theContents, theIsBundle, theUrlExtension);
}
public HttpPostClientInvocation(FhirContext theContext, Map<String, List<String>> theParams, String... theUrlExtension) {
super(theContext, theParams, theUrlExtension);
}
@Override
protected HttpPost createRequest(String url, AbstractHttpEntity theEntity) {
HttpPost retVal = new HttpPost(url);
protected HttpPost createRequest(StringBuilder theUrlBase, AbstractHttpEntity theEntity) {
HttpPost retVal = new HttpPost(theUrlBase.toString());
retVal.setEntity(theEntity);
return retVal;
}

View File

@ -34,15 +34,14 @@ public class HttpPutClientInvocation extends BaseHttpClientInvocationWithContent
}
public HttpPutClientInvocation(FhirContext theContext, String theContents, boolean theIsBundle, String theUrlExtension) {
super(theContext,theContents, theIsBundle, theUrlExtension);
super(theContext, theContents, theIsBundle, theUrlExtension);
}
@Override
protected HttpRequestBase createRequest(String url, AbstractHttpEntity theEntity) {
HttpPut retVal = new HttpPut(url);
protected HttpRequestBase createRequest(StringBuilder theUrl, AbstractHttpEntity theEntity) {
HttpPut retVal = new HttpPut(theUrl.toString());
retVal.setEntity(theEntity);
return retVal;
}
}

View File

@ -5,14 +5,17 @@ import static org.apache.commons.lang3.StringUtils.*;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@ -44,6 +47,7 @@ import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.ConditionalOperationParam;
import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.IncludeParam;
@ -95,9 +99,65 @@ import ca.uhn.fhir.util.ReflectionUtil;
public class MethodUtil {
private static final String LABEL = "label=\"";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
private static final String SCHEME = "scheme=\"";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
static void addTagsToPostOrPut(IResource resource, BaseHttpClientInvocation retVal) {
TagList list = (TagList) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
if (list != null) {
for (Tag tag : list) {
if (StringUtils.isNotBlank(tag.getTerm())) {
retVal.addHeader(Constants.HEADER_CATEGORY, tag.toHeaderValue());
}
}
}
}
public static HttpGetClientInvocation createConformanceInvocation() {
return new HttpGetClientInvocation("metadata");
}
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, FhirContext theContext) {
return createCreateInvocation(theResource, null, null, theContext);
}
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, String theResourceBody, String theId, FhirContext theContext) {
RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
String resourceName = def.getName();
StringBuilder urlExtension = new StringBuilder();
urlExtension.append(resourceName);
if (StringUtils.isNotBlank(theId)) {
urlExtension.append('/');
urlExtension.append(theId);
}
HttpPostClientInvocation retVal;
if (StringUtils.isBlank(theResourceBody)) {
retVal = new HttpPostClientInvocation(theContext, theResource, urlExtension.toString());
} else {
retVal = new HttpPostClientInvocation(theContext, theResourceBody, false, urlExtension.toString());
}
addTagsToPostOrPut(theResource, retVal);
// addContentTypeHeaderBasedOnDetectedType(retVal, theResourceBody);
return retVal;
}
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, String theResourceBody, String theId, FhirContext theContext, Map<String, List<String>> theIfNoneExistParams) {
HttpPostClientInvocation retVal = createCreateInvocation(theResource, theResourceBody, theId, theContext);
retVal.setIfNoneExistParams(theIfNoneExistParams);
return retVal;
}
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, String theResourceBody, String theId, FhirContext theContext, String theIfNoneExistUrl) {
HttpPostClientInvocation retVal = createCreateInvocation(theResource, theResourceBody, theId, theContext);
retVal.setIfNoneExistString(theIfNoneExistUrl);
return retVal;
}
public static HttpPutClientInvocation createUpdateInvocation(IResource theResource, String theResourceBody, IdDt theId, FhirContext theContext) {
String resourceName = theContext.getResourceDefinition(theResource).getName();
@ -105,9 +165,9 @@ public class MethodUtil {
urlBuilder.append(resourceName);
urlBuilder.append('/');
urlBuilder.append(theId.getIdPart());
String urlExtension = urlBuilder.toString();
HttpPutClientInvocation retVal;
String urlExtension = urlBuilder.toString();
if (StringUtils.isBlank(theResourceBody)) {
retVal = new HttpPutClientInvocation(theContext, theResource, urlExtension);
} else {
@ -135,203 +195,49 @@ public class MethodUtil {
return retVal;
}
public static void parseClientRequestResourceHeaders(IdDt theRequestedId, Map<String, List<String>> theHeaders, IBaseResource resource) {
List<String> lmHeaders = theHeaders.get(Constants.HEADER_LAST_MODIFIED_LOWERCASE);
if (lmHeaders != null && lmHeaders.size() > 0 && StringUtils.isNotBlank(lmHeaders.get(0))) {
String headerValue = lmHeaders.get(0);
Date headerDateValue;
try {
headerDateValue = DateUtils.parseDate(headerValue);
if (resource instanceof IResource) {
InstantDt lmValue = new InstantDt(headerDateValue);
((IResource) resource).getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, lmValue);
} else if (resource instanceof IAnyResource) {
((IAnyResource) resource).getMeta().setLastUpdated(headerDateValue);
}
} catch (Exception e) {
ourLog.warn("Unable to parse date string '{}'. Error is: {}", headerValue, e.toString());
}
}
public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IResource theResource, String theResourceBody, Map<String, List<String>> theMatchParams) {
StringBuilder b = new StringBuilder();
List<String> clHeaders = theHeaders.get(Constants.HEADER_CONTENT_LOCATION_LC);
if (clHeaders != null && clHeaders.size() > 0 && StringUtils.isNotBlank(clHeaders.get(0))) {
String headerValue = clHeaders.get(0);
if (isNotBlank(headerValue)) {
new IdDt(headerValue).applyTo(resource);
}
}
String resourceType = theContext.getResourceDefinition(theResource).getName();
b.append(resourceType);
IdDt existing = IdDt.of(resource);
List<String> eTagHeaders = theHeaders.get(Constants.HEADER_ETAG_LC);
String eTagVersion = null;
if (eTagHeaders != null && eTagHeaders.size() > 0) {
eTagVersion = parseETagValue(eTagHeaders.get(0));
}
if (isNotBlank(eTagVersion)) {
if (existing == null || existing.isEmpty()) {
if (theRequestedId != null) {
theRequestedId.withVersion(eTagVersion).applyTo(resource);
}
} else if (existing.hasVersionIdPart() == false) {
existing.withVersion(eTagVersion).applyTo(resource);
}
} else if (existing == null || existing.isEmpty()) {
if (theRequestedId != null) {
theRequestedId.applyTo(resource);
}
}
List<String> categoryHeaders = theHeaders.get(Constants.HEADER_CATEGORY_LC);
if (categoryHeaders != null && categoryHeaders.size() > 0 && StringUtils.isNotBlank(categoryHeaders.get(0))) {
TagList tagList = new TagList();
for (String header : categoryHeaders) {
parseTagValue(tagList, header);
}
if (resource instanceof IResource) {
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) resource, tagList);
} else if (resource instanceof IAnyResource) {
IMetaType meta = ((IAnyResource) resource).getMeta();
for (Tag next : tagList) {
meta.addTag().setSystem(next.getScheme()).setCode(next.getTerm()).setDisplay(next.getLabel());
boolean haveQuestionMark = false;
for (Entry<String, List<String>> nextEntry : theMatchParams.entrySet()) {
for (String nextValue : nextEntry.getValue()) {
b.append(haveQuestionMark ? '&' : '?');
haveQuestionMark = true;
try {
b.append(URLEncoder.encode(nextEntry.getKey(), "UTF-8"));
b.append('=');
b.append(URLEncoder.encode(nextValue, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new ConfigurationException("UTF-8 not supported on this platform");
}
}
}
}
public static String parseETagValue(String value) {
String eTagVersion;
value = value.trim();
if (value.length() > 1) {
if (value.charAt(value.length() - 1) == '"') {
if (value.charAt(0) == '"') {
eTagVersion = value.substring(1, value.length() - 1);
} else if (value.length() > 3 && value.charAt(0) == 'W' && value.charAt(1) == '/' && value.charAt(2) == '"') {
eTagVersion = value.substring(3, value.length() - 1);
} else {
eTagVersion = value;
}
} else {
eTagVersion = value;
}
} else {
eTagVersion = value;
}
return eTagVersion;
}
public static void parseTagValue(TagList tagList, String nextTagComplete) {
StringBuilder next = new StringBuilder(nextTagComplete);
parseTagValue(tagList, nextTagComplete, next);
}
private static void parseTagValue(TagList theTagList, String theCompleteHeaderValue, StringBuilder theBuffer) {
int firstSemicolon = theBuffer.indexOf(";");
int deleteTo;
if (firstSemicolon == -1) {
firstSemicolon = theBuffer.indexOf(",");
if (firstSemicolon == -1) {
firstSemicolon = theBuffer.length();
deleteTo = theBuffer.length();
} else {
deleteTo = firstSemicolon;
}
} else {
deleteTo = firstSemicolon + 1;
}
String term = theBuffer.substring(0, firstSemicolon);
String scheme = null;
String label = null;
if (isBlank(term)) {
return;
}
theBuffer.delete(0, deleteTo);
while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') {
theBuffer.deleteCharAt(0);
}
while (theBuffer.length() > 0) {
boolean foundSomething = false;
if (theBuffer.length() > SCHEME.length() && theBuffer.substring(0, SCHEME.length()).equals(SCHEME)) {
int closeIdx = theBuffer.indexOf("\"", SCHEME.length());
scheme = theBuffer.substring(SCHEME.length(), closeIdx);
theBuffer.delete(0, closeIdx + 1);
foundSomething = true;
}
if (theBuffer.length() > LABEL.length() && theBuffer.substring(0, LABEL.length()).equals(LABEL)) {
int closeIdx = theBuffer.indexOf("\"", LABEL.length());
label = theBuffer.substring(LABEL.length(), closeIdx);
theBuffer.delete(0, closeIdx + 1);
foundSomething = true;
}
// TODO: support enc2231-string as described in
// http://tools.ietf.org/html/draft-johnston-http-category-header-02
// TODO: support multiple tags in one header as described in
// http://hl7.org/implement/standards/fhir/http.html#tags
while (theBuffer.length() > 0 && (theBuffer.charAt(0) == ' ' || theBuffer.charAt(0) == ';')) {
theBuffer.deleteCharAt(0);
}
if (!foundSomething) {
break;
}
}
if (theBuffer.length() > 0 && theBuffer.charAt(0) == ',') {
theBuffer.deleteCharAt(0);
while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') {
theBuffer.deleteCharAt(0);
}
theTagList.add(new Tag(scheme, term, label));
parseTagValue(theTagList, theCompleteHeaderValue, theBuffer);
} else {
theTagList.add(new Tag(scheme, term, label));
}
if (theBuffer.length() > 0) {
ourLog.warn("Ignoring extra text at the end of " + Constants.HEADER_CATEGORY + " tag '" + theBuffer.toString() + "' - Complete tag value was: " + theCompleteHeaderValue);
}
}
static void addTagsToPostOrPut(IResource resource, BaseHttpClientInvocation retVal) {
TagList list = (TagList) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST);
if (list != null) {
for (Tag tag : list) {
if (StringUtils.isNotBlank(tag.getTerm())) {
retVal.addHeader(Constants.HEADER_CATEGORY, tag.toHeaderValue());
}
}
}
}
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, FhirContext theContext) {
return createCreateInvocation(theResource, null, null, theContext);
}
public static HttpPostClientInvocation createCreateInvocation(IResource theResource, String theResourceBody, String theId, FhirContext theContext) {
RuntimeResourceDefinition def = theContext.getResourceDefinition(theResource);
String resourceName = def.getName();
StringBuilder urlExtension = new StringBuilder();
urlExtension.append(resourceName);
if (StringUtils.isNotBlank(theId)) {
urlExtension.append('/');
urlExtension.append(theId);
}
HttpPostClientInvocation retVal;
HttpPutClientInvocation retVal;
if (StringUtils.isBlank(theResourceBody)) {
retVal = new HttpPostClientInvocation(theContext, theResource, urlExtension.toString());
retVal = new HttpPutClientInvocation(theContext, theResource, b.toString());
} else {
retVal = new HttpPostClientInvocation(theContext, theResourceBody, false, urlExtension.toString());
retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, b.toString());
}
addTagsToPostOrPut(theResource, retVal);
// addContentTypeHeaderBasedOnDetectedType(retVal, theResourceBody);
return retVal;
}
public static HttpPutClientInvocation createUpdateInvocation(FhirContext theContext, IResource theResource, String theResourceBody, String theMatchUrl) {
HttpPutClientInvocation retVal;
if (StringUtils.isBlank(theResourceBody)) {
retVal = new HttpPutClientInvocation(theContext, theResource, theMatchUrl);
} else {
retVal = new HttpPutClientInvocation(theContext, theResourceBody, false, theMatchUrl);
}
addTagsToPostOrPut(theResource, retVal);
return retVal;
}
@ -339,66 +245,30 @@ public class MethodUtil {
public static EncodingEnum detectEncoding(String theBody) {
for (int i = 0; i < theBody.length(); i++) {
switch (theBody.charAt(i)) {
case '<':
return EncodingEnum.XML;
case '{':
return EncodingEnum.JSON;
case '<':
return EncodingEnum.XML;
case '{':
return EncodingEnum.JSON;
}
}
return EncodingEnum.XML;
}
public static HttpGetClientInvocation createConformanceInvocation() {
return new HttpGetClientInvocation("metadata");
}
public static MethodOutcome process2xxResponse(FhirContext theContext, String theResourceName, int theResponseStatusCode, String theResponseMimeType, Reader theResponseReader, Map<String, List<String>> theHeaders) {
List<String> locationHeaders = new ArrayList<String>();
List<String> lh = theHeaders.get(Constants.HEADER_LOCATION_LC);
if (lh != null) {
locationHeaders.addAll(lh);
}
List<String> clh = theHeaders.get(Constants.HEADER_CONTENT_LOCATION_LC);
if (clh != null) {
locationHeaders.addAll(clh);
}
MethodOutcome retVal = new MethodOutcome();
if (locationHeaders != null && locationHeaders.size() > 0) {
String locationHeader = locationHeaders.get(0);
BaseOutcomeReturningMethodBinding.parseContentLocation(retVal, theResourceName, locationHeader);
}
if (theResponseStatusCode != Constants.STATUS_HTTP_204_NO_CONTENT) {
EncodingEnum ct = EncodingEnum.forContentType(theResponseMimeType);
if (ct != null) {
PushbackReader reader = new PushbackReader(theResponseReader);
try {
int firstByte = reader.read();
if (firstByte == -1) {
BaseOutcomeReturningMethodBinding.ourLog.debug("No content in response, not going to read");
reader = null;
} else {
reader.unread(firstByte);
}
} catch (IOException e) {
BaseOutcomeReturningMethodBinding.ourLog.debug("No content in response, not going to read", e);
reader = null;
public static void extractDescription(SearchParameter theParameter, Annotation[] theAnnotations) {
for (Annotation annotation : theAnnotations) {
if (annotation instanceof Description) {
Description desc = (Description) annotation;
if (isNotBlank(desc.formalDefinition())) {
theParameter.setDescription(desc.formalDefinition());
} else {
theParameter.setDescription(desc.shortDefinition());
}
if (reader != null) {
IParser parser = ct.newParser(theContext);
IResource outcome = parser.parseResource(reader);
if (outcome instanceof BaseOperationOutcome) {
retVal.setOperationOutcome((BaseOperationOutcome) outcome);
}
}
} else {
BaseOutcomeReturningMethodBinding.ourLog.debug("Ignoring response content of type: {}", theResponseMimeType);
}
}
return retVal;
}
public static Integer findIdParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, IdParam.class);
}
public static Integer findParamAnnotationIndex(Method theMethod, Class<?> toFind) {
@ -416,38 +286,12 @@ public class MethodUtil {
return null;
}
public static void extractDescription(SearchParameter theParameter, Annotation[] theAnnotations) {
for (Annotation annotation : theAnnotations) {
if (annotation instanceof Description) {
Description desc = (Description) annotation;
if (isNotBlank(desc.formalDefinition())) {
theParameter.setDescription(desc.formalDefinition());
} else {
theParameter.setDescription(desc.shortDefinition());
}
}
}
public static Integer findTagListParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, TagListParam.class);
}
public static IQueryParameterOr<?> singleton(final IQueryParameterType theParam) {
return new IQueryParameterOr<IQueryParameterType>() {
@Override
public void setValuesAsQueryTokens(QualifiedParamList theParameters) {
if (theParameters.isEmpty()) {
return;
}
if (theParameters.size() > 1) {
throw new IllegalArgumentException("Type " + theParam.getClass().getCanonicalName() + " does not support multiple values");
}
theParam.setValueAsQueryToken(theParameters.getQualifier(), theParameters.get(0));
}
@Override
public List<IQueryParameterType> getValuesAsQueryTokens() {
return Collections.singletonList(theParam);
}
};
public static Integer findConditionalOperationParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, ConditionalOperationParam.class);
}
@SuppressWarnings("deprecation")
@ -455,46 +299,6 @@ public class MethodUtil {
return MethodUtil.findParamAnnotationIndex(theMethod, VersionIdParam.class);
}
public static Integer findIdParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, IdParam.class);
}
public static Integer findTagListParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, TagListParam.class);
}
/**
* This is a utility method intended provided to help the JPA module.
*/
public static IQueryParameterAnd<?> parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
QueryParameterAndBinder binder = null;
switch (theParamDef.getParamType()) {
case COMPOSITE:
throw new UnsupportedOperationException();
case DATE:
binder = new QueryParameterAndBinder(DateAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case NUMBER:
binder = new QueryParameterAndBinder(NumberAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case QUANTITY:
binder = new QueryParameterAndBinder(QuantityAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case REFERENCE:
binder = new QueryParameterAndBinder(ReferenceAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case STRING:
binder = new QueryParameterAndBinder(StringAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case TOKEN:
binder = new QueryParameterAndBinder(TokenAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
}
return binder.parse(theUnqualifiedParamName, theParameters);
}
@SuppressWarnings("unchecked")
public static List<IParameter> getResourceParameters(FhirContext theContext, Method theMethod, Object theProvider) {
List<IParameter> parameters = new ArrayList<IParameter>();
@ -591,6 +395,8 @@ public class MethodUtil {
param = new SortParameter();
} else if (nextAnnotation instanceof TransactionParam) {
param = new TransactionParamBinder(theContext);
} else if (nextAnnotation instanceof ConditionalOperationParam) {
param = new ConditionalParamBinder();
} else {
continue;
}
@ -612,4 +418,267 @@ public class MethodUtil {
return parameters;
}
public static void parseClientRequestResourceHeaders(IdDt theRequestedId, Map<String, List<String>> theHeaders, IBaseResource resource) {
List<String> lmHeaders = theHeaders.get(Constants.HEADER_LAST_MODIFIED_LOWERCASE);
if (lmHeaders != null && lmHeaders.size() > 0 && StringUtils.isNotBlank(lmHeaders.get(0))) {
String headerValue = lmHeaders.get(0);
Date headerDateValue;
try {
headerDateValue = DateUtils.parseDate(headerValue);
if (resource instanceof IResource) {
InstantDt lmValue = new InstantDt(headerDateValue);
((IResource) resource).getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, lmValue);
} else if (resource instanceof IAnyResource) {
((IAnyResource) resource).getMeta().setLastUpdated(headerDateValue);
}
} catch (Exception e) {
ourLog.warn("Unable to parse date string '{}'. Error is: {}", headerValue, e.toString());
}
}
List<String> clHeaders = theHeaders.get(Constants.HEADER_CONTENT_LOCATION_LC);
if (clHeaders != null && clHeaders.size() > 0 && StringUtils.isNotBlank(clHeaders.get(0))) {
String headerValue = clHeaders.get(0);
if (isNotBlank(headerValue)) {
new IdDt(headerValue).applyTo(resource);
}
}
IdDt existing = IdDt.of(resource);
List<String> eTagHeaders = theHeaders.get(Constants.HEADER_ETAG_LC);
String eTagVersion = null;
if (eTagHeaders != null && eTagHeaders.size() > 0) {
eTagVersion = parseETagValue(eTagHeaders.get(0));
}
if (isNotBlank(eTagVersion)) {
if (existing == null || existing.isEmpty()) {
if (theRequestedId != null) {
theRequestedId.withVersion(eTagVersion).applyTo(resource);
}
} else if (existing.hasVersionIdPart() == false) {
existing.withVersion(eTagVersion).applyTo(resource);
}
} else if (existing == null || existing.isEmpty()) {
if (theRequestedId != null) {
theRequestedId.applyTo(resource);
}
}
List<String> categoryHeaders = theHeaders.get(Constants.HEADER_CATEGORY_LC);
if (categoryHeaders != null && categoryHeaders.size() > 0 && StringUtils.isNotBlank(categoryHeaders.get(0))) {
TagList tagList = new TagList();
for (String header : categoryHeaders) {
parseTagValue(tagList, header);
}
if (resource instanceof IResource) {
ResourceMetadataKeyEnum.TAG_LIST.put((IResource) resource, tagList);
} else if (resource instanceof IAnyResource) {
IMetaType meta = ((IAnyResource) resource).getMeta();
for (Tag next : tagList) {
meta.addTag().setSystem(next.getScheme()).setCode(next.getTerm()).setDisplay(next.getLabel());
}
}
}
}
public static String parseETagValue(String value) {
String eTagVersion;
value = value.trim();
if (value.length() > 1) {
if (value.charAt(value.length() - 1) == '"') {
if (value.charAt(0) == '"') {
eTagVersion = value.substring(1, value.length() - 1);
} else if (value.length() > 3 && value.charAt(0) == 'W' && value.charAt(1) == '/' && value.charAt(2) == '"') {
eTagVersion = value.substring(3, value.length() - 1);
} else {
eTagVersion = value;
}
} else {
eTagVersion = value;
}
} else {
eTagVersion = value;
}
return eTagVersion;
}
/**
* This is a utility method intended provided to help the JPA module.
*/
public static IQueryParameterAnd<?> parseQueryParams(RuntimeSearchParam theParamDef, String theUnqualifiedParamName, List<QualifiedParamList> theParameters) {
QueryParameterAndBinder binder = null;
switch (theParamDef.getParamType()) {
case COMPOSITE:
throw new UnsupportedOperationException();
case DATE:
binder = new QueryParameterAndBinder(DateAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case NUMBER:
binder = new QueryParameterAndBinder(NumberAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case QUANTITY:
binder = new QueryParameterAndBinder(QuantityAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case REFERENCE:
binder = new QueryParameterAndBinder(ReferenceAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case STRING:
binder = new QueryParameterAndBinder(StringAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
case TOKEN:
binder = new QueryParameterAndBinder(TokenAndListParam.class, Collections.<Class<? extends IQueryParameterType>>emptyList());
break;
}
return binder.parse(theUnqualifiedParamName, theParameters);
}
public static void parseTagValue(TagList tagList, String nextTagComplete) {
StringBuilder next = new StringBuilder(nextTagComplete);
parseTagValue(tagList, nextTagComplete, next);
}
private static void parseTagValue(TagList theTagList, String theCompleteHeaderValue, StringBuilder theBuffer) {
int firstSemicolon = theBuffer.indexOf(";");
int deleteTo;
if (firstSemicolon == -1) {
firstSemicolon = theBuffer.indexOf(",");
if (firstSemicolon == -1) {
firstSemicolon = theBuffer.length();
deleteTo = theBuffer.length();
} else {
deleteTo = firstSemicolon;
}
} else {
deleteTo = firstSemicolon + 1;
}
String term = theBuffer.substring(0, firstSemicolon);
String scheme = null;
String label = null;
if (isBlank(term)) {
return;
}
theBuffer.delete(0, deleteTo);
while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') {
theBuffer.deleteCharAt(0);
}
while (theBuffer.length() > 0) {
boolean foundSomething = false;
if (theBuffer.length() > SCHEME.length() && theBuffer.substring(0, SCHEME.length()).equals(SCHEME)) {
int closeIdx = theBuffer.indexOf("\"", SCHEME.length());
scheme = theBuffer.substring(SCHEME.length(), closeIdx);
theBuffer.delete(0, closeIdx + 1);
foundSomething = true;
}
if (theBuffer.length() > LABEL.length() && theBuffer.substring(0, LABEL.length()).equals(LABEL)) {
int closeIdx = theBuffer.indexOf("\"", LABEL.length());
label = theBuffer.substring(LABEL.length(), closeIdx);
theBuffer.delete(0, closeIdx + 1);
foundSomething = true;
}
// TODO: support enc2231-string as described in
// http://tools.ietf.org/html/draft-johnston-http-category-header-02
// TODO: support multiple tags in one header as described in
// http://hl7.org/implement/standards/fhir/http.html#tags
while (theBuffer.length() > 0 && (theBuffer.charAt(0) == ' ' || theBuffer.charAt(0) == ';')) {
theBuffer.deleteCharAt(0);
}
if (!foundSomething) {
break;
}
}
if (theBuffer.length() > 0 && theBuffer.charAt(0) == ',') {
theBuffer.deleteCharAt(0);
while (theBuffer.length() > 0 && theBuffer.charAt(0) == ' ') {
theBuffer.deleteCharAt(0);
}
theTagList.add(new Tag(scheme, term, label));
parseTagValue(theTagList, theCompleteHeaderValue, theBuffer);
} else {
theTagList.add(new Tag(scheme, term, label));
}
if (theBuffer.length() > 0) {
ourLog.warn("Ignoring extra text at the end of " + Constants.HEADER_CATEGORY + " tag '" + theBuffer.toString() + "' - Complete tag value was: " + theCompleteHeaderValue);
}
}
public static MethodOutcome process2xxResponse(FhirContext theContext, String theResourceName, int theResponseStatusCode, String theResponseMimeType, Reader theResponseReader, Map<String, List<String>> theHeaders) {
List<String> locationHeaders = new ArrayList<String>();
List<String> lh = theHeaders.get(Constants.HEADER_LOCATION_LC);
if (lh != null) {
locationHeaders.addAll(lh);
}
List<String> clh = theHeaders.get(Constants.HEADER_CONTENT_LOCATION_LC);
if (clh != null) {
locationHeaders.addAll(clh);
}
MethodOutcome retVal = new MethodOutcome();
if (locationHeaders != null && locationHeaders.size() > 0) {
String locationHeader = locationHeaders.get(0);
BaseOutcomeReturningMethodBinding.parseContentLocation(retVal, theResourceName, locationHeader);
}
if (theResponseStatusCode != Constants.STATUS_HTTP_204_NO_CONTENT) {
EncodingEnum ct = EncodingEnum.forContentType(theResponseMimeType);
if (ct != null) {
PushbackReader reader = new PushbackReader(theResponseReader);
try {
int firstByte = reader.read();
if (firstByte == -1) {
BaseOutcomeReturningMethodBinding.ourLog.debug("No content in response, not going to read");
reader = null;
} else {
reader.unread(firstByte);
}
} catch (IOException e) {
BaseOutcomeReturningMethodBinding.ourLog.debug("No content in response, not going to read", e);
reader = null;
}
if (reader != null) {
IParser parser = ct.newParser(theContext);
IResource outcome = parser.parseResource(reader);
if (outcome instanceof BaseOperationOutcome) {
retVal.setOperationOutcome((BaseOperationOutcome) outcome);
}
}
} else {
BaseOutcomeReturningMethodBinding.ourLog.debug("Ignoring response content of type: {}", theResponseMimeType);
}
}
return retVal;
}
public static IQueryParameterOr<?> singleton(final IQueryParameterType theParam) {
return new IQueryParameterOr<IQueryParameterType>() {
@Override
public List<IQueryParameterType> getValuesAsQueryTokens() {
return Collections.singletonList(theParam);
}
@Override
public void setValuesAsQueryTokens(QualifiedParamList theParameters) {
if (theParameters.isEmpty()) {
return;
}
if (theParameters.size() > 1) {
throw new IllegalArgumentException("Type " + theParam.getClass().getCanonicalName() + " does not support multiple values");
}
theParam.setValueAsQueryToken(theParameters.getQualifier(), theParameters.get(0));
}
};
}
}

View File

@ -20,19 +20,17 @@ package ca.uhn.fhir.rest.method;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Set;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum;
import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
@ -43,16 +41,11 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {
private Integer myIdParameterIndex;
private Integer myVersionIdParameterIndex;
public UpdateMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
super(theMethod, theContext, Update.class, theProvider);
myIdParameterIndex = MethodUtil.findIdParameterIndex(theMethod);
if (myIdParameterIndex == null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' on type '" + theMethod.getDeclaringClass().getCanonicalName() + "' has no parameter annotated with the @" + IdParam.class.getSimpleName() + " annotation");
}
myVersionIdParameterIndex = MethodUtil.findVersionIdParameterIndex(theMethod);
}
@Override
@ -92,7 +85,7 @@ class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceP
if (theRequest.getId() != null && theRequest.getId().hasVersionIdPart() == false) {
if (id != null && id.hasVersionIdPart()) {
theRequest.setId(id);
theRequest.getId().setValue(id.getValue());
}
}
@ -104,9 +97,8 @@ class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceP
}
}
theParams[myIdParameterIndex] = theRequest.getId();
if (myVersionIdParameterIndex != null) {
theParams[myVersionIdParameterIndex] = theRequest.getId();
if (myIdParameterIndex != null) {
theParams[myIdParameterIndex] = theRequest.getId();
}
}
@ -117,12 +109,6 @@ class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceP
throw new NullPointerException("ID can not be null");
}
if (myVersionIdParameterIndex != null) {
IdDt versionIdDt = (IdDt) theArgs[myVersionIdParameterIndex];
if (idDt.hasVersionIdPart() == false) {
idDt = idDt.withVersion(versionIdDt.getIdPart());
}
}
FhirContext context = getContext();
HttpPutClientInvocation retVal = MethodUtil.createUpdateInvocation(theResource, null, idDt, context);

View File

@ -49,8 +49,7 @@ import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
public class InternalCodingDt
extends BaseCodingDt implements ICompositeDatatype
public class InternalCodingDt extends BaseCodingDt implements ICompositeDatatype
{
/**

View File

@ -111,6 +111,8 @@ public class Constants {
public static final int STATUS_HTTP_501_NOT_IMPLEMENTED = 501;
public static final String URL_TOKEN_HISTORY = "_history";
public static final String URL_TOKEN_METADATA = "metadata";
public static final String HEADER_IF_NONE_EXIST = "If-None-Exist";
public static final String HEADER_IF_NONE_EXIST_LC = HEADER_IF_NONE_EXIST.toLowerCase();
static {
Map<String, EncodingEnum> valToEncoding = new HashMap<String, EncodingEnum>();

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IBaseResource;
public interface IAnyResource extends IBaseResource {

View File

@ -1,5 +1,27 @@
package org.hl7.fhir.instance.model.api;
public interface IBackboneElement {
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IBase;
public interface IBackboneElement extends IBase {
}

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IPrimitiveType;
public interface IBaseBooleanDatatype extends IPrimitiveType<Boolean> {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IBaseResource;
public interface IBaseBundle extends IBaseResource {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IBase;
public interface IBaseDatatype extends IBase {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.math.BigDecimal;
import org.hl7.fhir.instance.model.IPrimitiveType;

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IBaseElement {
IBaseElement setId(String theValue);

View File

@ -0,0 +1,42 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IBaseEnumFactory<T extends Enum<?>> {
/**
* Read an enumeration value from the string that represents it on the XML or JSON
*
* @param codeString the value found in the XML or JSON
* @return the enumeration value
* @throws IllegalArgumentException is the value is not known
*/
public T fromCode(String codeString) throws IllegalArgumentException;
/**
* Get the XML/JSON representation for an enumerated value
*
* @param code - the enumeration value
* @return the XML/JSON representation
*/
public String toCode(T code);
}

View File

@ -1,7 +1,39 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import org.hl7.fhir.instance.model.ICompositeType;
public interface IBaseExtension extends ICompositeType {
public interface IBaseExtension<T> extends ICompositeType {
List<T> getExtension();
String getUrl();
IBaseDatatype getValue();
T setUrl(String theUrl);
T setValue(IBaseDatatype theValue);
}

View File

@ -0,0 +1,31 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
public interface IBaseHasExtensions {
public List<? extends IBaseExtension<?>> getExtension();
public IBaseExtension<?> addExtension();
}

View File

@ -0,0 +1,31 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
public interface IBaseHasModifierExtensions {
public List<? extends IBaseExtension<?>> getModifierExtension();
public IBaseExtension<?> addModifierExtension();
}

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IPrimitiveType;
public interface IBaseIntegerDatatype extends IPrimitiveType<Integer> {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface ICoding {
ICoding setSystem(String theScheme);

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.api.IElement;
public interface IDatatypeElement extends IElement {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
public interface IDomainResource {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IIdType {

View File

@ -1,8 +1,30 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Date;
public interface IMetaType {
import org.hl7.fhir.instance.model.ICompositeType;
public interface IMetaType extends ICompositeType {
ICoding addTag();

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.ICompositeType;
public interface INarrative extends ICompositeType {

View File

@ -1,5 +1,25 @@
package org.hl7.fhir.instance.model.api;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.IBase;
public interface IReference extends IBase {

View File

@ -24,7 +24,16 @@ ca.uhn.fhir.validation.FhirValidator.noPhlocError=Phloc-schematron library not f
# JPA Messages
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.incomingNoopInTransaction=Transaction contains resource with operation NOOP. This is only valid as a response operation, not in a request.
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionOperationWithMultipleMatchFailure=Failed to {0} resource with match URL "{1}" because this search matched {2} resources
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionOperationFailedNoId=Failed to {0} resource in transaction because no ID was provided
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionOperationFailedUnknownId=Failed to {0} resource in transaction because no resource could be found with ID {1}
ca.uhn.fhir.jpa.dao.BaseFhirDao.incomingNoopInTransaction=Transaction contains resource with operation NOOP. This is only valid as a response operation, not in a request.
ca.uhn.fhir.jpa.dao.BaseFhirDao.transactionOperationWithMultipleMatchFailure=Failed to {0} resource with match URL "{1}" because this search matched {2} resources
ca.uhn.fhir.jpa.dao.BaseFhirDao.transactionOperationFailedNoId=Failed to {0} resource in transaction because no ID was provided
ca.uhn.fhir.jpa.dao.BaseFhirDao.transactionOperationFailedUnknownId=Failed to {0} resource in transaction because no resource could be found with ID {1}
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionContainsMultipleWithDuplicateId=Transaction bundle contains multiple resources with ID: {0}
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionEntryHasInvalidVerb=Transaction bundle entry has missing or invalid HTTP Verb specified in Bundle.entry.transaction.method. Found value: "{0}"
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionMissingUrl=Unable to perform {0}, no URL provided.
ca.uhn.fhir.jpa.dao.BaseFhirSystemDao.transactionInvalidUrl=Unable to perform {0}, URL provided is invalid: {1}
ca.uhn.fhir.jpa.dao.FhirResourceDao.duplicateCreateForcedId=Can not create entity with ID[{0}], a resource with this ID already exists
ca.uhn.fhir.jpa.dao.FhirResourceDao.failedToCreateWithClientAssignedNumericId=Can not create entity with ID[{0}], this server does not allow clients to assign numeric IDs
ca.uhn.fhir.jpa.dao.FhirResourceDao.unableToDeleteNotFound=Unable to find resource matching URL "{0}". Deletion failed.

View File

@ -21,8 +21,8 @@ public class MultiVersionJsonParserTest {
String str = FhirContext.forDstu2().newJsonParser().encodeResourceToString(p);
ourLog.info(str);
assertThat(str,StringContains.containsString("{\"resourceType\":\"Patient\",\"http://foo#ext\":[{\"valueQuantity\":{\"value\":2.2}}],\"identifier\":[{\"system\":\"urn:sys\",\"value\":\"001\"}]}"));
assertThat(str, StringContains.containsString("{\"resourceType\":\"Patient\",\"extension\":[{\"url\":\"http://foo#ext\",\"valueQuantity\":{\"value\":2.2}}],\"identifier\":[{\"system\":\"urn:sys\",\"value\":\"001\"}]}"));
}
}

View File

@ -9,22 +9,23 @@ import ca.uhn.fhir.validation.FhirValidator;
public class ValidatorTest {
@Test
public void testValidator() {
FhirContext ctx = new FhirContext();
FhirValidator val = ctx.newValidator();
// Phloc is not onthe classpath
assertTrue(val.isValidateAgainstStandardSchema());
assertFalse(val.isValidateAgainstStandardSchematron());
@Test
public void testValidator() {
FhirContext ctx = new FhirContext();
FhirValidator val = ctx.newValidator();
// Phloc is not onthe classpath
assertTrue(val.isValidateAgainstStandardSchema());
assertFalse(val.isValidateAgainstStandardSchematron());
try {
val.setValidateAgainstStandardSchematron(true);
fail();
} catch (IllegalArgumentException e) {
assertEquals("Phloc-schematron library not found on classpath, can not enable perform schematron validation", e.getMessage());
}
}
try { val.setValidateAgainstStandardSchematron(true);
fail();
} catch (IllegalArgumentException e) {
assertEquals("Phloc-schematron library not found on classpath, can not enable perform schematron validation", e.getMessage());
}
}
}

View File

@ -27,7 +27,7 @@
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
<attributes>
<attribute name="owner.project.facets" value="java"/>
</attributes>

View File

@ -7,9 +7,9 @@ org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nul
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
@ -97,4 +97,4 @@ org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<installed facet="jst.utility" version="1.0"/>
<installed facet="java" version="1.6"/>
<installed facet="java" version="1.7"/>
</faceted-project>

View File

@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.*;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collection;
@ -48,6 +50,8 @@ import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.hl7.fhir.instance.model.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
@ -77,6 +81,7 @@ import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.ResourceTag;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
@ -87,6 +92,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -95,15 +102,16 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.FhirTerser;
import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
public abstract class BaseFhirDao implements IDao {
public static final String UCUM_NS = "http://unitsofmeasure.org";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseFhirDao.class);
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
public static final String UCUM_NS = "http://unitsofmeasure.org";
@Autowired(required = true)
private DaoConfig myConfig;
@ -114,8 +122,6 @@ public abstract class BaseFhirDao implements IDao {
private EntityManager myEntityManager;
private List<IDaoListener> myListeners = new ArrayList<IDaoListener>();
private ISearchParamExtractor mySearchParamExtractor;
@Autowired
private PlatformTransactionManager myPlatformTransactionManager;
@ -124,6 +130,8 @@ public abstract class BaseFhirDao implements IDao {
private Map<Class<? extends IBaseResource>, IFhirResourceDao<?>> myResourceTypeToDao;
private ISearchParamExtractor mySearchParamExtractor;
protected void createForcedIdIfNeeded(ResourceTable entity, IdDt id) {
if (id.isEmpty() == false && id.hasIdPart()) {
if (isValidPid(id)) {
@ -196,7 +204,7 @@ public abstract class BaseFhirDao implements IDao {
b.append(nextValue.getReference().getResourceType());
b.append("] - Valid resource types for this server: ");
b.append(myResourceTypeToDao.keySet().toString());
throw new InvalidRequestException(b.toString());
}
Long valueOf;
@ -508,19 +516,6 @@ public abstract class BaseFhirDao implements IDao {
return retVal;
}
protected static String normalizeString(String theString) {
char[] out = new char[theString.length()];
theString = Normalizer.normalize(theString, Normalizer.Form.NFD);
int j = 0;
for (int i = 0, n = theString.length(); i < n; ++i) {
char c = theString.charAt(i);
if (c <= '\u007F') {
out[j++] = c;
}
}
return new String(out).toUpperCase();
}
protected void notifyWriteCompleted() {
for (IDaoListener next : myListeners) {
next.writeCompleted();
@ -579,6 +574,58 @@ public abstract class BaseFhirDao implements IDao {
}
protected Set<Long> processMatchUrl(String theMatchUrl, Class<? extends IBaseResource> theResourceType) {
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
SearchParameterMap paramMap = translateMatchUrl(theMatchUrl, resourceDef);
IFhirResourceDao<? extends IResource> dao = getDao(theResourceType);
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap);
return ids;
}
protected SearchParameterMap translateMatchUrl(String theMatchUrl, RuntimeResourceDefinition resourceDef) {
SearchParameterMap paramMap = new SearchParameterMap();
List<NameValuePair> parameters;
try {
parameters = URLEncodedUtils.parse(new URI(theMatchUrl), "UTF-8");
} catch (URISyntaxException e) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Error was: " + e.toString());
}
ArrayListMultimap<String, QualifiedParamList> nameToParamLists = ArrayListMultimap.create();
for (NameValuePair next : parameters) {
String paramName = next.getName();
String qualifier = null;
for (int i = 0; i < paramMap.size(); i++) {
switch (paramName.charAt(i)) {
case '.':
case ':':
qualifier = paramName.substring(i);
paramName = paramName.substring(0, i);
i = Integer.MAX_VALUE;
break;
}
}
QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, next.getValue());
nameToParamLists.put(paramName, paramList);
}
for (String nextParamName : nameToParamLists.keySet()) {
RuntimeSearchParam paramDef = resourceDef.getSearchParam(nextParamName);
if (paramDef == null) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
}
List<QualifiedParamList> paramList = nameToParamLists.get(nextParamName);
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(paramDef, nextParamName, paramList);
paramMap.add(nextParamName, param);
}
return paramMap;
}
@Override
public void registerDaoListener(IDaoListener theListener) {
Validate.notNull(theListener, "theListener");
@ -832,7 +879,20 @@ public abstract class BaseFhirDao implements IDao {
}
}
protected String translatePidIdToForcedId(Long theId) {
ForcedId forcedId = myEntityManager.find(ForcedId.class, theId);
if (forcedId != null) {
return forcedId.getForcedId();
} else {
return theId.toString();
}
}
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull) {
return updateEntity(theResource, entity, theUpdateHistory, theDeletedTimestampOrNull, true, true);
}
protected ResourceTable updateEntity(final IResource theResource, ResourceTable entity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion) {
if (entity.getPublished() == null) {
entity.setPublished(new Date());
}
@ -849,8 +909,10 @@ public abstract class BaseFhirDao implements IDao {
myEntityManager.persist(historyEntry);
}
entity.setVersion(entity.getVersion() + 1);
if (theUpdateVersion) {
entity.setVersion(entity.getVersion() + 1);
}
Collection<ResourceIndexedSearchParamString> paramsString = new ArrayList<ResourceIndexedSearchParamString>(entity.getParamsString());
Collection<ResourceIndexedSearchParamToken> paramsToken = new ArrayList<ResourceIndexedSearchParamToken>(entity.getParamsToken());
Collection<ResourceIndexedSearchParamNumber> paramsNumber = new ArrayList<ResourceIndexedSearchParamNumber>(entity.getParamsNumber());
@ -858,12 +920,13 @@ public abstract class BaseFhirDao implements IDao {
Collection<ResourceIndexedSearchParamDate> paramsDate = new ArrayList<ResourceIndexedSearchParamDate>(entity.getParamsDate());
Collection<ResourceLink> resourceLinks = new ArrayList<ResourceLink>(entity.getResourceLinks());
final List<ResourceIndexedSearchParamString> stringParams;
final List<ResourceIndexedSearchParamToken> tokenParams;
final List<ResourceIndexedSearchParamNumber> numberParams;
final List<ResourceIndexedSearchParamQuantity> quantityParams;
final List<ResourceIndexedSearchParamDate> dateParams;
final List<ResourceLink> links;
List<ResourceIndexedSearchParamString> stringParams = null;
List<ResourceIndexedSearchParamToken> tokenParams = null;
List<ResourceIndexedSearchParamNumber> numberParams = null;
List<ResourceIndexedSearchParamQuantity> quantityParams = null;
List<ResourceIndexedSearchParamDate> dateParams = null;
List<ResourceLink> links = null;
if (theDeletedTimestampOrNull != null) {
stringParams = Collections.emptyList();
@ -875,7 +938,7 @@ public abstract class BaseFhirDao implements IDao {
entity.setDeleted(theDeletedTimestampOrNull);
entity.setUpdated(theDeletedTimestampOrNull);
} else {
} else if (thePerformIndexing) {
stringParams = extractSearchParamStrings(entity, theResource);
numberParams = extractSearchParamNumber(entity, theResource);
@ -893,7 +956,6 @@ public abstract class BaseFhirDao implements IDao {
links = extractResourceLinks(entity, theResource);
populateResourceIntoEntity(theResource, entity);
entity.setUpdated(new Date());
entity.setLanguage(theResource.getLanguage().getValue());
entity.setParamsString(stringParams);
@ -909,6 +971,12 @@ public abstract class BaseFhirDao implements IDao {
entity.setResourceLinks(links);
entity.setHasLinks(links.isEmpty() == false);
} else {
populateResourceIntoEntity(theResource, entity);
entity.setUpdated(new Date());
entity.setLanguage(theResource.getLanguage().getValue());
}
if (entity.getId() == null) {
@ -922,59 +990,63 @@ public abstract class BaseFhirDao implements IDao {
entity = myEntityManager.merge(entity);
}
if (entity.isParamsStringPopulated()) {
for (ResourceIndexedSearchParamString next : paramsString) {
myEntityManager.remove(next);
}
}
for (ResourceIndexedSearchParamString next : stringParams) {
myEntityManager.persist(next);
}
if (thePerformIndexing) {
if (entity.isParamsTokenPopulated()) {
for (ResourceIndexedSearchParamToken next : paramsToken) {
myEntityManager.remove(next);
if (entity.isParamsStringPopulated()) {
for (ResourceIndexedSearchParamString next : paramsString) {
myEntityManager.remove(next);
}
}
for (ResourceIndexedSearchParamString next : stringParams) {
myEntityManager.persist(next);
}
}
for (ResourceIndexedSearchParamToken next : tokenParams) {
myEntityManager.persist(next);
}
if (entity.isParamsNumberPopulated()) {
for (ResourceIndexedSearchParamNumber next : paramsNumber) {
myEntityManager.remove(next);
if (entity.isParamsTokenPopulated()) {
for (ResourceIndexedSearchParamToken next : paramsToken) {
myEntityManager.remove(next);
}
}
for (ResourceIndexedSearchParamToken next : tokenParams) {
myEntityManager.persist(next);
}
}
for (ResourceIndexedSearchParamNumber next : numberParams) {
myEntityManager.persist(next);
}
if (entity.isParamsQuantityPopulated()) {
for (ResourceIndexedSearchParamQuantity next : paramsQuantity) {
myEntityManager.remove(next);
if (entity.isParamsNumberPopulated()) {
for (ResourceIndexedSearchParamNumber next : paramsNumber) {
myEntityManager.remove(next);
}
}
for (ResourceIndexedSearchParamNumber next : numberParams) {
myEntityManager.persist(next);
}
}
for (ResourceIndexedSearchParamQuantity next : quantityParams) {
myEntityManager.persist(next);
}
if (entity.isParamsDatePopulated()) {
for (ResourceIndexedSearchParamDate next : paramsDate) {
myEntityManager.remove(next);
if (entity.isParamsQuantityPopulated()) {
for (ResourceIndexedSearchParamQuantity next : paramsQuantity) {
myEntityManager.remove(next);
}
}
for (ResourceIndexedSearchParamQuantity next : quantityParams) {
myEntityManager.persist(next);
}
}
for (ResourceIndexedSearchParamDate next : dateParams) {
myEntityManager.persist(next);
}
if (entity.isHasLinks()) {
for (ResourceLink next : resourceLinks) {
myEntityManager.remove(next);
if (entity.isParamsDatePopulated()) {
for (ResourceIndexedSearchParamDate next : paramsDate) {
myEntityManager.remove(next);
}
}
}
for (ResourceLink next : links) {
myEntityManager.persist(next);
}
for (ResourceIndexedSearchParamDate next : dateParams) {
myEntityManager.persist(next);
}
if (entity.isHasLinks()) {
for (ResourceLink next : resourceLinks) {
myEntityManager.remove(next);
}
}
for (ResourceLink next : links) {
myEntityManager.persist(next);
}
} // if thePerformIndexing
myEntityManager.flush();
@ -985,4 +1057,17 @@ public abstract class BaseFhirDao implements IDao {
return entity;
}
protected static String normalizeString(String theString) {
char[] out = new char[theString.length()];
theString = Normalizer.normalize(theString, Normalizer.Form.NFD);
int j = 0;
for (int i = 0, n = theString.length(); i < n; ++i) {
char c = theString.charAt(i);
if (c <= '\u007F') {
out[j++] = c;
}
}
return new String(out).toUpperCase();
}
}

View File

@ -20,11 +20,8 @@ package ca.uhn.fhir.jpa.dao;
* #L%
*/
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -36,27 +33,14 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.StopWatch;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.method.QualifiedParamList;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import com.google.common.collect.ArrayListMultimap;
public abstract class BaseFhirSystemDao<T> extends BaseFhirDao implements IFhirSystemDao<T> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseFhirSystemDao.class);
@ -82,53 +66,6 @@ public abstract class BaseFhirSystemDao<T> extends BaseFhirDao implements IFhirS
return myEntityManager.find(ResourceTable.class, candidateMatches.iterator().next());
}
protected Set<Long> processMatchUrl(String theMatchUrl, Class<? extends IBaseResource> theResourceType) {
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
SearchParameterMap paramMap = new SearchParameterMap();
List<NameValuePair> parameters;
try {
parameters = URLEncodedUtils.parse(new URI(theMatchUrl), "UTF-8");
} catch (URISyntaxException e) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Error was: " + e.toString());
}
ArrayListMultimap<String, QualifiedParamList> nameToParamLists = ArrayListMultimap.create();
for (NameValuePair next : parameters) {
String paramName = next.getName();
String qualifier = null;
for (int i = 0; i < paramMap.size(); i++) {
switch (paramName.charAt(i)) {
case '.':
case ':':
qualifier = paramName.substring(i);
paramName = paramName.substring(0, i);
i = Integer.MAX_VALUE;
break;
}
}
QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, next.getValue());
nameToParamLists.put(paramName, paramList);
}
for (String nextParamName : nameToParamLists.keySet()) {
RuntimeSearchParam paramDef = resourceDef.getSearchParam(nextParamName);
if (paramDef == null) {
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
}
List<QualifiedParamList> paramList = nameToParamLists.get(nextParamName);
IQueryParameterAnd<?> param = MethodUtil.parseQueryParams(paramDef, nextParamName, paramList);
paramMap.add(nextParamName, param);
}
IFhirResourceDao<? extends IResource> dao = getDao(theResourceType);
Set<Long> ids = dao.searchForIdsWithAndOr(paramMap);
return ids;
}
@Override
public IBundleProvider history(Date theSince) {
StopWatch w = new StopWatch();

View File

@ -0,0 +1,56 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.api.MethodOutcome;
public class DaoMethodOutcome extends MethodOutcome {
private ResourceTable myEntity;
private IResource myResource;
public ResourceTable getEntity() {
return myEntity;
}
public IResource getResource() {
return myResource;
}
@Override
public DaoMethodOutcome setCreated(Boolean theCreated) {
super.setCreated(theCreated);
return this;
}
public DaoMethodOutcome setEntity(ResourceTable theEntity) {
myEntity = theEntity;
return this;
}
public DaoMethodOutcome setResource(IResource theResource) {
myResource = theResource;
return this;
}
}

View File

@ -20,229 +20,516 @@ package ca.uhn.fhir.jpa.dao;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
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.EntryTransactionResponse;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.FhirTerser;
public class FhirSystemDaoDstu2 extends BaseFhirSystemDao<Bundle> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class);
private UrlParts parseUrl(String theAction, String theUrl) {
UrlParts retVal = new UrlParts();
//@formatter:off
/*
* We assume that the URL passed in is in one of the following forms:
* [Resource Type]?[Search Params]
* [Resource Type]/[Resource ID]
* [Resource Type]/[Resource ID]/_history/[Version ID]
*/
//@formatter:on
int nextStart = 0;
boolean nextIsHistory = false;
for (int idx = 0; idx < theUrl.length(); idx++) {
char nextChar = theUrl.charAt(idx);
boolean atEnd = (idx + 1) == theUrl.length();
if (nextChar == '?' || nextChar == '/' || atEnd) {
int endIdx = atEnd ? idx + 1 : idx;
String nextSubstring = theUrl.substring(nextStart, endIdx);
if (retVal.getResourceType() == null) {
retVal.setResourceType(nextSubstring);
} else if (retVal.getResourceId() == null) {
retVal.setResourceId(nextSubstring);
} else if (nextIsHistory) {
retVal.setVersionId(nextSubstring);
} else {
if (nextSubstring.equals(Constants.URL_TOKEN_HISTORY)) {
nextIsHistory = true;
} else {
String msg = getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
}
if (nextChar == '?') {
if (theUrl.length() > idx + 1) {
retVal.setParams(theUrl.substring(idx + 1, theUrl.length()));
}
break;
}
nextStart = idx + 1;
}
}
RuntimeResourceDefinition resType = getContext().getResourceDefinition(retVal.getResourceType());
IFhirResourceDao<? extends IResource> dao = null;
if (resType != null) {
dao = getDao(resType.getImplementingClass());
}
if (dao == null) {
String msg = getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
retVal.setDao(dao);
if (retVal.getResourceId() == null && retVal.getParams() == null) {
String msg = getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionInvalidUrl", theAction, theUrl);
throw new InvalidRequestException(msg);
}
return retVal;
}
@SuppressWarnings("unchecked")
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Bundle transaction(Bundle theResources) {
ourLog.info("Beginning transaction with {} resources", theResources.getEntry().size());
long start = System.currentTimeMillis();
// Set<IdDt> allIds = new HashSet<IdDt>();
//
// for (int i = 0; i < theResources.size(); i++) {
// IResource res = theResources.get(i);
// if (res.getId().hasIdPart() && !res.getId().hasResourceType()) {
// res.setId(new IdDt(toResourceName(res.getClass()), res.getId().getIdPart()));
// }
//
// /*
// * Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
// */
// if (res.getId().hasResourceType() && res.getId().hasIdPart()) {
// IdDt nextId = res.getId().toUnqualifiedVersionless();
// if (!allIds.add(nextId)) {
// throw new InvalidRequestException("Transaction bundle contains multiple resources with ID: " + nextId);
// }
// }
// }
//
// FhirTerser terser = getContext().newTerser();
//
// int creations = 0;
// int updates = 0;
//
// Map<IdDt, IdDt> idConversions = new HashMap<IdDt, IdDt>();
//
// List<ResourceTable> persistedResources = new ArrayList<ResourceTable>();
//
// List<IResource> retVal = new ArrayList<IResource>();
// OperationOutcome oo = new OperationOutcome();
// retVal.add(oo);
//
// for (int resourceIdx = 0; resourceIdx < theResources.size(); resourceIdx++) {
// IResource nextResource = theResources.get(resourceIdx);
//
// IdDt nextId = nextResource.getId();
// if (nextId == null) {
// nextId = new IdDt();
// }
//
// String resourceName = toResourceName(nextResource);
// BundleEntryTransactionOperationEnum nextResouceOperationIn = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(nextResource);
// if (nextResouceOperationIn == null && hasValue(ResourceMetadataKeyEnum.DELETED_AT.get(nextResource))) {
// nextResouceOperationIn = BundleEntryTransactionOperationEnum.DELETE;
// }
//
// String matchUrl = ResourceMetadataKeyEnum.LINK_SEARCH.get(nextResource);
// Set<Long> candidateMatches = null;
// if (StringUtils.isNotBlank(matchUrl)) {
// candidateMatches = processMatchUrl(matchUrl, nextResource.getClass());
// }
//
// ResourceTable entity;
// if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
// entity = null;
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE || nextResouceOperationIn == BundleEntryTransactionOperationEnum.DELETE) {
// if (candidateMatches == null || candidateMatches.size() == 0) {
// if (nextId == null || StringUtils.isBlank(nextId.getIdPart())) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class, "transactionOperationFailedNoId", nextResouceOperationIn.name()));
// }
// entity = tryToLoadEntity(nextId);
// if (entity == null) {
// if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE) {
// ourLog.debug("Attempting to UPDATE resource with unknown ID '{}', will CREATE instead", nextId);
// } else if (candidateMatches == null) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class, "transactionOperationFailedUnknownId", nextResouceOperationIn.name(), nextId));
// } else {
// ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource, BundleEntryTransactionOperationEnum.NOOP);
// persistedResources.add(null);
// retVal.add(nextResource);
// continue;
// }
// }
// } else if (candidateMatches.size() == 1) {
// entity = loadFirstEntityFromCandidateMatches(candidateMatches);
// } else {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class, "transactionOperationWithMultipleMatchFailure", nextResouceOperationIn.name(), matchUrl, candidateMatches.size()));
// }
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.NOOP) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class, "incomingNoopInTransaction"));
// } else if (nextId.isEmpty()) {
// entity = null;
// } else {
// entity = tryToLoadEntity(nextId);
// }
//
// BundleEntryTransactionOperationEnum nextResouceOperationOut;
// if (entity == null) {
// nextResouceOperationOut = BundleEntryTransactionOperationEnum.CREATE;
// entity = toEntity(nextResource);
// if (nextId.isEmpty() == false && nextId.getIdPart().startsWith("cid:")) {
// ourLog.debug("Resource in transaction has ID[{}], will replace with server assigned ID", nextId.getIdPart());
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
// if (nextId.isEmpty() == false) {
// ourLog.debug("Resource in transaction has ID[{}] but is marked for CREATE, will ignore ID", nextId.getIdPart());
// }
// if (candidateMatches != null) {
// if (candidateMatches.size() == 1) {
// ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
// BaseHasResource existingEntity = loadFirstEntityFromCandidateMatches(candidateMatches);
// IResource existing = (IResource) toResource(existingEntity);
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(existing, BundleEntryTransactionOperationEnum.NOOP);
// persistedResources.add(null);
// retVal.add(existing);
// continue;
// }
// if (candidateMatches.size() > 1) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class, "transactionOperationWithMultipleMatchFailure", BundleEntryTransactionOperationEnum.CREATE.name(), matchUrl, candidateMatches.size()));
// }
// }
// } else {
// createForcedIdIfNeeded(entity, nextId);
// }
// myEntityManager.persist(entity);
// if (entity.getForcedId() != null) {
// myEntityManager.persist(entity.getForcedId());
// }
// creations++;
// ourLog.info("Resource Type[{}] with ID[{}] does not exist, creating it", resourceName, nextId);
// } else {
// nextResouceOperationOut = nextResouceOperationIn;
// if (nextResouceOperationOut == null) {
// nextResouceOperationOut = BundleEntryTransactionOperationEnum.UPDATE;
// }
// updates++;
// ourLog.info("Resource Type[{}] with ID[{}] exists, updating it", resourceName, nextId);
// }
//
// persistedResources.add(entity);
// retVal.add(nextResource);
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource, nextResouceOperationOut);
// }
//
// ourLog.info("Flushing transaction to database");
// myEntityManager.flush();
//
// for (int i = 0; i < persistedResources.size(); i++) {
// ResourceTable entity = persistedResources.get(i);
//
// String resourceName = toResourceName(theResources.get(i));
// IdDt nextId = theResources.get(i).getId();
//
// IdDt newId;
//
// if (entity == null) {
// newId = retVal.get(i + 1).getId().toUnqualifiedVersionless();
// } else {
// newId = entity.getIdDt().toUnqualifiedVersionless();
// }
//
// if (nextId == null || nextId.isEmpty()) {
// ourLog.info("Transaction resource (with no preexisting ID) has been assigned new ID[{}]", nextId, newId);
// } else {
// if (nextId.toUnqualifiedVersionless().equals(newId)) {
// ourLog.info("Transaction resource ID[{}] is being updated", newId);
// } else {
// if (!nextId.getIdPart().startsWith("#")) {
// nextId = new IdDt(resourceName + '/' + nextId.getIdPart());
// ourLog.info("Transaction resource ID[{}] has been assigned new ID[{}]", nextId, newId);
// idConversions.put(nextId, newId);
// }
// }
// }
//
// }
//
// for (IResource nextResource : theResources) {
// List<BaseResourceReferenceDt> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, BaseResourceReferenceDt.class);
// for (BaseResourceReferenceDt nextRef : allRefs) {
// IdDt nextId = nextRef.getReference();
// if (idConversions.containsKey(nextId)) {
// IdDt newId = idConversions.get(nextId);
// ourLog.info(" * Replacing resource ref {} with {}", nextId, newId);
// nextRef.setReference(newId);
// } else {
// ourLog.debug(" * Reference [{}] does not exist in bundle", nextId);
// }
// }
// }
//
// ourLog.info("Re-flushing updated resource references and extracting search criteria");
//
// for (int i = 0; i < theResources.size(); i++) {
// IResource resource = theResources.get(i);
// ResourceTable table = persistedResources.get(i);
// if (table == null) {
// continue;
// }
//
// InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(resource);
// Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
// if (deletedInstantOrNull == null && ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(resource) == BundleEntryTransactionOperationEnum.DELETE) {
// deletedTimestampOrNull = new Date();
// ResourceMetadataKeyEnum.DELETED_AT.put(resource, new InstantDt(deletedTimestampOrNull));
// }
//
// updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull);
// }
//
// long delay = System.currentTimeMillis() - start;
// ourLog.info("Transaction completed in {}ms with {} creations and {} updates", new Object[] { delay, creations, updates });
//
// oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Transaction completed in " + delay + "ms with " + creations + " creations and " + updates + " updates");
//
// notifyWriteCompleted();
Set<IdDt> allIds = new HashSet<IdDt>();
Map<IdDt, IdDt> idSubstitutions = new HashMap<IdDt, IdDt>();
Map<IdDt, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdDt, DaoMethodOutcome>();
return null;
Bundle response = new Bundle();
OperationOutcome oo = new OperationOutcome();
response.addEntry().setResource(oo);
for (int i = 0; i < theResources.getEntry().size(); i++) {
Entry nextEntry = theResources.getEntry().get(i);
IResource res = nextEntry.getResource();
IdDt nextResourceId = null;
if (res != null) {
nextResourceId = res.getId();
if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType()) {
nextResourceId = new IdDt(toResourceName(res.getClass()), nextResourceId.getIdPart());
res.setId(nextResourceId);
}
/*
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
*/
if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
IdDt nextId = nextResourceId.toUnqualifiedVersionless();
if (!allIds.add(nextId)) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
}
}
}
HTTPVerbEnum verb = nextEntry.getTransaction().getMethodElement().getValueAsEnum();
if (verb == null) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionEntryHasInvalidVerb", nextEntry.getTransaction().getMethod()));
}
switch (verb) {
case POST: {
// CREATE
@SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = getDao(res.getClass());
res.setId(null);
DaoMethodOutcome outcome;
Entry newEntry = response.addEntry();
outcome = resourceDao.create(res, nextEntry.getTransaction().getIfNoneExist(), false);
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
break;
}
case DELETE: {
// DELETE
Entry newEntry = response.addEntry();
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url);
if (parts.getResourceId() != null) {
parts.getDao().delete(new IdDt(parts.getResourceType(), parts.getResourceId()));
} else {
parts.getDao().deleteByUrl(parts.getResourceType() + '?' + parts.getParams());
}
newEntry.getTransactionResponse().setStatus(Integer.toString(Constants.STATUS_HTTP_204_NO_CONTENT));
break;
}
case PUT: {
// UPDATE
@SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = getDao(res.getClass());
DaoMethodOutcome outcome;
Entry newEntry = response.addEntry();
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url);
if (parts.getResourceId() != null) {
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
outcome = resourceDao.update(res, null, false);
} else {
res.setId(null);
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false);
}
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, newEntry);
break;
}
case GET: {
// SEARCH/READ/VREAD
String url = extractTransactionUrlOrThrowException(nextEntry, verb);
UrlParts parts = parseUrl(verb.getCode(), url);
@SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = parts.getDao();
if (parts.getResourceId() != null && parts.getParams() == null) {
IResource found;
if (parts.getVersionId() != null) {
found = resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId(), parts.getVersionId()));
} else {
found = resourceDao.read(new IdDt(parts.getResourceType(), parts.getResourceId()));
}
EntryTransactionResponse resp = response.addEntry().setResource(found).getTransactionResponse();
resp.setLocation(found.getId().toUnqualified().getValue());
resp.addEtag(found.getId().getVersionIdPart());
} else if (parts.getParams() != null) {
RuntimeResourceDefinition def = getContext().getResourceDefinition(parts.getDao().getResourceType());
SearchParameterMap params = translateMatchUrl(url, def);
IBundleProvider bundle = parts.getDao().search(params);
Bundle searchBundle = new Bundle();
searchBundle.setTotal(bundle.size());
int configuredMax = 100; // this should probably be configurable or something
if (bundle.size() > configuredMax) {
oo.addIssue().setSeverity(IssueSeverityEnum.WARNING).setDetails("Search nested within transaction found more than " + configuredMax + " matches, but paging is not supported in nested transactions");
}
List<IResource> resourcesToAdd = bundle.getResources(0, Math.min(bundle.size(), configuredMax));
for (IResource next : resourcesToAdd) {
searchBundle.addEntry().setResource(next);
}
response.addEntry().setResource(searchBundle);
}
}
}
}
FhirTerser terser = getContext().newTerser();
// int creations = 0;
// int updates = 0;
//
// Map<IdDt, IdDt> idConversions = new HashMap<IdDt, IdDt>();
//
// List<ResourceTable> persistedResources = new ArrayList<ResourceTable>();
//
// List<IResource> retVal = new ArrayList<IResource>();
// OperationOutcome oo = new OperationOutcome();
// retVal.add(oo);
//
// for (int resourceIdx = 0; resourceIdx < theResources.size(); resourceIdx++) {
// IResource nextResource = theResources.get(resourceIdx);
//
// IdDt nextId = nextResource.getId();
// if (nextId == null) {
// nextId = new IdDt();
// }
//
// String resourceName = toResourceName(nextResource);
// BundleEntryTransactionOperationEnum nextResouceOperationIn =
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(nextResource);
// if (nextResouceOperationIn == null && hasValue(ResourceMetadataKeyEnum.DELETED_AT.get(nextResource))) {
// nextResouceOperationIn = BundleEntryTransactionOperationEnum.DELETE;
// }
//
// String matchUrl = ResourceMetadataKeyEnum.LINK_SEARCH.get(nextResource);
// Set<Long> candidateMatches = null;
// if (StringUtils.isNotBlank(matchUrl)) {
// candidateMatches = processMatchUrl(matchUrl, nextResource.getClass());
// }
//
// ResourceTable entity;
// if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
// entity = null;
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE || nextResouceOperationIn ==
// BundleEntryTransactionOperationEnum.DELETE) {
// if (candidateMatches == null || candidateMatches.size() == 0) {
// if (nextId == null || StringUtils.isBlank(nextId.getIdPart())) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
// "transactionOperationFailedNoId", nextResouceOperationIn.name()));
// }
// entity = tryToLoadEntity(nextId);
// if (entity == null) {
// if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.UPDATE) {
// ourLog.debug("Attempting to UPDATE resource with unknown ID '{}', will CREATE instead", nextId);
// } else if (candidateMatches == null) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
// "transactionOperationFailedUnknownId", nextResouceOperationIn.name(), nextId));
// } else {
// ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource,
// BundleEntryTransactionOperationEnum.NOOP);
// persistedResources.add(null);
// retVal.add(nextResource);
// continue;
// }
// }
// } else if (candidateMatches.size() == 1) {
// entity = loadFirstEntityFromCandidateMatches(candidateMatches);
// } else {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
// "transactionOperationWithMultipleMatchFailure", nextResouceOperationIn.name(), matchUrl,
// candidateMatches.size()));
// }
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.NOOP) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
// "incomingNoopInTransaction"));
// } else if (nextId.isEmpty()) {
// entity = null;
// } else {
// entity = tryToLoadEntity(nextId);
// }
//
// BundleEntryTransactionOperationEnum nextResouceOperationOut;
// if (entity == null) {
// nextResouceOperationOut = BundleEntryTransactionOperationEnum.CREATE;
// entity = toEntity(nextResource);
// if (nextId.isEmpty() == false && nextId.getIdPart().startsWith("cid:")) {
// ourLog.debug("Resource in transaction has ID[{}], will replace with server assigned ID", nextId.getIdPart());
// } else if (nextResouceOperationIn == BundleEntryTransactionOperationEnum.CREATE) {
// if (nextId.isEmpty() == false) {
// ourLog.debug("Resource in transaction has ID[{}] but is marked for CREATE, will ignore ID",
// nextId.getIdPart());
// }
// if (candidateMatches != null) {
// if (candidateMatches.size() == 1) {
// ourLog.debug("Resource with match URL [{}] already exists, will be NOOP", matchUrl);
// BaseHasResource existingEntity = loadFirstEntityFromCandidateMatches(candidateMatches);
// IResource existing = (IResource) toResource(existingEntity);
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(existing, BundleEntryTransactionOperationEnum.NOOP);
// persistedResources.add(null);
// retVal.add(existing);
// continue;
// }
// if (candidateMatches.size() > 1) {
// throw new InvalidRequestException(getContext().getLocalizer().getMessage(FhirSystemDaoDstu2.class,
// "transactionOperationWithMultipleMatchFailure", BundleEntryTransactionOperationEnum.CREATE.name(), matchUrl,
// candidateMatches.size()));
// }
// }
// } else {
// createForcedIdIfNeeded(entity, nextId);
// }
// myEntityManager.persist(entity);
// if (entity.getForcedId() != null) {
// myEntityManager.persist(entity.getForcedId());
// }
// creations++;
// ourLog.info("Resource Type[{}] with ID[{}] does not exist, creating it", resourceName, nextId);
// } else {
// nextResouceOperationOut = nextResouceOperationIn;
// if (nextResouceOperationOut == null) {
// nextResouceOperationOut = BundleEntryTransactionOperationEnum.UPDATE;
// }
// updates++;
// ourLog.info("Resource Type[{}] with ID[{}] exists, updating it", resourceName, nextId);
// }
//
// persistedResources.add(entity);
// retVal.add(nextResource);
// ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(nextResource, nextResouceOperationOut);
// }
//
// ourLog.info("Flushing transaction to database");
// myEntityManager.flush();
//
// for (int i = 0; i < persistedResources.size(); i++) {
// ResourceTable entity = persistedResources.get(i);
//
// String resourceName = toResourceName(theResources.get(i));
// IdDt nextId = theResources.get(i).getId();
//
// IdDt newId;
//
// if (entity == null) {
// newId = retVal.get(i + 1).getId().toUnqualifiedVersionless();
// } else {
// newId = entity.getIdDt().toUnqualifiedVersionless();
// }
//
// if (nextId == null || nextId.isEmpty()) {
// ourLog.info("Transaction resource (with no preexisting ID) has been assigned new ID[{}]", nextId, newId);
// } else {
// if (nextId.toUnqualifiedVersionless().equals(newId)) {
// ourLog.info("Transaction resource ID[{}] is being updated", newId);
// } else {
// if (!nextId.getIdPart().startsWith("#")) {
// nextId = new IdDt(resourceName + '/' + nextId.getIdPart());
// ourLog.info("Transaction resource ID[{}] has been assigned new ID[{}]", nextId, newId);
// idConversions.put(nextId, newId);
// }
// }
// }
//
// }
//
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
IResource nextResource = nextOutcome.getResource();
if (nextResource == null) {
continue;
}
List<BaseResourceReferenceDt> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, BaseResourceReferenceDt.class);
for (BaseResourceReferenceDt nextRef : allRefs) {
IdDt nextId = nextRef.getReference();
if (idSubstitutions.containsKey(nextId)) {
IdDt newId = idSubstitutions.get(nextId);
ourLog.info(" * Replacing resource ref {} with {}", nextId, newId);
nextRef.setReference(newId);
} else {
ourLog.debug(" * Reference [{}] does not exist in bundle", nextId);
}
}
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false);
}
//
// ourLog.info("Re-flushing updated resource references and extracting search criteria");
//
// for (int i = 0; i < theResources.size(); i++) {
// IResource resource = theResources.get(i);
// ResourceTable table = persistedResources.get(i);
// if (table == null) {
// continue;
// }
//
// InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(resource);
// Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
// if (deletedInstantOrNull == null && ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(resource) ==
// BundleEntryTransactionOperationEnum.DELETE) {
// deletedTimestampOrNull = new Date();
// ResourceMetadataKeyEnum.DELETED_AT.put(resource, new InstantDt(deletedTimestampOrNull));
// }
//
// updateEntity(resource, table, table.getId() != null, deletedTimestampOrNull);
// }
long delay = System.currentTimeMillis() - start;
ourLog.info("Transaction completed in {}ms", new Object[]{delay});
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Transaction completed in " + delay + "ms");
notifyWriteCompleted();
return response;
}
private void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome, Entry newEntry) {
IdDt newId = outcome.getId().toUnqualifiedVersionless();
if (newId.equals(nextResourceId) == false) {
idSubstitutions.put(nextResourceId, newId);
}
idToPersistedOutcome.put(newId, outcome);
if (outcome.getCreated().booleanValue()) {
newEntry.getTransactionResponse().setStatus(Long.toString(Constants.STATUS_HTTP_201_CREATED));
} else {
newEntry.getTransactionResponse().setStatus(Long.toString(Constants.STATUS_HTTP_200_OK));
}
newEntry.getTransactionResponse().setLocation(outcome.getId().toUnqualified().getValue());
newEntry.getTransactionResponse().addEtag().setValue(outcome.getId().getVersionIdPart());
}
private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) {
String url = nextEntry.getTransaction().getUrl();
if (isBlank(url)) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseFhirSystemDao.class, "transactionMissingUrl", verb.name()));
}
return url;
}
private static class UrlParts {
private IFhirResourceDao<? extends IResource> myDao;
private String myParams;
private String myResourceId;
private String myResourceType;
private String myVersionId;
public IFhirResourceDao<? extends IResource> getDao() {
return myDao;
}
public void setVersionId(String theVersionId) {
myVersionId = theVersionId;
}
public String getVersionId() {
return myVersionId;
}
public String getParams() {
return myParams;
}
public String getResourceId() {
return myResourceId;
}
public String getResourceType() {
return myResourceType;
}
public void setDao(IFhirResourceDao<? extends IResource> theDao) {
myDao = theDao;
}
public void setParams(String theParams) {
myParams = theParams;
}
public void setResourceId(String theResourceId) {
myResourceId = theResourceId;
}
public void setResourceType(String theResourceType) {
myResourceType = theResourceType;
}
}
}

View File

@ -29,7 +29,6 @@ import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -37,9 +36,19 @@ public interface IFhirResourceDao<T extends IResource> extends IDao {
void addTag(IdDt theId, String theScheme, String theTerm, String theLabel);
MethodOutcome create(T theResource);
DaoMethodOutcome create(T theResource);
MethodOutcome delete(IdDt theResource);
DaoMethodOutcome create(T theResource, String theIfNoneExist);
/**
* @param thePerformIndexing Use with caution! If you set this to false, you need to manually perform indexing or your resources
* won't be indexed and searches won't work.
*/
DaoMethodOutcome create(T theResource, String theIfNoneExist, boolean thePerformIndexing);
DaoMethodOutcome delete(IdDt theResource);
DaoMethodOutcome deleteByUrl(String theString);
TagList getAllResourceTags();
@ -49,20 +58,27 @@ public interface IFhirResourceDao<T extends IResource> extends IDao {
IBundleProvider history(Date theSince);
IBundleProvider history(IdDt theId,Date theSince);
IBundleProvider history(IdDt theId, Date theSince);
IBundleProvider history(Long theId, Date theSince);
/**
*
* @param theId
* @return
* @throws ResourceNotFoundException If the ID is not known to the server
* @throws ResourceNotFoundException
* If the ID is not known to the server
*/
T read(IdDt theId);
BaseHasResource readEntity(IdDt theId);
/**
* @param theCheckForForcedId If true, this method should fail if the requested ID contains a numeric PID which exists, but is
* obscured by a "forced ID" so should not exist as far as the outside world is concerned.
*/
BaseHasResource readEntity(IdDt theId, boolean theCheckForForcedId);
void removeTag(IdDt theId, String theScheme, String theTerm);
IBundleProvider search(Map<String, IQueryParameterType> theParams);
@ -75,15 +91,17 @@ public interface IFhirResourceDao<T extends IResource> extends IDao {
Set<Long> searchForIds(String theParameterName, IQueryParameterType theValue);
MethodOutcome update(T theResource, IdDt theId);
Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams);
DaoMethodOutcome update(T theResource);
DaoMethodOutcome update(T theResource, String theMatchUrl);
/**
* @param theCheckForForcedId If true, this method should fail if the requested ID contains
* a numeric PID which exists, but is obscured by a "forced ID" so should not exist as
* far as the outside world is concerned.
* @param thePerformIndexing
* Use with caution! If you set this to false, you need to manually perform indexing or your resources
* won't be indexed and searches won't work.
*/
BaseHasResource readEntity(IdDt theId, boolean theCheckForForcedId);
DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing);
}

View File

@ -32,9 +32,15 @@ import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
//@formatter:off
@Entity()
@Table(name = "HFJ_FORCED_ID", uniqueConstraints = { @UniqueConstraint(name = "IDX_FORCEDID", columnNames = { "FORCED_ID" }) })
@NamedQueries(@NamedQuery(name = "Q_GET_FORCED_ID", query = "SELECT f FROM ForcedId f WHERE myForcedId = :ID"))
@Table(name = "HFJ_FORCED_ID", uniqueConstraints = {
@UniqueConstraint(name = "IDX_FORCEDID", columnNames = {"FORCED_ID"})
})
@NamedQueries(value = {
@NamedQuery(name = "Q_GET_FORCED_ID", query = "SELECT f FROM ForcedId f WHERE myForcedId = :ID")
})
//@formatter:on
public class ForcedId {
public static final int MAX_FORCED_ID_LENGTH = 100;

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
@ -44,11 +45,11 @@ import javax.servlet.http.HttpServletRequest;
public class JpaConformanceProviderDstu1 extends ServerConformanceProvider {
private String myImplementationDescription;
private IFhirSystemDao mySystemDao;
private IFhirSystemDao<List<IResource>> mySystemDao;
private volatile Conformance myCachedValue;
private RestfulServer myRestfulServer;
public JpaConformanceProviderDstu1(RestfulServer theRestfulServer, IFhirSystemDao theSystemDao) {
public JpaConformanceProviderDstu1(RestfulServer theRestfulServer, IFhirSystemDao<List<IResource>> theSystemDao) {
super(theRestfulServer);
myRestfulServer = theRestfulServer;
mySystemDao = theSystemDao;

View File

@ -29,6 +29,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Conformance.Rest;
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource;
@ -44,11 +45,11 @@ import ca.uhn.fhir.util.ExtensionConstants;
public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
private String myImplementationDescription;
private IFhirSystemDao mySystemDao;
private IFhirSystemDao<Bundle> mySystemDao;
private volatile Conformance myCachedValue;
private RestfulServer myRestfulServer;
public JpaConformanceProviderDstu2(RestfulServer theRestfulServer, IFhirSystemDao theSystemDao) {
public JpaConformanceProviderDstu2(RestfulServer theRestfulServer, IFhirSystemDao<Bundle> theSystemDao) {
super(theRestfulServer);
myRestfulServer = theRestfulServer;
mySystemDao = theSystemDao;

View File

@ -162,13 +162,12 @@ public class JpaResourceProvider<T extends IResource> extends BaseJpaProvider im
public MethodOutcome update(HttpServletRequest theRequest, @ResourceParam T theResource, @IdParam IdDt theId) {
startRequest(theRequest);
try {
return myDao.update(theResource, theId);
theResource.setId(theId);
return myDao.update(theResource);
} catch (ResourceNotFoundException e) {
ourLog.info("Can't update resource with ID[" + theId.getValue() + "] because it doesn't exist, going to create it instead");
theResource.setId(theId);
MethodOutcome retVal = myDao.create(theResource);
retVal.setCreated(true);
return retVal;
return myDao.create(theResource);
} finally {
endRequest(theRequest);
}

View File

@ -1,17 +1,7 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Date;
@ -40,6 +30,7 @@ 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.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Device;
import ca.uhn.fhir.model.dstu2.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu2.resource.Encounter;
@ -47,7 +38,9 @@ import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Organization;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.dstu2.valueset.QuantityComparatorEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
@ -65,8 +58,10 @@ import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
@ -84,6 +79,150 @@ public class FhirResourceDaoTest {
private static IFhirResourceDao<Organization> ourOrganizationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
@Test
public void testCreateDuplicateIdFails() {
String methodName = "testCreateDuplocateIdFailsText";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
try {
ourPatientDao.create(p);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Can not create entity with ID[" + methodName + "], a resource with this ID already exists"));
}
}
@Test
public void testUpdateByUrl() {
String methodName = "testUpdateByUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ourPatientDao.update(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
p = ourPatientDao.read(id.toVersionless());
assertThat(p.getId().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
}
@Test
public void testCreateNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123");
try {
ourPatientDao.create(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Can not create entity with ID[123], this server does not allow clients to assign numeric IDs"));
}
}
@Test
public void testDeleteWithMatchUrl() {
String methodName = "testDeleteWithMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
Bundle request = new Bundle();
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
ourPatientDao.deleteByUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
try {
ourPatientDao.read(new IdDt("Patient/" + methodName));
fail();
} catch (ResourceNotFoundException e) {
// ok
}
IBundleProvider history = ourPatientDao.history(id, null);
assertEquals(2, history.size());
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0)));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0)).getValue());
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(1, 1).get(0)));
}
@Test
public void testCreateWithIfNoneExist() {
String methodName = "testCreateWithIfNoneExist";
MethodOutcome results;
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
results = ourPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
assertEquals(id.getIdPart(), results.getId().getIdPart());
assertFalse(results.getCreated().booleanValue());
// Now create a second one
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName + "DOESNTEXIST");
results = ourPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName + "DOESNTEXIST");
assertNotEquals(id.getIdPart(), results.getId().getIdPart());
assertTrue(results.getCreated().booleanValue());
// Now try to create one with the original match URL and it should fail
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
try {
ourPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
fail();
} catch (PreconditionFailedException e) {
assertThat(e.getMessage(), containsString("Failed to CREATE"));
}
}
@Test
public void testChoiceParamConcept() {
Observation o1 = new Observation();
@ -216,7 +355,7 @@ public class FhirResourceDaoTest {
public void testDatePeriodParamStartAndEnd() {
{
Encounter enc = new Encounter();
enc.addIdentifier().setSystem("testDatePeriodParam").setValue( "03");
enc.addIdentifier().setSystem("testDatePeriodParam").setValue("03");
enc.getPeriod().getStartElement().setValueAsString("2001-01-02");
enc.getPeriod().getEndElement().setValueAsString("2001-01-03");
ourEncounterDao.create(enc);
@ -329,7 +468,7 @@ public class FhirResourceDaoTest {
{
Patient patient = ourPatientDao.read(id2);
patient.addIdentifier().setSystem("ZZZZZZZ").setValue("ZZZZZZZZZ");
id2b = ourPatientDao.update(patient, id2).getId();
id2b = ourPatientDao.update(patient).getId();
}
ourLog.info("ID1:{} ID2:{} ID2b:{}", new Object[] { id1, id2, id2b });
@ -373,7 +512,7 @@ public class FhirResourceDaoTest {
@Test
public void testIdParam() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester").addGiven("Joe");
MethodOutcome outcome = ourPatientDao.create(patient);
@ -484,11 +623,11 @@ public class FhirResourceDaoTest {
@Test
public void testPersistResourceLink() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testPersistResourceLink01");
patient.addIdentifier().setSystem("urn:system").setValue("testPersistResourceLink01");
IdDt patientId01 = ourPatientDao.create(patient).getId();
Patient patient02 = new Patient();
patient02.addIdentifier().setSystem("urn:system").setValue( "testPersistResourceLink02");
patient02.addIdentifier().setSystem("urn:system").setValue("testPersistResourceLink02");
IdDt patientId02 = ourPatientDao.create(patient02).getId();
Observation obs01 = new Observation();
@ -524,7 +663,7 @@ public class FhirResourceDaoTest {
@Test
public void testPersistSearchParamDate() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.setBirthDate(new DateDt("2001-01-01"));
ourPatientDao.create(patient);
@ -576,7 +715,7 @@ public class FhirResourceDaoTest {
@Test
public void testPersistSearchParams() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001testPersistSearchParams");
patient.addIdentifier().setSystem("urn:system").setValue("001testPersistSearchParams");
patient.getGenderElement().setValueAsEnum(AdministrativeGenderEnum.MALE);
patient.addName().addFamily("Tester").addGiven("JoetestPersistSearchParams");
@ -641,20 +780,20 @@ public class FhirResourceDaoTest {
assertTrue(patients.size() >= 2);
}
@Test
public void testHistoryByForcedId() {
IdDt idv1;
IdDt idv2;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testHistoryByForcedId");
patient.addIdentifier().setSystem("urn:system").setValue("testHistoryByForcedId");
patient.addName().addFamily("Tester").addGiven("testHistoryByForcedId");
patient.setId("Patient/testHistoryByForcedId");
idv1 = ourPatientDao.create(patient).getId();
patient.addName().addFamily("Tester").addGiven("testHistoryByForcedIdName2");
idv2 = ourPatientDao.update(patient, idv1.toUnqualifiedVersionless()).getId();
patient.setId(patient.getId().toUnqualifiedVersionless());
idv2 = ourPatientDao.update(patient).getId();
}
List<Patient> patients = toList(ourPatientDao.history(idv1.toVersionless(), null));
@ -676,7 +815,7 @@ public class FhirResourceDaoTest {
IdDt id2;
{
Organization patient = new Organization();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
id2 = ourOrganizationDao.create(patient).getId();
}
@ -769,14 +908,14 @@ public class FhirResourceDaoTest {
IdDt id1;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("testSearchNameParam01Fam").addGiven("testSearchNameParam01Giv");
ResourceMetadataKeyEnum.TITLE.put(patient, "P1TITLE");
id1 = ourPatientDao.create(patient).getId();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "002");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("testSearchNameParam02Fam").addGiven("testSearchNameParam02Giv");
ourPatientDao.create(patient);
}
@ -816,12 +955,12 @@ public class FhirResourceDaoTest {
@Test
public void testSearchNumberParam() {
Encounter e1 = new Encounter();
e1.addIdentifier().setSystem("foo").setValue( "testSearchNumberParam01");
e1.addIdentifier().setSystem("foo").setValue("testSearchNumberParam01");
e1.getLength().setSystem(BaseFhirDao.UCUM_NS).setCode("min").setValue(4.0 * 24 * 60);
IdDt id1 = ourEncounterDao.create(e1).getId();
Encounter e2 = new Encounter();
e2.addIdentifier().setSystem("foo").setValue( "testSearchNumberParam02");
e2.addIdentifier().setSystem("foo").setValue("testSearchNumberParam02");
e2.getLength().setSystem(BaseFhirDao.UCUM_NS).setCode("year").setValue(2.0);
IdDt id2 = ourEncounterDao.create(e2).getId();
{
@ -843,13 +982,13 @@ public class FhirResourceDaoTest {
@Test
public void testSearchResourceLinkWithChain() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithChainXX");
patient.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithChain01");
patient.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithChainXX");
patient.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithChain01");
IdDt patientId01 = ourPatientDao.create(patient).getId();
Patient patient02 = new Patient();
patient02.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithChainXX");
patient02.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithChain02");
patient02.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithChainXX");
patient02.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithChain02");
IdDt patientId02 = ourPatientDao.create(patient02).getId();
Observation obs01 = new Observation();
@ -881,7 +1020,7 @@ public class FhirResourceDaoTest {
result = toList(ourObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "testSearchResourceLinkWithChainXX")));
assertEquals(2, result.size());
result = toList(ourObservationDao.search(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "|testSearchResourceLinkWithChainXX")));
assertEquals(0, result.size());
@ -891,14 +1030,14 @@ public class FhirResourceDaoTest {
public void testSearchResourceLinkWithTextLogicalId() {
Patient patient = new Patient();
patient.setId("testSearchResourceLinkWithTextLogicalId01");
patient.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithTextLogicalIdXX");
patient.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithTextLogicalId01");
patient.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithTextLogicalIdXX");
patient.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithTextLogicalId01");
IdDt patientId01 = ourPatientDao.create(patient).getId();
Patient patient02 = new Patient();
patient02.setId("testSearchResourceLinkWithTextLogicalId02");
patient02.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithTextLogicalIdXX");
patient02.addIdentifier().setSystem("urn:system").setValue( "testSearchResourceLinkWithTextLogicalId02");
patient02.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithTextLogicalIdXX");
patient02.addIdentifier().setSystem("urn:system").setValue("testSearchResourceLinkWithTextLogicalId02");
IdDt patientId02 = ourPatientDao.create(patient02).getId();
Observation obs01 = new Observation();
@ -981,13 +1120,13 @@ public class FhirResourceDaoTest {
public void testSearchStringParam() {
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester_testSearchStringParam").addGiven("Joe");
ourPatientDao.create(patient);
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "002");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("Tester_testSearchStringParam").addGiven("John");
ourPatientDao.create(patient);
}
@ -1009,7 +1148,7 @@ public class FhirResourceDaoTest {
{
Patient patient = new Patient();
patient.getLanguage().setValue("en_CA");
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("testSearchLanguageParam").addGiven("Joe");
id1 = ourPatientDao.create(patient).getId();
}
@ -1017,7 +1156,7 @@ public class FhirResourceDaoTest {
{
Patient patient = new Patient();
patient.getLanguage().setValue("en_US");
patient.addIdentifier().setSystem("urn:system").setValue( "002");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("testSearchLanguageParam").addGiven("John");
id2 = ourPatientDao.create(patient).getId();
}
@ -1048,13 +1187,13 @@ public class FhirResourceDaoTest {
public void testSearchStringParamWithNonNormalized() {
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addGiven("testSearchStringParamWithNonNormalized_h\u00F6ra");
ourPatientDao.create(patient);
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "002");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addGiven("testSearchStringParamWithNonNormalized_HORA");
ourPatientDao.create(patient);
}
@ -1081,7 +1220,7 @@ public class FhirResourceDaoTest {
ourPatientDao.create(patient);
patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testSearchTokenParam002");
patient.addIdentifier().setSystem("urn:system").setValue("testSearchTokenParam002");
patient.addName().addFamily("Tester").addGiven("testSearchTokenParam2");
ourPatientDao.create(patient);
@ -1147,14 +1286,14 @@ public class FhirResourceDaoTest {
IdDt orgId = ourOrganizationDao.create(org).getId();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester_testSearchWithIncludes_P1").addGiven("Joe");
patient.getManagingOrganization().setReference(orgId);
ourPatientDao.create(patient);
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "002");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("Tester_testSearchWithIncludes_P2").addGiven("John");
ourPatientDao.create(patient);
}
@ -1221,7 +1360,7 @@ public class FhirResourceDaoTest {
public void testStoreUtf8Characters() throws Exception {
Organization org = new Organization();
org.setName("測試醫院");
org.addIdentifier().setSystem("urn:system").setValue( "testStoreUtf8Characters_01");
org.addIdentifier().setSystem("urn:system").setValue("testStoreUtf8Characters_01");
IdDt orgId = ourOrganizationDao.create(org).getId();
Organization returned = ourOrganizationDao.read(orgId);
@ -1244,14 +1383,14 @@ public class FhirResourceDaoTest {
assertThat(orgId.getValue(), endsWith("Organization/testSearchWithIncludesThatHaveTextId_id1/_history/1"));
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester_testSearchWithIncludesThatHaveTextId_P1").addGiven("Joe");
patient.getManagingOrganization().setReference(orgId);
ourPatientDao.create(patient);
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "002");
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addFamily("Tester_testSearchWithIncludesThatHaveTextId_P2").addGiven("John");
ourPatientDao.create(patient);
}
@ -1290,23 +1429,23 @@ public class FhirResourceDaoTest {
@Test
public void testSort() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue( "testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addName().addFamily("testSortF1").addGiven("testSortG1");
IdDt id1 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
// Create out of order
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue( "testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addName().addFamily("testSortF3").addGiven("testSortG3");
IdDt id3 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue( "testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
p.addName().addFamily("testSortF2").addGiven("testSortG2");
IdDt id2 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue( "testSort001");
p.addIdentifier().setSystem("urn:system").setValue("testSort001");
IdDt id4 = ourPatientDao.create(p).getId().toUnqualifiedVersionless();
SearchParameterMap pm = new SearchParameterMap();
@ -1367,7 +1506,7 @@ public class FhirResourceDaoTest {
@Test
public void testTagsWithCreateAndReadAndSearch() {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "testTagsWithCreateAndReadAndSearch");
patient.addIdentifier().setSystem("urn:system").setValue("testTagsWithCreateAndReadAndSearch");
patient.addName().addFamily("Tester").addGiven("Joe");
TagList tagList = new TagList();
tagList.addTag(null, "Dog", "Puppies");
@ -1458,7 +1597,7 @@ public class FhirResourceDaoTest {
@Test
public void testUpdateAndGetHistoryResource() throws InterruptedException {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue( "001");
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester").addGiven("Joe");
MethodOutcome outcome = ourPatientDao.create(patient);
@ -1477,7 +1616,7 @@ public class FhirResourceDaoTest {
Thread.sleep(1000);
retrieved.getIdentifierFirstRep().setValue("002");
MethodOutcome outcome2 = ourPatientDao.update(retrieved, outcome.getId());
MethodOutcome outcome2 = ourPatientDao.update(retrieved);
assertEquals(outcome.getId().getIdPart(), outcome2.getId().getIdPart());
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
@ -1521,12 +1660,12 @@ public class FhirResourceDaoTest {
@Test
public void testUpdateMaintainsSearchParams() throws InterruptedException {
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue( "testUpdateMaintainsSearchParamsAAA");
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsAAA");
p1.addName().addFamily("Tester").addGiven("testUpdateMaintainsSearchParamsAAA");
IdDt p1id = ourPatientDao.create(p1).getId();
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue( "testUpdateMaintainsSearchParamsBBB");
p2.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsBBB");
p2.addName().addFamily("Tester").addGiven("testUpdateMaintainsSearchParamsBBB");
ourPatientDao.create(p2).getId();
@ -1536,7 +1675,7 @@ public class FhirResourceDaoTest {
// Update the name
p1.getNameFirstRep().getGivenFirstRep().setValue("testUpdateMaintainsSearchParamsBBB");
MethodOutcome update2 = ourPatientDao.update(p1, p1id);
MethodOutcome update2 = ourPatientDao.update(p1);
IdDt p1id2 = update2.getId();
ids = ourPatientDao.searchForIds(Patient.SP_GIVEN, new StringDt("testUpdateMaintainsSearchParamsAAA"));
@ -1557,21 +1696,23 @@ public class FhirResourceDaoTest {
@Test
public void testUpdateRejectsInvalidTypes() throws InterruptedException {
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue( "testUpdateRejectsInvalidTypes");
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateRejectsInvalidTypes");
p1.addName().addFamily("Tester").addGiven("testUpdateRejectsInvalidTypes");
IdDt p1id = ourPatientDao.create(p1).getId();
Organization p2 = new Organization();
p2.getNameElement().setValue("testUpdateRejectsInvalidTypes");
try {
ourOrganizationDao.update(p2, new IdDt("Organization/" + p1id.getIdPart()));
p2.setId(new IdDt("Organization/" + p1id.getIdPart()));
ourOrganizationDao.update(p2);
fail();
} catch (UnprocessableEntityException e) {
// good
}
try {
ourOrganizationDao.update(p2, new IdDt("Patient/" + p1id.getIdPart()));
p2.setId(new IdDt("Patient/" + p1id.getIdPart()));
ourOrganizationDao.update(p2);
fail();
} catch (UnprocessableEntityException e) {
// good
@ -1589,7 +1730,7 @@ public class FhirResourceDaoTest {
assertEquals("ABABA", p1id.getIdPart());
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue( "testUpdateRejectsIdWhichPointsToForcedId02");
p2.addIdentifier().setSystem("urn:system").setValue("testUpdateRejectsIdWhichPointsToForcedId02");
p2.addName().addFamily("Tester").addGiven("testUpdateRejectsIdWhichPointsToForcedId02");
IdDt p2id = ourPatientDao.create(p2).getId();
long p1longId = p2id.getIdPartAsLong() - 1;
@ -1602,7 +1743,8 @@ public class FhirResourceDaoTest {
}
try {
ourPatientDao.update(p1, new IdDt("Patient/" + p1longId));
p1.setId(new IdDt("Patient/" + p1longId));
ourPatientDao.update(p1);
fail();
} catch (ResourceNotFoundException e) {
// good
@ -1613,13 +1755,14 @@ public class FhirResourceDaoTest {
@Test
public void testReadForcedIdVersionHistory() throws InterruptedException {
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue( "testReadVorcedIdVersionHistory01");
p1.addIdentifier().setSystem("urn:system").setValue("testReadVorcedIdVersionHistory01");
p1.setId("testReadVorcedIdVersionHistory");
IdDt p1id = ourPatientDao.create(p1).getId();
assertEquals("testReadVorcedIdVersionHistory", p1id.getIdPart());
p1.addIdentifier().setSystem("urn:system").setValue( "testReadVorcedIdVersionHistory02");
IdDt p1idv2 = ourPatientDao.update(p1, p1id).getId();
p1.addIdentifier().setSystem("urn:system").setValue("testReadVorcedIdVersionHistory02");
p1.setId(p1id);
IdDt p1idv2 = ourPatientDao.update(p1).getId();
assertEquals("testReadVorcedIdVersionHistory", p1idv2.getIdPart());
assertNotEquals(p1id.getValue(), p1idv2.getValue());
@ -1652,7 +1795,7 @@ public class FhirResourceDaoTest {
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
public static void beforeClass() {
ourCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu2.xml", "fhir-jpabase-spring-test-config.xml");
ourPatientDao = ourCtx.getBean("myPatientDaoDstu2", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDaoDstu2", IFhirResourceDao.class);

View File

@ -0,0 +1,414 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class FhirSystemDaoDstu1Test {
private static ClassPathXmlApplicationContext ourCtx;
private static FhirContext ourFhirContext;
private static IFhirResourceDao<Location> ourLocationDao;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu1Test.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirSystemDao<List<IResource>> ourSystemDao;
@Test
public void testGetResourceCounts() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01");
ourObservationDao.create(obs);
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient);
Map<String, Long> newCounts = ourSystemDao.getResourceCounts();
if (oldCounts.containsKey("Patient")) {
assertEquals(oldCounts.get("Patient") + 1, (long) newCounts.get("Patient"));
} else {
assertEquals(1L, (long) newCounts.get("Patient"));
}
assertEquals((long) oldCounts.get("Observation"), (long) newCounts.get("Observation"));
}
@Test
public void testHistory() throws Exception {
Date start = new Date();
Thread.sleep(10);
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testHistory");
patient.addName().addFamily("Tester").addGiven("Joe");
IdDt pid = ourPatientDao.create(patient).getId().toVersionless();
Thread.sleep(10);
patient.setId(pid);
IdDt newpid = ourPatientDao.update(patient).getId();
Thread.sleep(10);
patient.setId(pid);
IdDt newpid2 = ourPatientDao.update(patient).getId();
Thread.sleep(10);
patient.setId(pid);
IdDt newpid3 = ourPatientDao.update(patient).getId();
IBundleProvider values = ourSystemDao.history(start);
assertEquals(4, values.size());
List<IResource> res = values.getResources(0, 4);
assertEquals(newpid3, res.get(0).getId());
assertEquals(newpid2, res.get(1).getId());
assertEquals(newpid, res.get(2).getId());
assertEquals(pid.toUnqualifiedVersionless(), res.get(3).getId().toUnqualifiedVersionless());
Location loc = new Location();
loc.getAddress().addLine("AAA");
IdDt lid = ourLocationDao.create(loc).getId();
Location loc2 = new Location();
loc2.getAddress().addLine("AAA");
ourLocationDao.create(loc2).getId();
Thread.sleep(2000);
values = ourLocationDao.history(start);
assertEquals(2, values.size());
values = ourLocationDao.history(lid.getIdPartAsLong(), start);
assertEquals(1, values.size());
}
@Test
public void testPersistWithSimpleLink() {
Patient patient = new Patient();
patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01"));
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
patient.addName().addFamily("Tester").addGiven("Joe");
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01"));
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId = (patient.getId().getIdPart());
String obsId = (obs.getId().getIdPart());
// assertThat(patientId, greaterThan(0L));
// assertEquals(patientVersion, 1L);
// assertThat(obsId, greaterThan(patientId));
// assertEquals(obsVersion, 1L);
// Try to search
IBundleProvider obsResults = ourObservationDao.search(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01"));
assertEquals(1, obsResults.size());
IBundleProvider patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01"));
assertEquals(1, obsResults.size());
IdDt foundPatientId = patResults.getResources(0, 1).get(0).getId();
ResourceReferenceDt subject = obs.getSubject();
assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart());
// Update
patient = (Patient) patResults.getResources(0, 1).get(0);
obs = (Observation) obsResults.getResources(0, 1).get(0);
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId2 = (patient.getId().getIdPart());
String patientVersion2 = (patient.getId().getVersionIdPart());
String obsId2 = (obs.getId().getIdPart());
String obsVersion2 = (obs.getId().getVersionIdPart());
assertEquals(patientId, patientId2);
assertEquals(patientVersion2, "2");
assertEquals(obsId, obsId2);
assertEquals(obsVersion2, "2");
}
@Test
public void testPersistWithUnknownId() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/999998888888"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject"));
}
obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject"));
}
}
@Test
public void testTagOperationss() throws Exception {
TagList preSystemTl = ourSystemDao.getAllTags();
TagList tl1 = new TagList();
tl1.addTag("testGetAllTagsScheme1", "testGetAllTagsTerm1", "testGetAllTagsLabel1");
Patient p1 = new Patient();
p1.addIdentifier().setSystem("foo").setValue("testGetAllTags01");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, tl1);
ourPatientDao.create(p1);
TagList tl2 = new TagList();
tl2.addTag("testGetAllTagsScheme2", "testGetAllTagsTerm2", "testGetAllTagsLabel2");
Observation o1 = new Observation();
o1.getName().setText("testGetAllTags02");
ResourceMetadataKeyEnum.TAG_LIST.put(o1, tl2);
IdDt o1id = ourObservationDao.create(o1).getId();
assertTrue(o1id.getVersionIdPart() != null);
TagList postSystemTl = ourSystemDao.getAllTags();
assertEquals(preSystemTl.size() + 2, postSystemTl.size());
assertEquals("testGetAllTagsLabel1", postSystemTl.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel());
TagList tags = ourPatientDao.getAllResourceTags();
assertEquals("testGetAllTagsLabel1", tags.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel());
assertNull(tags.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
TagList tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel());
o1.getResourceMetadata().remove(ResourceMetadataKeyEnum.TAG_LIST);
o1.setId(o1id);
IdDt o1id2 = ourObservationDao.update(o1).getId();
assertTrue(o1id2.getVersionIdPart() != null);
tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel());
tags2 = ourObservationDao.getTags(o1id2);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
/*
* Remove a tag from a version
*/
ourObservationDao.removeTag(o1id2, "testGetAllTagsScheme2", "testGetAllTagsTerm2");
tags2 = ourObservationDao.getTags(o1id2);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
/*
* Add a tag
*/
ourObservationDao.addTag(o1id2, "testGetAllTagsScheme3", "testGetAllTagsTerm3", "testGetAllTagsLabel3");
tags2 = ourObservationDao.getTags(o1id2);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
assertNotNull(tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3"));
assertEquals("testGetAllTagsLabel3", tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3").getLabel());
tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
}
@Test(expected = InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() {
Patient patient1 = new Patient();
patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient1.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
Patient patient2 = new Patient();
patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
ourSystemDao.transaction(Arrays.asList((IResource) patient1, patient2));
}
@Test
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = FhirSystemDaoDstu1Test.class.getResourceAsStream("/bundle-dstu1.xml");
Bundle bundle = ourFhirContext.newXmlParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourSystemDao.transaction(res);
Patient p1 = (Patient) res.get(0);
String id = p1.getId().getValue();
ourLog.info("ID: {}", id);
assertThat(id, not(equalToIgnoringCase("74635")));
assertThat(id, not(equalToIgnoringCase("")));
}
/**
* Issue #55
*/
@Test
public void testTransactionWithCidIds() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
res.add(p1);
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02");
o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o1);
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03");
o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o2);
ourSystemDao.transaction(res);
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
}
@Test
public void testTransactionWithDelete() throws Exception {
/*
* Create 3
*/
List<IResource> res;
res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p1);
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p2);
Patient p3 = new Patient();
p3.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p3);
ourSystemDao.transaction(res);
/*
* Verify
*/
IBundleProvider results = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete"));
assertEquals(3, results.size());
/*
* Now delete 2
*/
res = new ArrayList<IResource>();
List<IResource> existing = results.getResources(0, 3);
p1 = new Patient();
p1.setId(existing.get(0).getId());
ResourceMetadataKeyEnum.DELETED_AT.put(p1, InstantDt.withCurrentTime());
res.add(p1);
p2 = new Patient();
p2.setId(existing.get(1).getId());
ResourceMetadataKeyEnum.DELETED_AT.put(p2, InstantDt.withCurrentTime());
res.add(p2);
ourSystemDao.transaction(res);
/*
* Verify
*/
IBundleProvider results2 = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete"));
assertEquals(1, results2.size());
List<IResource> existing2 = results2.getResources(0, 1);
assertEquals(existing2.get(0).getId(), existing.get(2).getId());
}
@AfterClass
public static void afterClass() {
ourCtx.close();
}
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
ourCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu1.xml", "fhir-jpabase-spring-test-config.xml");
ourFhirContext = ourCtx.getBean(FhirContext.class);
ourPatientDao = ourCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
ourLocationDao = ourCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
ourSystemDao = ourCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
}
}

View File

@ -0,0 +1,680 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.hamcrest.Matchers;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Location;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
public class FhirSystemDaoDstu2Test {
private static ClassPathXmlApplicationContext ourCtx;
private static FhirContext ourFhirContext;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2Test.class);
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirSystemDao<Bundle> ourSystemDao;
private static IFhirResourceDao<Observation> ourObservationDao;
@Test
public void testTransactionCreateMatchUrlWithOneMatch() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(3, resp.getEntry().size());
Entry respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_200_OK + "", respEntry.getTransactionResponse().getStatus());
assertThat(respEntry.getTransactionResponse().getLocation(), endsWith("Patient/" + id.getIdPart() + "/_history/1"));
assertEquals("1", respEntry.getTransactionResponse().getEtag().get(0).getValue());
respEntry = resp.getEntry().get(2);
assertEquals(Constants.STATUS_HTTP_201_CREATED + "", respEntry.getTransactionResponse().getStatus());
assertThat(respEntry.getTransactionResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getTransactionResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getTransactionResponse().getEtag().get(0).getValue());
o = (Observation) ourObservationDao.read(new IdDt(respEntry.getTransactionResponse().getLocationElement()));
assertEquals(id.toVersionless(), o.getSubject().getReference());
assertEquals("1", o.getId().getVersionIdPart());
}
@Test
public void testTransactionReadAndSearch() {
String methodName = "testTransactionReadAndSearch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt idv1 = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got id: {}", idv1);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Family Name");
p.setId("Patient/" + methodName);
IdDt idv2 = ourPatientDao.update(p).getId();
ourLog.info("Updated patient, got id: {}", idv2);
Bundle request = new Bundle();
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue());
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualified().getValue());
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.GET).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(4, resp.getEntry().size());
Entry nextEntry;
nextEntry = resp.getEntry().get(1);
assertEquals(Patient.class, nextEntry.getResource().getClass());
assertEquals(idv2.toUnqualified(), nextEntry.getResource().getId().toUnqualified());
nextEntry = resp.getEntry().get(2);
assertEquals(Patient.class, nextEntry.getResource().getClass());
assertEquals(idv1.toUnqualified(), nextEntry.getResource().getId().toUnqualified());
nextEntry = resp.getEntry().get(3);
assertEquals(Bundle.class, nextEntry.getResource().getClass());
Bundle respBundle = (Bundle) nextEntry.getResource();
assertEquals(1, respBundle.getTotal().intValue());
}
@Test
public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
Bundle request = new Bundle();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
try {
ourSystemDao.transaction(request);
fail();
} catch (PreconditionFailedException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionCreateMatchUrlWithZeroMatch() {
String methodName = "testTransactionCreateMatchUrlWithZeroMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(3, resp.getEntry().size());
Entry respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + "", respEntry.getTransactionResponse().getStatus());
String patientId = respEntry.getTransactionResponse().getLocation();
assertThat(patientId, not(endsWith("Patient/" + methodName + "/_history/1")));
assertThat(patientId, (endsWith("/_history/1")));
assertThat(patientId, (containsString("Patient/")));
assertEquals("1", respEntry.getTransactionResponse().getEtag().get(0).getValue());
respEntry = resp.getEntry().get(2);
assertEquals(Constants.STATUS_HTTP_201_CREATED + "", respEntry.getTransactionResponse().getStatus());
assertThat(respEntry.getTransactionResponse().getLocation(), containsString("Observation/"));
assertThat(respEntry.getTransactionResponse().getLocation(), endsWith("/_history/1"));
assertEquals("1", respEntry.getTransactionResponse().getEtag().get(0).getValue());
o = (Observation) ourObservationDao.read(new IdDt(respEntry.getTransactionResponse().getLocationElement()));
assertEquals(new IdDt(patientId).toUnqualifiedVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionCreateNoMatchUrl() {
String methodName = "testTransactionCreateNoMatchUrl";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(2, resp.getEntry().size());
Entry respEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + "", respEntry.getTransactionResponse().getStatus());
String patientId = respEntry.getTransactionResponse().getLocation();
assertThat(patientId, not(containsString("test")));
}
@Test
public void testTransactionDeleteMatchUrlWithOneMatch() {
String methodName = "testTransactionDeleteMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
Bundle request = new Bundle();
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(2, resp.getEntry().size());
Entry nextEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_204_NO_CONTENT + "", nextEntry.getTransactionResponse().getStatus());
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
try {
ourPatientDao.read(new IdDt("Patient/" + methodName));
fail();
} catch (ResourceNotFoundException e) {
// ok
}
IBundleProvider history = ourPatientDao.history(id, null);
assertEquals(2, history.size());
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0)));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(0, 0).get(0)).getValue());
assertNull(ResourceMetadataKeyEnum.DELETED_AT.get(history.getResources(1, 1).get(0)));
}
@Test
public void testTransactionDeleteMatchUrlWithTwoMatch() {
String methodName = "testTransactionDeleteMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
Bundle request = new Bundle();
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
try {
ourSystemDao.transaction(request);
fail();
} catch (ResourceNotFoundException e) {
assertThat(e.getMessage(), containsString("resource with match URL \"Patient?"));
}
}
@Test
public void testTransactionDeleteByResourceId() {
String methodName = "testTransactionDeleteByResourceId";
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id1 = ourPatientDao.create(p1).getId();
ourLog.info("Created patient, got it: {}", id1);
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue(methodName);
p2.setId("Patient/" + methodName);
IdDt id2 = ourPatientDao.create(p2).getId();
ourLog.info("Created patient, got it: {}", id2);
Bundle request = new Bundle();
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient/" + id1.getIdPart());
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient/" + id2.getIdPart());
ourPatientDao.read(id1.toVersionless());
ourPatientDao.read(id2.toVersionless());
Bundle resp = ourSystemDao.transaction(request);
assertEquals(3, resp.getEntry().size());
assertEquals("204", resp.getEntry().get(1).getTransactionResponse().getStatus());
assertEquals("204", resp.getEntry().get(2).getTransactionResponse().getStatus());
try {
ourPatientDao.read(id1.toVersionless());
fail();
} catch (ResourceGoneException e) {
// good
}
try {
ourPatientDao.read(id2.toVersionless());
fail();
} catch (ResourceGoneException e) {
// good
}
}
@Test
public void testTransactionDeleteMatchUrlWithZeroMatch() {
String methodName = "testTransactionDeleteMatchUrlWithZeroMatch";
Bundle request = new Bundle();
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
try {
ourSystemDao.transaction(request);
fail();
} catch (ResourceNotFoundException e) {
assertThat(e.getMessage(), containsString("resource matching URL \"Patient?"));
}
}
@Test
public void testTransactionDeleteNoMatchUrl() {
String methodName = "testTransactionDeleteNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
Bundle request = new Bundle();
request.addEntry().getTransaction().setMethod(HTTPVerbEnum.DELETE).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
Bundle res = ourSystemDao.transaction(request);
assertEquals(2, res.getEntry().size());
assertEquals(Constants.STATUS_HTTP_204_NO_CONTENT + "", res.getEntry().get(1).getTransactionResponse().getStatus());
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
}
@Test(expected = InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() {
Bundle request = new Bundle();
Patient patient1 = new Patient();
patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient1.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
request.addEntry().setResource(patient1).getTransaction().setMethod(HTTPVerbEnum.POST);
Patient patient2 = new Patient();
patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
request.addEntry().setResource(patient2).getTransaction().setMethod(HTTPVerbEnum.POST);
ourSystemDao.transaction(request);
}
@Test
public void testTransactionUpdateMatchUrlWithOneMatch() {
String methodName = "testTransactionUpdateMatchUrlWithOneMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.PUT).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(3, resp.getEntry().size());
Entry nextEntry = resp.getEntry().get(1);
assertEquals("200", nextEntry.getTransactionResponse().getStatus());
assertThat(nextEntry.getTransactionResponse().getLocation(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
nextEntry = resp.getEntry().get(1);
assertEquals("" + Constants.STATUS_HTTP_200_OK, nextEntry.getTransactionResponse().getStatus());
assertThat(nextEntry.getTransactionResponse().getLocation(), not(emptyString()));
nextEntry = resp.getEntry().get(2);
o = ourObservationDao.read(new IdDt(nextEntry.getTransactionResponse().getLocation()));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateMatchUrlWithTwoMatch() {
String methodName = "testTransactionUpdateMatchUrlWithTwoMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.PUT).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
try {
ourSystemDao.transaction(request);
fail();
} catch (PreconditionFailedException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionUpdateMatchUrlWithZeroMatch() {
String methodName = "testTransactionUpdateMatchUrlWithZeroMatch";
Bundle request = new Bundle();
Patient p = new Patient();
p.addName().addFamily("Hello");
IdDt id = ourPatientDao.create(p).getId();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId(id);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.PUT).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference(id);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(3, resp.getEntry().size());
Entry nextEntry = resp.getEntry().get(1);
assertEquals(Constants.STATUS_HTTP_201_CREATED + "", nextEntry.getTransactionResponse().getStatus());
assertThat(nextEntry.getTransactionResponse().getLocation(), not(containsString("test")));
assertNotEquals(id.toVersionless(), new IdDt(nextEntry.getTransactionResponse().getLocation()).toVersionless());
assertThat(nextEntry.getTransactionResponse().getLocation(), endsWith("/_history/1"));
nextEntry = resp.getEntry().get(1);
assertEquals("" + Constants.STATUS_HTTP_201_CREATED, nextEntry.getTransactionResponse().getStatus());
nextEntry = resp.getEntry().get(2);
o = ourObservationDao.read(new IdDt(nextEntry.getTransactionResponse().getLocation()));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateNoMatchUrl() {
String methodName = "testTransactionUpdateNoMatchUrl";
Bundle request = new Bundle();
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
request.addEntry().setResource(p).getTransaction().setMethod(HTTPVerbEnum.PUT).setUrl("Patient/" + id.getIdPart());
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
request.addEntry().setResource(o).getTransaction().setMethod(HTTPVerbEnum.POST);
Bundle resp = ourSystemDao.transaction(request);
assertEquals(3, resp.getEntry().size());
Entry nextEntry = resp.getEntry().get(1);
assertEquals("200", nextEntry.getTransactionResponse().getStatus());
assertThat(nextEntry.getTransactionResponse().getLocation(), (containsString("test")));
assertEquals(id.toVersionless(), new IdDt(nextEntry.getTransactionResponse().getLocation()).toVersionless());
assertNotEquals(id, new IdDt(nextEntry.getTransactionResponse().getLocation()));
assertThat(nextEntry.getTransactionResponse().getLocation(), endsWith("/_history/2"));
nextEntry = resp.getEntry().get(2);
assertEquals("" + Constants.STATUS_HTTP_201_CREATED, nextEntry.getTransactionResponse().getStatus());
o = ourObservationDao.read(new IdDt(resp.getEntry().get(2).getTransactionResponse().getLocation()));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
//
//
// /**
// * Issue #55
// */
// @Test
// public void testTransactionWithCidIds() throws Exception {
// Bundle request = new Bundle();
//
// Patient p1 = new Patient();
// p1.setId("cid:patient1");
// p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
// res.add(p1);
//
// Observation o1 = new Observation();
// o1.setId("cid:observation1");
// o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02");
// o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
// res.add(o1);
//
// Observation o2 = new Observation();
// o2.setId("cid:observation2");
// o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03");
// o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
// res.add(o2);
//
// ourSystemDao.transaction(res);
//
// assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
// assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
// assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
//
// assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
// assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
//
// }
//
// @Test
// public void testTransactionWithDelete() throws Exception {
// Bundle request = new Bundle();
//
// /*
// * Create 3
// */
//
// List<IResource> res;
// res = new ArrayList<IResource>();
//
// Patient p1 = new Patient();
// p1.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
// res.add(p1);
//
// Patient p2 = new Patient();
// p2.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
// res.add(p2);
//
// Patient p3 = new Patient();
// p3.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
// res.add(p3);
//
// ourSystemDao.transaction(res);
//
// /*
// * Verify
// */
//
// IBundleProvider results = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system",
// "testTransactionWithDelete"));
// assertEquals(3, results.size());
//
// /*
// * Now delete 2
// */
//
// request = new Bundle();
// res = new ArrayList<IResource>();
// List<IResource> existing = results.getResources(0, 3);
//
// p1 = new Patient();
// p1.setId(existing.get(0).getId());
// ResourceMetadataKeyEnum.DELETED_AT.put(p1, InstantDt.withCurrentTime());
// res.add(p1);
//
// p2 = new Patient();
// p2.setId(existing.get(1).getId());
// ResourceMetadataKeyEnum.DELETED_AT.put(p2, InstantDt.withCurrentTime());
// res.add(p2);
//
// ourSystemDao.transaction(res);
//
// /*
// * Verify
// */
//
// IBundleProvider results2 = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system",
// "testTransactionWithDelete"));
// assertEquals(1, results2.size());
// List<IResource> existing2 = results2.getResources(0, 1);
// assertEquals(existing2.get(0).getId(), existing.get(2).getId());
//
// }
@AfterClass
public static void afterClass() {
ourCtx.close();
}
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
ourCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu2.xml", "fhir-jpabase-spring-test-config.xml");
ourFhirContext = ourCtx.getBean(FhirContext.class);
assertEquals(FhirVersionEnum.DSTU2, ourFhirContext.getVersion().getVersion());
ourPatientDao = ourCtx.getBean("myPatientDaoDstu2", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDaoDstu2", IFhirResourceDao.class);
ourSystemDao = ourCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
}
}

View File

@ -1,899 +0,0 @@
package ca.uhn.fhir.jpa.dao;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.composite.QuantityDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionOperationEnum;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
public class FhirSystemDaoTest {
private static ClassPathXmlApplicationContext ourCtx;
private static FhirContext ourFhirContext;
private static IFhirResourceDao<Location> ourLocationDao;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoTest.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirSystemDao<List<IResource>> ourSystemDao;
@Test
public void testGetResourceCounts() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testGetResourceCountsO01");
ourObservationDao.create(obs);
Map<String, Long> oldCounts = ourSystemDao.getResourceCounts();
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testGetResourceCountsP01");
patient.addName().addFamily("Tester").addGiven("Joe");
ourPatientDao.create(patient);
Map<String, Long> newCounts = ourSystemDao.getResourceCounts();
if (oldCounts.containsKey("Patient")) {
assertEquals(oldCounts.get("Patient") + 1, (long) newCounts.get("Patient"));
} else {
assertEquals(1L, (long) newCounts.get("Patient"));
}
assertEquals((long) oldCounts.get("Observation"), (long) newCounts.get("Observation"));
}
@Test
public void testHistory() throws Exception {
Date start = new Date();
Thread.sleep(10);
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("testHistory");
patient.addName().addFamily("Tester").addGiven("Joe");
IdDt pid = ourPatientDao.create(patient).getId().toVersionless();
Thread.sleep(10);
IdDt newpid = ourPatientDao.update(patient, pid).getId();
Thread.sleep(10);
IdDt newpid2 = ourPatientDao.update(patient, pid).getId();
Thread.sleep(10);
IdDt newpid3 = ourPatientDao.update(patient, pid).getId();
IBundleProvider values = ourSystemDao.history(start);
assertEquals(4, values.size());
List<IResource> res = values.getResources(0, 4);
assertEquals(newpid3, res.get(0).getId());
assertEquals(newpid2, res.get(1).getId());
assertEquals(newpid, res.get(2).getId());
assertEquals(pid.toUnqualifiedVersionless(), res.get(3).getId().toUnqualifiedVersionless());
Location loc = new Location();
loc.getAddress().addLine("AAA");
IdDt lid = ourLocationDao.create(loc).getId();
Location loc2 = new Location();
loc2.getAddress().addLine("AAA");
ourLocationDao.create(loc2).getId();
Thread.sleep(2000);
values = ourLocationDao.history(start);
assertEquals(2, values.size());
values = ourLocationDao.history(lid.getIdPartAsLong(), start);
assertEquals(1, values.size());
}
@Test
public void testPersistWithSimpleLink() {
Patient patient = new Patient();
patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01"));
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
patient.addName().addFamily("Tester").addGiven("Joe");
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01"));
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId = (patient.getId().getIdPart());
String obsId = (obs.getId().getIdPart());
// assertThat(patientId, greaterThan(0L));
// assertEquals(patientVersion, 1L);
// assertThat(obsId, greaterThan(patientId));
// assertEquals(obsVersion, 1L);
// Try to search
IBundleProvider obsResults = ourObservationDao.search(Observation.SP_NAME, new IdentifierDt("urn:system", "testPersistWithSimpleLinkO01"));
assertEquals(1, obsResults.size());
IBundleProvider patResults = ourPatientDao.search(Patient.SP_IDENTIFIER, new IdentifierDt("urn:system", "testPersistWithSimpleLinkP01"));
assertEquals(1, obsResults.size());
IdDt foundPatientId = patResults.getResources(0, 1).get(0).getId();
ResourceReferenceDt subject = obs.getSubject();
assertEquals(foundPatientId.getIdPart(), subject.getReference().getIdPart());
// Update
patient = (Patient) patResults.getResources(0, 1).get(0);
obs = (Observation) obsResults.getResources(0, 1).get(0);
patient.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO02");
ourSystemDao.transaction(Arrays.asList((IResource) patient, obs));
String patientId2 = (patient.getId().getIdPart());
String patientVersion2 = (patient.getId().getVersionIdPart());
String obsId2 = (obs.getId().getIdPart());
String obsVersion2 = (obs.getId().getVersionIdPart());
assertEquals(patientId, patientId2);
assertEquals(patientVersion2, "2");
assertEquals(obsId, obsId2);
assertEquals(obsVersion2, "2");
}
@Test
public void testPersistWithUnknownId() {
Observation obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/999998888888"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/999998888888 not found, specified in path: Observation.subject"));
}
obs = new Observation();
obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01");
obs.setSubject(new ResourceReferenceDt("Patient/1.2.3.4"));
try {
ourSystemDao.transaction(Arrays.asList((IResource) obs));
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Resource Patient/1.2.3.4 not found, specified in path: Observation.subject"));
}
}
@Test
public void testTagOperationss() throws Exception {
TagList preSystemTl = ourSystemDao.getAllTags();
TagList tl1 = new TagList();
tl1.addTag("testGetAllTagsScheme1", "testGetAllTagsTerm1", "testGetAllTagsLabel1");
Patient p1 = new Patient();
p1.addIdentifier().setSystem("foo").setValue("testGetAllTags01");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, tl1);
ourPatientDao.create(p1);
TagList tl2 = new TagList();
tl2.addTag("testGetAllTagsScheme2", "testGetAllTagsTerm2", "testGetAllTagsLabel2");
Observation o1 = new Observation();
o1.getName().setText("testGetAllTags02");
ResourceMetadataKeyEnum.TAG_LIST.put(o1, tl2);
IdDt o1id = ourObservationDao.create(o1).getId();
assertTrue(o1id.getVersionIdPart() != null);
TagList postSystemTl = ourSystemDao.getAllTags();
assertEquals(preSystemTl.size() + 2, postSystemTl.size());
assertEquals("testGetAllTagsLabel1", postSystemTl.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel());
TagList tags = ourPatientDao.getAllResourceTags();
assertEquals("testGetAllTagsLabel1", tags.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1").getLabel());
assertNull(tags.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
TagList tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel());
o1.getResourceMetadata().remove(ResourceMetadataKeyEnum.TAG_LIST);
IdDt o1id2 = ourObservationDao.update(o1, o1id).getId();
assertTrue(o1id2.getVersionIdPart() != null);
tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertEquals("testGetAllTagsLabel2", tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2").getLabel());
tags2 = ourObservationDao.getTags(o1id2);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
/*
* Remove a tag from a version
*/
ourObservationDao.removeTag(o1id2, "testGetAllTagsScheme2", "testGetAllTagsTerm2");
tags2 = ourObservationDao.getTags(o1id2);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
/*
* Add a tag
*/
ourObservationDao.addTag(o1id2, "testGetAllTagsScheme3", "testGetAllTagsTerm3", "testGetAllTagsLabel3");
tags2 = ourObservationDao.getTags(o1id2);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
assertNotNull(tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3"));
assertEquals("testGetAllTagsLabel3", tags2.getTag("testGetAllTagsScheme3", "testGetAllTagsTerm3").getLabel());
tags2 = ourObservationDao.getTags(o1id);
assertNull(tags2.getTag("testGetAllTagsScheme1", "testGetAllTagsTerm1"));
assertNotNull(tags2.getTag("testGetAllTagsScheme2", "testGetAllTagsTerm2"));
}
@Test
public void testTransactionCreateMatchUrlWithOneMatch() {
String methodName = "testTransactionCreateMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.NOOP, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertEquals(id, p.getId());
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionCreateMatchUrlWithTwoMatch() {
String methodName = "testTransactionCreateMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
try {
ourSystemDao.transaction(Arrays.asList((IResource) p, o));
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionCreateMatchUrlWithZeroMatch() {
String methodName = "testTransactionCreateMatchUrlWithZeroMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().getIdPart(), not(containsString("test")));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(p.getId().toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionCreateNoMatchUrl() {
String methodName = "testTransactionCreateNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.CREATE);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().getIdPart(), not(containsString("test")));
}
@Test
public void testTransactionDeleteMatchUrlWithOneMatch() {
String methodName = "testTransactionDeleteMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
try {
ourPatientDao.read(new IdDt("Patient/" + methodName));
fail();
} catch (ResourceNotFoundException e) {
// ok
}
}
@Test
public void testTransactionDeleteMatchUrlWithTwoMatch() {
String methodName = "testTransactionDeleteMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
try {
ourSystemDao.transaction(Arrays.asList((IResource) p, o));
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionDeleteMatchUrlWithZeroMatch() {
String methodName = "testTransactionDeleteMatchUrlWithZeroMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName + "ZZZ");
p.addName().addFamily("Hello");
IdDt id = ourPatientDao.create(p).getId();
p = new Patient();
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
IdDt id2 = ourPatientDao.create(p).getId();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), (containsString("test")));
assertThat(p.getId().toString(), endsWith("/_history/2"));
assertEquals(id2.toVersionless(), p.getId().toVersionless());
assertNotEquals(id2, p.getId());
try {
ourPatientDao.read(id2.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
Patient found = ourPatientDao.read(id);
assertEquals(id, found.getId());
}
@Test
public void testTransactionDeleteNoMatchUrl() {
String methodName = "testTransactionDeleteNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.DELETE);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p));
assertEquals(2, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.DELETE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertNotNull(ResourceMetadataKeyEnum.DELETED_AT.get(p).getValue());
try {
ourPatientDao.read(id.toVersionless());
fail();
} catch (ResourceGoneException e) {
// ok
}
}
@Test(expected = InvalidRequestException.class)
public void testTransactionFailsWithDuplicateIds() {
Patient patient1 = new Patient();
patient1.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient1.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP01");
Patient patient2 = new Patient();
patient2.setId(new IdDt("Patient/testTransactionFailsWithDusplicateIds"));
patient2.addIdentifier().setSystem("urn:system").setValue("testPersistWithSimpleLinkP02");
ourSystemDao.transaction(Arrays.asList((IResource) patient1, patient2));
}
// @Test TODO: re-enable
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = FhirSystemDaoTest.class.getResourceAsStream("/bundle.json");
Bundle bundle = ourFhirContext.newJsonParser().parseBundle(new InputStreamReader(bundleRes));
List<IResource> res = bundle.toListOfResources();
ourSystemDao.transaction(res);
Patient p1 = (Patient) res.get(0);
String id = p1.getId().getValue();
ourLog.info("ID: {}", id);
assertThat(id, not(containsString("5556918")));
assertThat(id, not(equalToIgnoringCase("")));
}
@Test
public void testTransactionUpdateMatchUrlWithOneMatch() {
String methodName = "testTransactionUpdateMatchUrlWithOneMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateMatchUrlWithTwoMatch() {
String methodName = "testTransactionUpdateMatchUrlWithTwoMatch";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
try {
ourSystemDao.transaction(Arrays.asList((IResource) p, o));
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("with match URL \"Patient"));
}
}
@Test
public void testTransactionUpdateMatchUrlWithZeroMatch() {
String methodName = "testTransactionUpdateMatchUrlWithZeroMatch";
Patient p = new Patient();
p.addName().addFamily("Hello");
IdDt id = ourPatientDao.create(p).getId();
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId(id);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference(id);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(p.getId().toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateMatchUrlWithZeroMatchAndNotPreExisting() {
String methodName = "testTransactionUpdateMatchUrlWithZeroMatchAndNotPreExisting";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
ResourceMetadataKeyEnum.LINK_SEARCH.put(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), containsString("test"));
assertThat(p.getId().toString(), endsWith("/_history/1"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(p.getId().toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateNoMatchUrl() {
String methodName = "testTransactionUpdateNoMatchUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.setId("Patient/" + methodName);
IdDt id = ourPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.put(p, BundleEntryTransactionOperationEnum.UPDATE);
Observation o = new Observation();
o.getName().setText("Some Observation");
o.getSubject().setReference("Patient/" + methodName);
List<IResource> resp = ourSystemDao.transaction(Arrays.asList((IResource) p, o));
assertEquals(3, resp.size());
p = (Patient) resp.get(1);
assertEquals(BundleEntryTransactionOperationEnum.UPDATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(p));
assertThat(p.getId().toVersionless().toString(), containsString("test"));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
o = (Observation) resp.get(2);
assertEquals(BundleEntryTransactionOperationEnum.CREATE, ResourceMetadataKeyEnum.ENTRY_TRANSACTION_OPERATION.get(o));
assertEquals(id.toVersionless(), o.getSubject().getReference());
}
@Test
public void testTransactionUpdateNoOperationSpecified() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.getId().setValue("testTransactionWithUpdateXXX01");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithUpdate01");
res.add(p1);
Observation p2 = new Observation();
p2.getId().setValue("testTransactionWithUpdateXXX02");
p2.getIdentifier().setSystem("system").setValue("testTransactionWithUpdate02");
p2.setSubject(new ResourceReferenceDt("Patient/testTransactionWithUpdateXXX01"));
res.add(p2);
ourSystemDao.transaction(res);
assertFalse(p1.getId().isEmpty());
assertFalse(p2.getId().isEmpty());
assertEquals("testTransactionWithUpdateXXX01", p1.getId().getIdPart());
assertEquals("testTransactionWithUpdateXXX02", p2.getId().getIdPart());
assertNotEquals("testTransactionWithUpdateXXX01", p1.getId().getVersionIdPart());
assertNotEquals("testTransactionWithUpdateXXX02", p2.getId().getVersionIdPart());
assertEquals(p1.getId().toUnqualified().toVersionless(), p2.getSubject().getReference());
IdDt p1id = p1.getId().toUnqualified().toVersionless();
IdDt p1idWithVer = p1.getId().toUnqualified();
IdDt p2id = p2.getId().toUnqualified().toVersionless();
IdDt p2idWithVer = p2.getId().toUnqualified();
/*
* Make some changes
*/
res = new ArrayList<IResource>();
p1 = new Patient();
p1.getId().setValue("testTransactionWithUpdateXXX01");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithUpdate01");
p1.addName().addFamily("Name1");
res.add(p1);
p2 = new Observation();
p2.getId().setValue("testTransactionWithUpdateXXX02");
p2.getIdentifier().setSystem("system").setValue("testTransactionWithUpdate02");
p2.setSubject(new ResourceReferenceDt("Patient/testTransactionWithUpdateXXX01"));
p2.addReferenceRange().setHigh(new QuantityDt(123L));
res.add(p2);
List<IResource> results = ourSystemDao.transaction(res);
assertEquals(p1id, results.get(1).getId().toUnqualified().toVersionless());
assertEquals(p2id, results.get(2).getId().toUnqualified().toVersionless());
assertNotEquals(p1idWithVer, results.get(1).getId().toUnqualified());
assertNotEquals(p2idWithVer, results.get(2).getId().toUnqualified());
}
/**
* Issue #55
*/
@Test
public void testTransactionWithCidIds() throws Exception {
List<IResource> res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.setId("cid:patient1");
p1.addIdentifier().setSystem("system").setValue("testTransactionWithCidIds01");
res.add(p1);
Observation o1 = new Observation();
o1.setId("cid:observation1");
o1.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds02");
o1.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o1);
Observation o2 = new Observation();
o2.setId("cid:observation2");
o2.getIdentifier().setSystem("system").setValue("testTransactionWithCidIds03");
o2.setSubject(new ResourceReferenceDt("Patient/cid:patient1"));
res.add(o2);
ourSystemDao.transaction(res);
assertTrue(p1.getId().getValue(), p1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o1.getId().getValue(), o1.getId().getIdPart().matches("^[0-9]+$"));
assertTrue(o2.getId().getValue(), o2.getId().getIdPart().matches("^[0-9]+$"));
assertThat(o1.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
assertThat(o2.getSubject().getReference().getValue(), endsWith("Patient/" + p1.getId().getIdPart()));
}
@Test
public void testTransactionWithDelete() throws Exception {
/*
* Create 3
*/
List<IResource> res;
res = new ArrayList<IResource>();
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p1);
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p2);
Patient p3 = new Patient();
p3.addIdentifier().setSystem("urn:system").setValue("testTransactionWithDelete");
res.add(p3);
ourSystemDao.transaction(res);
/*
* Verify
*/
IBundleProvider results = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete"));
assertEquals(3, results.size());
/*
* Now delete 2
*/
res = new ArrayList<IResource>();
List<IResource> existing = results.getResources(0, 3);
p1 = new Patient();
p1.setId(existing.get(0).getId());
ResourceMetadataKeyEnum.DELETED_AT.put(p1, InstantDt.withCurrentTime());
res.add(p1);
p2 = new Patient();
p2.setId(existing.get(1).getId());
ResourceMetadataKeyEnum.DELETED_AT.put(p2, InstantDt.withCurrentTime());
res.add(p2);
ourSystemDao.transaction(res);
/*
* Verify
*/
IBundleProvider results2 = ourPatientDao.search(Patient.SP_IDENTIFIER, new TokenParam("urn:system", "testTransactionWithDelete"));
assertEquals(1, results2.size());
List<IResource> existing2 = results2.getResources(0, 1);
assertEquals(existing2.get(0).getId(), existing.get(2).getId());
}
@AfterClass
public static void afterClass() {
ourCtx.close();
}
@SuppressWarnings("unchecked")
@BeforeClass
public static void beforeClass() {
ourCtx = new ClassPathXmlApplicationContext("hapi-fhir-server-resourceproviders-dstu1.xml", "fhir-jpabase-spring-test-config.xml");
ourFhirContext = ourCtx.getBean(FhirContext.class);
ourPatientDao = ourCtx.getBean("myPatientDaoDstu1", IFhirResourceDao.class);
ourObservationDao = ourCtx.getBean("myObservationDaoDstu1", IFhirResourceDao.class);
ourLocationDao = ourCtx.getBean("myLocationDaoDstu1", IFhirResourceDao.class);
ourSystemDao = ourCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
}
}

View File

@ -19,7 +19,6 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;

File diff suppressed because one or more lines are too long

View File

@ -9,6 +9,7 @@ import org.springframework.web.context.WebApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
@ -48,7 +49,7 @@ public class JpaServerDemo extends RestfulServer {
* The system provider implements non-resource-type methods, such as
* transaction, and global history.
*/
JpaSystemProviderDstu1 systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu1.class);
JpaSystemProviderDstu2 systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
setPlainProviders(systemProvider);
/*

Some files were not shown because too many files have changed in this diff Show More