Merge branch 'master' into missing-date-fields-fix

This commit is contained in:
James Agnew 2019-10-01 05:29:57 -04:00 committed by GitHub
commit 1a2271f751
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2157 changed files with 160704 additions and 11410 deletions

View File

@ -3,15 +3,13 @@ HAPI FHIR
HAPI FHIR - Java API for HL7 FHIR Clients and Servers
[![Coverage Status](https://coveralls.io/repos/jamesagnew/hapi-fhir/badge.svg?branch=master&service=github)](https://coveralls.io/github/jamesagnew/hapi-fhir?branch=master)
[![Build Status](https://dev.azure.com/jamesagnew214/jamesagnew214/_apis/build/status/jamesagnew.hapi-fhir?branchName=master)](https://dev.azure.com/jamesagnew214/jamesagnew214/_build/latest?definitionId=1&branchName=master)
[![codecov](https://codecov.io/gh/jamesagnew/hapi-fhir/branch/master/graph/badge.svg)](https://codecov.io/gh/jamesagnew/hapi-fhir)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/ca.uhn.hapi.fhir/hapi-fhir-base/badge.svg)](http://search.maven.org/#search|ga|1|ca.uhn.hapi.fhir)
[![License](https://img.shields.io/badge/license-apache%202.0-60C060.svg)](http://jamesagnew.github.io/hapi-fhir/license.html)
* Linux Build: [![Build Status](https://travis-ci.org/jamesagnew/hapi-fhir.svg?branch=master)](https://travis-ci.org/jamesagnew/hapi-fhir)
* Windows Build: <a href="https://ci.appveyor.com/project/jamesagnew/hapi-fhir"><img src="https://ci.appveyor.com/api/projects/status/github/jamesagnew/hapi-fhir?branch=master&svg=true"></a>
Complete project documentation is available here:
http://jamesagnew.github.io/hapi-fhir/
http://hapifhir.io
A demonstration of this project is available here:
http://hapi.fhir.org/

View File

@ -1,9 +0,0 @@
version: 1.0.{build}
image: Visual Studio 2017
cache:
- C:\maven\
- C:\Users\appveyor\.m2\repository
build_script:
- SET JAVA_HOME=C:\Program Files\Java\jdk10
- SET PATH=C:\Program Files\Java\jdk10\bin;%PATH%
- cmd: mvn -P MINPARALLEL,ALLMODULES,REDUCED_JPA_TESTS clean install

55
azure-pipelines.yml Normal file
View File

@ -0,0 +1,55 @@
# HAPI FHIR Build Pipeline
variables:
MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository
MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
trigger:
- master
pool:
vmImage: 'ubuntu-latest'
jobs:
- job: Build
timeoutInMinutes: 360
steps:
- task: CacheBeta@0
inputs:
key: maven
path: $(MAVEN_CACHE_FOLDER)
displayName: Cache Maven local repo
- task: Maven@3
inputs:
goals: 'clean install'
# These are Maven CLI options (and show up in the build logs) - "-nsu"=Don't update snapshots. We can remove this when Maven OSS is more healthy
options: '-P ALLMODULES,JACOCO -nsu'
# These are JVM options (and don't show up in the build logs)
mavenOptions: '-Xmx2048m $(MAVEN_OPTS) -Dorg.slf4j.simpleLogger.showDateTime=true -Dorg.slf4j.simpleLogger.dateTimeFormat=HH:mm:ss,SSS -Duser.timezone=America/Toronto'
- script: bash <(curl https://codecov.io/bash) -t $(CODECOV_TOKEN)
displayName: 'codecov'
# Potential Additional Maven3 Options:
#publishJUnitResults: true
#testResultsFiles: '**/surefire-reports/TEST-*.xml' # Required when publishJUnitResults == True
#testRunTitle: # Optional
#codeCoverageToolOption: 'None' # Optional. Options: none, cobertura, jaCoCo. Enabling code coverage inserts the `clean` goal into the Maven goals list when Maven runs.
#codeCoverageClassFilter: # Optional. Comma-separated list of filters to include or exclude classes from collecting code coverage. For example: +:com.*,+:org.*,-:my.app*.*
#codeCoverageClassFilesDirectories: # Optional
#codeCoverageSourceDirectories: # Optional
#codeCoverageFailIfEmpty: false # Optional
#javaHomeOption: 'JDKVersion' # Options: jDKVersion, path
#jdkVersionOption: 'default' # Optional. Options: default, 1.11, 1.10, 1.9, 1.8, 1.7, 1.6
#jdkDirectory: # Required when javaHomeOption == Path
#jdkArchitectureOption: 'x64' # Optional. Options: x86, x64
#mavenVersionOption: 'Default' # Options: default, path
#mavenDirectory: # Required when mavenVersionOption == Path
#mavenSetM2Home: false # Required when mavenVersionOption == Path
#mavenAuthenticateFeed: false
#effectivePomSkip: false
#sonarQubeRunAnalysis: false
#sqMavenPluginVersionChoice: 'latest' # Required when sonarQubeRunAnalysis == True# Options: latest, pom
#checkStyleRunAnalysis: false # Optional
#pmdRunAnalysis: false # Optional
#findBugsRunAnalysis: false # Optional

View File

@ -25,8 +25,9 @@ public class IncludesExamples {
FhirContext ctx = FhirContext.forDstu2();
Dstu2BundleFactory bf = new Dstu2BundleFactory(ctx);
bf.initializeBundleFromResourceList(null, resources, "http://example.com/base", "http://example.com/base/Patient", 1, BundleTypeEnum.SEARCHSET);
IBaseResource b = bf.getResourceBundle();
bf.addRootPropertiesToBundle(null, null, null, null, null, resources.size(), BundleTypeEnum.SEARCHSET, null);
bf.addResourcesToBundle(new ArrayList<>(resources), BundleTypeEnum.SEARCHSET, null, null, null);
IBaseResource b = bf.getResourceBundle();
// Encode the bundle
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);

View File

@ -143,10 +143,15 @@
<groupId>org.checkerframework</groupId>
<artifactId>checker-compat-qual</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
</dependency>
</ignoredDependencies>
<ignoredResourcePatterns>
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
<ignoredResourcePattern>schemaorg_apache_xmlbeans.*</ignoredResourcePattern>
<ignoredResource>javac.bat</ignoredResource>
<ignoredResource>about.html</ignoredResource>
<ignoredResource>changelog.xml</ignoredResource>
@ -181,6 +186,7 @@
</links>
<additionalparam>-Xdoclint:none</additionalparam>
<additionalJOption>-Xdoclint:none</additionalJOption>
<source>8</source>
</configuration>
</reportSet>
</reportSets>
@ -204,11 +210,13 @@
<verbose>false</verbose>
<debug>false</debug>
<additionalJOption>-Xdoclint:none</additionalJOption>
<source>8</source>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<!--<goal>aggregate-jar</goal>-->
<goal>jar</goal>
</goals>
</execution>

View File

@ -8,6 +8,7 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import org.hl7.fhir.dstu3.model.*;
import org.junit.*;
import org.mockito.ArgumentCaptor;
@ -20,7 +21,6 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;

View File

@ -69,12 +69,21 @@
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- JENA Dependencies - Used for Turtle encoding -->
<dependency>
<groupId>org.apache.jena</groupId>
<artifactId>apache-jena-libs</artifactId>
<optional>true</optional>
<type>pom</type>
<exclusions>
<exclusion>
<groupId>com.github.jsonld-java</groupId>
<artifactId>jsonld-java</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
@ -111,6 +120,7 @@
<optional>true</optional>
</dependency>
</dependencies>
<build>
@ -119,12 +129,6 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<classFolders>
<classFolder>${basedir}/target/classes</classFolder>
</classFolders>
<sourceFolders>
<sourceFolder>${basedir}/src/main/java</sourceFolder>
</sourceFolders>
<dumpOnExit>true</dumpOnExit>
</configuration>
<executions>
@ -143,20 +147,6 @@
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
</configuration>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
-->
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>

View File

@ -66,13 +66,17 @@ public abstract class BaseRuntimeChildDefinition {
}
public interface IAccessor {
List<IBase> getValues(Object theTarget);
List<IBase> getValues(IBase theTarget);
default IBase getFirstValueOrNull(IBase theTarget) {
return getValues(theTarget).stream().findFirst().orElse(null);
}
}
public interface IMutator {
void addValue(Object theTarget, IBase theValue);
void addValue(IBase theTarget, IBase theValue);
void setValue(Object theTarget, IBase theValue);
void setValue(IBase theTarget, IBase theValue);
}
BaseRuntimeElementDefinition<?> findResourceReferenceDefinition(Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {

View File

@ -20,34 +20,33 @@ package ca.uhn.fhir.context;
* #L%
*/
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.util.ValidateUtil;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.util.ValidateUtil;
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
private final IAccessor myAccessor;
private String myBindingValueSet;
private final String myElementName;
private final Field myField;
private final String myFormalDefinition;
private final int myMax;
private final int myMin;
private boolean myModifier;
private final IMutator myMutator;
private final String myShortDefinition;
private String myBindingValueSet;
private boolean myModifier;
private boolean mySummary;
BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
super();
Validate.notNull(theField, "No field speficied");
Validate.notNull(theField, "No field specified");
ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0");
Validate.isTrue(theChildAnnotation.max() == -1 || theChildAnnotation.max() >= theChildAnnotation.min(), "Max must be >= Min (unless it is -1 / unlimited)");
Validate.notBlank(theElementName, "Element name must not be blank");
@ -87,6 +86,10 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
return myBindingValueSet;
}
void setBindingValueSet(String theBindingValueSet) {
myBindingValueSet = theBindingValueSet;
}
@Override
public String getElementName() {
return myElementName;
@ -119,107 +122,99 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
return myShortDefinition;
}
public BaseRuntimeElementDefinition<?> getSingleChildOrThrow() {
if (getValidChildNames().size() != 1) {
throw new IllegalStateException("This child has " + getValidChildNames().size() + " children, expected 1. This is a HAPI bug. Found: " + getValidChildNames());
}
return getChildByName(getValidChildNames().iterator().next());
}
public boolean isModifier() {
return myModifier;
}
protected void setModifier(boolean theModifier) {
myModifier = theModifier;
}
@Override
public boolean isSummary() {
return mySummary;
}
void setBindingValueSet(String theBindingValueSet) {
myBindingValueSet = theBindingValueSet;
}
protected void setModifier(boolean theModifier) {
myModifier = theModifier;
}
private final class FieldListAccessor implements IAccessor {
@SuppressWarnings("unchecked")
@Override
public List<IBase> getValues(Object theTarget) {
List<IBase> retVal;
try {
retVal = (List<IBase>) myField.get(theTarget);
} catch (Exception e) {
throw new ConfigurationException("Failed to get value", e);
}
public List<IBase> getValues(IBase theTarget) {
List<IBase> retVal = (List<IBase>) getFieldValue(theTarget, myField);
if (retVal == null) {
retVal = Collections.emptyList();
}
return retVal;
}
}
protected final class FieldListMutator implements IMutator {
@Override
public void addValue(Object theTarget, IBase theValue) {
public void addValue(IBase theTarget, IBase theValue) {
addValue(theTarget, theValue, false);
}
private void addValue(Object theTarget, IBase theValue, boolean theClear) {
try {
@SuppressWarnings("unchecked")
List<IBase> existingList = (List<IBase>) myField.get(theTarget);
if (existingList == null) {
existingList = new ArrayList<IBase>(2);
myField.set(theTarget, existingList);
}
if (theClear) {
existingList.clear();
}
existingList.add(theValue);
} catch (Exception e) {
throw new ConfigurationException("Failed to set value", e);
private void addValue(IBase theTarget, IBase theValue, boolean theClear) {
@SuppressWarnings("unchecked")
List<IBase> existingList = (List<IBase>) getFieldValue(theTarget, myField);
if (existingList == null) {
existingList = new ArrayList<>(2);
setFieldValue(theTarget, existingList, myField);
}
if (theClear) {
existingList.clear();
}
existingList.add(theValue);
}
@Override
public void setValue(Object theTarget, IBase theValue) {
public void setValue(IBase theTarget, IBase theValue) {
addValue(theTarget, theValue, true);
}
}
private final class FieldPlainAccessor implements IAccessor {
@Override
public List<IBase> getValues(Object theTarget) {
try {
Object values = myField.get(theTarget);
if (values == null) {
return Collections.emptyList();
}
List<IBase> retVal = Collections.singletonList((IBase) values);
return retVal;
} catch (Exception e) {
throw new ConfigurationException("Failed to get value", e);
public List<IBase> getValues(IBase theTarget) {
Object values = getFieldValue(theTarget, myField);
if (values == null) {
return Collections.emptyList();
}
return Collections.singletonList((IBase) values);
}
@Override
public IBase getFirstValueOrNull(IBase theTarget) {
return (IBase) getFieldValue(theTarget, myField);
}
}
protected final class FieldPlainMutator implements IMutator {
@Override
public void addValue(Object theTarget, IBase theValue) {
try {
myField.set(theTarget, theValue);
} catch (Exception e) {
throw new ConfigurationException("Failed to set value", e);
}
public void addValue(IBase theTarget, IBase theValue) {
setFieldValue(theTarget, theValue, myField);
}
@Override
public void setValue(Object theTarget, IBase theValue) {
public void setValue(IBase theTarget, IBase theValue) {
addValue(theTarget, theValue);
}
}
private static void setFieldValue(IBase theTarget, Object theValue, Field theField) {
try {
theField.set(theTarget, theValue);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to set value", e);
}
}
private static Object getFieldValue(IBase theTarget, Field theField) {
try {
return theField.get(theTarget);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to get value", e);
}
}
}

View File

@ -68,7 +68,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
public IAccessor getAccessor() {
return new IAccessor() {
@Override
public List<IBase> getValues(Object theTarget) {
public List<IBase> getValues(IBase theTarget) {
ExtensionDt target = (ExtensionDt) theTarget;
if (target.getValue() != null) {
return Collections.singletonList((IBase) target.getValue());
@ -76,6 +76,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
ArrayList<IBase> retVal = new ArrayList<IBase>(target.getUndeclaredExtensions());
return retVal;
}
};
}
@ -113,7 +114,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
public IMutator getMutator() {
return new IMutator() {
@Override
public void addValue(Object theTarget, IBase theValue) {
public void addValue(IBase theTarget, IBase theValue) {
ExtensionDt target = (ExtensionDt) theTarget;
if (theValue instanceof IDatatype) {
target.setValue((IDatatype) theTarget);
@ -123,7 +124,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
}
@Override
public void setValue(Object theTarget, IBase theValue) {
public void setValue(IBase theTarget, IBase theValue) {
ExtensionDt target = (ExtensionDt) theTarget;
if (theValue instanceof IDatatype) {
target.setValue((IDatatype) theTarget);

View File

@ -20,31 +20,29 @@ package ca.uhn.fhir.model.api;
* #L%
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import java.util.*;
public abstract class BaseElement implements /*IElement, */ISupportsUndeclaredExtensions {
private static final long serialVersionUID = -3092659584634499332L;
private List<String> myFormatCommentsPost;
private List<String> myFormatCommentsPre;
@Child(name = "extension", type = {ExtensionDt.class}, order=0, min=0, max=Child.MAX_UNLIMITED, modifier=false, summary=false)
@Description(shortDefinition="Additional Content defined by implementations", formalDefinition="May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension." )
private Map<String, Object> userData;
@Child(name = "extension", type = {ExtensionDt.class}, order = 0, min = 0, max = Child.MAX_UNLIMITED, modifier = false, summary = false)
@Description(shortDefinition = "Additional Content defined by implementations", formalDefinition = "May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.")
private List<ExtensionDt> myUndeclaredExtensions;
/**
* May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.
*/
@Child(name = "modifierExtension", type = {ExtensionDt.class}, order=1, min=0, max=Child.MAX_UNLIMITED, modifier=true, summary=false)
@Description(shortDefinition="Extensions that cannot be ignored", formalDefinition="May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions." )
/**
* May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.
*/
@Child(name = "modifierExtension", type = {ExtensionDt.class}, order = 1, min = 0, max = Child.MAX_UNLIMITED, modifier = true, summary = false)
@Description(shortDefinition = "Extensions that cannot be ignored", formalDefinition = "May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict set of governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.")
private List<ExtensionDt> myUndeclaredModifierExtensions;
@Override
@ -148,6 +146,21 @@ public abstract class BaseElement implements /*IElement, */ISupportsUndeclaredEx
return (myFormatCommentsPre != null && !myFormatCommentsPre.isEmpty()) || (myFormatCommentsPost != null && !myFormatCommentsPost.isEmpty());
}
@Override
public Object getUserData(String name) {
if (userData == null)
return null;
return userData.get(name);
}
@Override
public void setUserData(String name, Object value) {
if (userData == null) {
userData = new HashMap<>();
}
userData.put(name, value);
}
/**
* Intended to be called by extending classes {@link #isEmpty()} implementations, returns <code>true</code> if all
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.

View File

@ -25,5 +25,6 @@ import org.hl7.fhir.instance.model.api.IBase;
public interface IElement extends IBase {
}

View File

@ -40,7 +40,7 @@ public class Include implements Serializable {
private static final long serialVersionUID = 1L;
private final boolean myImmutable;
private boolean myRecurse;
private boolean myIterate;
private String myValue;
/**
@ -59,12 +59,12 @@ public class Include implements Serializable {
*
* @param theValue
* The <code>_include</code> value, e.g. "Patient:name"
* @param theRecurse
* @param theIterate
* Should the include recurse
*/
public Include(String theValue, boolean theRecurse) {
public Include(String theValue, boolean theIterate) {
myValue = theValue;
myRecurse = theRecurse;
myIterate = theIterate;
myImmutable = false;
}
@ -73,12 +73,12 @@ public class Include implements Serializable {
*
* @param theValue
* The <code>_include</code> value, e.g. "Patient:name"
* @param theRecurse
* @param theIterate
* Should the include recurse
*/
public Include(String theValue, boolean theRecurse, boolean theImmutable) {
public Include(String theValue, boolean theIterate, boolean theImmutable) {
myValue = theValue;
myRecurse = theRecurse;
myIterate = theIterate;
myImmutable = theImmutable;
}
@ -111,7 +111,7 @@ public class Include implements Serializable {
return false;
}
Include other = (Include) obj;
if (myRecurse != other.myRecurse) {
if (myIterate != other.myIterate) {
return false;
}
if (myValue == null) {
@ -177,7 +177,7 @@ public class Include implements Serializable {
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (myRecurse ? 1231 : 1237);
result = prime * result + (myIterate ? 1231 : 1237);
result = prime * result + ((myValue == null) ? 0 : myValue.hashCode());
return result;
}
@ -190,7 +190,7 @@ public class Include implements Serializable {
}
public boolean isRecurse() {
return myRecurse;
return myIterate;
}
/**
@ -199,7 +199,7 @@ public class Include implements Serializable {
* @return Returns a reference to <code>this</code> for easy method chaining
*/
public Include setRecurse(boolean theRecurse) {
myRecurse = theRecurse;
myIterate = theRecurse;
return this;
}
@ -214,7 +214,7 @@ public class Include implements Serializable {
* Return a new
*/
public Include toLocked() {
Include retVal = new Include(myValue, myRecurse, true);
Include retVal = new Include(myValue, myIterate, true);
return retVal;
}
@ -222,7 +222,7 @@ public class Include implements Serializable {
public String toString() {
ToStringBuilder builder = new ToStringBuilder(this);
builder.append("value", myValue);
builder.append("recurse", myRecurse);
builder.append("iterate", myIterate);
return builder.toString();
}
@ -273,7 +273,7 @@ public class Include implements Serializable {
b.append(':');
b.append(theResourceType);
}
Include retVal = new Include(b.toString(), myRecurse, myImmutable);
Include retVal = new Include(b.toString(), myIterate, myImmutable);
return retVal;
}

View File

@ -29,6 +29,7 @@ import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.io.Serializable;
@ -629,5 +630,5 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
}
}
}

View File

@ -282,4 +282,14 @@ public class TagList implements Set<Tag>, Serializable, IBase {
throw new UnsupportedOperationException();
}
@Override
public Object getUserData(String theName) {
throw new UnsupportedOperationException();
}
@Override
public void setUserData(String theName, Object theValue) {
throw new UnsupportedOperationException();
}
}

View File

@ -20,21 +20,20 @@ package ca.uhn.fhir.model.primitive;
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import ca.uhn.fhir.model.api.BasePrimitive;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.time.FastDateFormat;
import ca.uhn.fhir.model.api.BasePrimitive;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.parser.DataFormatException;
import static org.apache.commons.lang3.StringUtils.isBlank;
public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
static final long NANOS_PER_MILLIS = 1000000L;
@ -42,7 +41,8 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
private static final FastDateFormat ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, FastDateFormat.MEDIUM);
private static final FastDateFormat ourXmlDateTimeFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss");
public static final String NOW_DATE_CONSTANT = "%now";
private String myFractionalSeconds;
private TemporalPrecisionEnum myPrecision = null;
private TimeZone myTimeZone;
@ -635,7 +635,12 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
@Override
public void setValueAsString(String theValue) throws DataFormatException {
clearTimeZone();
super.setValueAsString(theValue);
if (NOW_DATE_CONSTANT.equalsIgnoreCase(theValue)) {
super.setValueAsString(ourXmlDateTimeFormat.format(new Date()));
} else {
super.setValueAsString(theValue);
}
}
/**

View File

@ -128,114 +128,41 @@ public abstract class BaseParser implements IParser {
}
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final CompositeChildElement theParent, EncodeContext theEncodeContext) {
BaseRuntimeElementCompositeDefinition<?> elementDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(theCompositeElement.getClass());
final List<BaseRuntimeChildDefinition> children = elementDef.getChildrenAndExtension();
return theEncodeContext.getCompositeChildrenCache().computeIfAbsent(new Key(elementDef, theContainedResource, theParent, theEncodeContext), (k) -> {
return new Iterable<BaseParser.CompositeChildElement>() {
final List<BaseRuntimeChildDefinition> children = elementDef.getChildrenAndExtension();
final List<CompositeChildElement> result = new ArrayList<>(children.size());
@Override
public Iterator<CompositeChildElement> iterator() {
for (final BaseRuntimeChildDefinition child : children) {
CompositeChildElement myNext = new CompositeChildElement(theParent, child, theEncodeContext);
return new Iterator<CompositeChildElement>() {
private Iterator<? extends BaseRuntimeChildDefinition> myChildrenIter;
private Boolean myHasNext = null;
private CompositeChildElement myNext;
/**
* Constructor
*/ {
myChildrenIter = children.iterator();
/*
* There are lots of reasons we might skip encoding a particular child
*/
if (myNext.getDef().getElementName().equals("id")) {
continue;
} else if (!myNext.shouldBeEncoded(theContainedResource)) {
continue;
} else if (myNext.getDef() instanceof RuntimeChildNarrativeDefinition) {
if (isSuppressNarratives() || isSummaryMode()) {
continue;
} else if (theContainedResource) {
continue;
}
@Override
public boolean hasNext() {
if (myHasNext != null) {
return myHasNext;
}
myNext = null;
do {
if (myChildrenIter.hasNext() == false) {
myHasNext = Boolean.FALSE;
return false;
}
myNext = new CompositeChildElement(theParent, myChildrenIter.next(), theEncodeContext);
/*
* There are lots of reasons we might skip encoding a particular child
*/
if (myNext.getDef().getElementName().equals("id")) {
myNext = null;
} else if (!myNext.shouldBeEncoded(theContainedResource)) {
myNext = null;
} else if (myNext.getDef() instanceof RuntimeChildNarrativeDefinition) {
if (isSuppressNarratives() || isSummaryMode()) {
myNext = null;
} else if (theContainedResource) {
myNext = null;
}
} else if (myNext.getDef() instanceof RuntimeChildContainedResources) {
if (theContainedResource) {
myNext = null;
}
}
} while (myNext == null);
myHasNext = true;
return true;
} else if (myNext.getDef() instanceof RuntimeChildContainedResources) {
if (theContainedResource) {
continue;
}
@Override
public CompositeChildElement next() {
if (myHasNext == null) {
if (!hasNext()) {
throw new IllegalStateException();
}
}
CompositeChildElement retVal = myNext;
myNext = null;
myHasNext = null;
return retVal;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
result.add(myNext);
}
};
return result;
});
}
private void containResourcesForEncoding(ContainedResources theContained, IBaseResource theResource, IBaseResource theTarget) {
if (theTarget instanceof IResource) {
List<? extends IResource> containedResources = ((IResource) theTarget).getContained().getContainedResources();
for (IResource next : containedResources) {
String nextId = next.getId().getValue();
if (StringUtils.isNotBlank(nextId)) {
if (!nextId.startsWith("#")) {
nextId = '#' + nextId;
}
theContained.getExistingIdToContainedResource().put(nextId, next);
}
}
} else if (theTarget instanceof IDomainResource) {
List<? extends IAnyResource> containedResources = ((IDomainResource) theTarget).getContained();
for (IAnyResource next : containedResources) {
String nextId = next.getIdElement().getValue();
if (StringUtils.isNotBlank(nextId)) {
if (!nextId.startsWith("#")) {
nextId = '#' + nextId;
}
theContained.getExistingIdToContainedResource().put(nextId, next);
}
}
}
List<IBaseReference> allReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(theResource, IBaseReference.class);
List<IBaseReference> allReferences = getAllBaseReferences(theResource);
for (IBaseReference next : allReferences) {
IBaseResource resource = next.getResource();
if (resource == null && next.getReferenceElement().isLocal()) {
@ -274,12 +201,117 @@ public abstract class BaseParser implements IParser {
protected void containResourcesForEncoding(IBaseResource theResource) {
ContainedResources contained = new ContainedResources();
if (theResource instanceof IResource) {
List<? extends IResource> containedResources = ((IResource) theResource).getContained().getContainedResources();
for (IResource next : containedResources) {
String nextId = next.getId().getValue();
if (StringUtils.isNotBlank(nextId)) {
if (!nextId.startsWith("#")) {
nextId = '#' + nextId;
}
contained.getExistingIdToContainedResource().put(nextId, next);
}
}
} else if (theResource instanceof IDomainResource) {
List<? extends IAnyResource> containedResources = ((IDomainResource) theResource).getContained();
for (IAnyResource next : containedResources) {
String nextId = next.getIdElement().getValue();
if (StringUtils.isNotBlank(nextId)) {
if (!nextId.startsWith("#")) {
nextId = '#' + nextId;
}
contained.getExistingIdToContainedResource().put(nextId, next);
}
}
}
containResourcesForEncoding(contained, theResource, theResource);
contained.assignIdsToContainedResources();
myContainedResources = contained;
}
protected List<IBaseReference> getAllBaseReferences(IBaseResource theResource) {
final ArrayList<IBaseReference> retVal = new ArrayList<IBaseReference>();
findBaseReferences(retVal, theResource, myContext.getResourceDefinition(theResource));
return retVal;
}
/**
* A customised traversal of the tree to find the 'top level' base references. Nested references are found via the recursive traversal
* of contained resources.
*/
protected void findBaseReferences(List<IBaseReference> allElements, IBase theElement, BaseRuntimeElementDefinition<?> theDefinition) {
if (theElement instanceof IBaseReference) {
allElements.add((IBaseReference) theElement);
}
BaseRuntimeElementDefinition<?> def = theDefinition;
if (def.getChildType() == ChildTypeEnum.CONTAINED_RESOURCE_LIST) {
def = myContext.getElementDefinition(theElement.getClass());
}
switch (def.getChildType()) {
case ID_DATATYPE:
case PRIMITIVE_XHTML_HL7ORG:
case PRIMITIVE_XHTML:
case PRIMITIVE_DATATYPE:
// These are primitive types
break;
case RESOURCE:
case RESOURCE_BLOCK:
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> childDef = (BaseRuntimeElementCompositeDefinition<?>) def;
for (BaseRuntimeChildDefinition nextChild : childDef.getChildrenAndExtension()) {
List<?> values = nextChild.getAccessor().getValues(theElement);
if (values != null) {
for (Object nextValueObject : values) {
IBase nextValue;
try {
nextValue = (IBase) nextValueObject;
} catch (ClassCastException e) {
String s = "Found instance of " + nextValueObject.getClass() + " - Did you set a field value to the incorrect type? Expected " + IBase.class.getName();
throw new ClassCastException(s);
}
if (nextValue == null) {
continue;
}
if (nextValue.isEmpty()) {
continue;
}
BaseRuntimeElementDefinition<?> childElementDef;
childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
if (childElementDef == null) {
childElementDef = myContext.getElementDefinition(nextValue.getClass());
}
if (nextChild instanceof RuntimeChildDirectResource) {
// Don't descend into embedded resources
if (nextValue instanceof IBaseReference) {
allElements.add((IBaseReference) nextValue);
}
} else {
findBaseReferences(allElements, nextValue, childElementDef);
}
}
}
}
break;
}
case CONTAINED_RESOURCES:
// skip contained resources when looking for resources to contain
break;
case CONTAINED_RESOURCE_LIST:
case EXTENSION_DECLARED:
case UNDECL_EXT: {
throw new IllegalStateException("state should not happen: " + def.getChildType());
}
}
}
private String determineReferenceText(IBaseReference theRef, CompositeChildElement theCompositeChildElement) {
IIdType ref = theRef.getReferenceElement();
if (isBlank(ref.getIdPart())) {
@ -1193,6 +1225,37 @@ public abstract class BaseParser implements IParser {
return retVal;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((myDef == null) ? 0 : myDef.hashCode());
result = prime * result + ((myParent == null) ? 0 : myParent.hashCode());
result = prime * result + ((myResDef == null) ? 0 : myResDef.hashCode());
result = prime * result + ((myEncodeContext == null) ? 0 : myEncodeContext.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj instanceof CompositeChildElement) {
final CompositeChildElement that = (CompositeChildElement) obj;
return Objects.equals(this.getEnclosingInstance(), that.getEnclosingInstance()) &&
Objects.equals(this.myDef, that.myDef) &&
Objects.equals(this.myParent, that.myParent) &&
Objects.equals(this.myResDef, that.myResDef) &&
Objects.equals(this.myEncodeContext, that.myEncodeContext);
}
return false;
}
private BaseParser getEnclosingInstance() {
return BaseParser.this;
}
}
protected class EncodeContextPath {
@ -1264,13 +1327,17 @@ public abstract class BaseParser implements IParser {
}
}
/**
* EncodeContext is a shared state object that is passed around the
* encode process
*/
protected class EncodeContext extends EncodeContextPath {
private final ArrayList<EncodeContextPathElement> myResourcePath = new ArrayList<>(10);
private final Map<Key, List<CompositeChildElement>> myCompositeChildrenCache = new HashMap<>();
public Map<Key, List<CompositeChildElement>> getCompositeChildrenCache() {
return myCompositeChildrenCache;
}
protected ArrayList<EncodeContextPathElement> getResourcePath() {
return myResourcePath;
@ -1403,6 +1470,46 @@ public abstract class BaseParser implements IParser {
}
}
private static class Key {
private final BaseRuntimeElementCompositeDefinition<?> resDef;
private final boolean theContainedResource;
private final CompositeChildElement theParent;
private final EncodeContext theEncodeContext;
public Key(BaseRuntimeElementCompositeDefinition<?> resDef, final boolean theContainedResource, final CompositeChildElement theParent, EncodeContext theEncodeContext) {
this.resDef = resDef;
this.theContainedResource = theContainedResource;
this.theParent = theParent;
this.theEncodeContext = theEncodeContext;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((resDef == null) ? 0 : resDef.hashCode());
result = prime * result + (theContainedResource ? 1231 : 1237);
result = prime * result + ((theParent == null) ? 0 : theParent.hashCode());
result = prime * result + ((theEncodeContext == null) ? 0 : theEncodeContext.hashCode());
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Key) {
final Key that = (Key) obj;
return Objects.equals(this.resDef, that.resDef) &&
this.theContainedResource == that.theContainedResource &&
Objects.equals(this.theParent, that.theParent) &&
Objects.equals(this.theEncodeContext, that.theEncodeContext);
}
return false;
}
}
static class ContainedResources {
private long myNextContainedId = 1;

View File

@ -224,13 +224,24 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
case PRIMITIVE_DATATYPE: {
final IPrimitiveType<?> value = (IPrimitiveType<?>) theNextValue;
if (isBlank(value.getValueAsString())) {
final String valueStr = value.getValueAsString();
if (isBlank(valueStr)) {
if (theForceEmpty) {
theEventWriter.writeNull();
}
break;
}
// check for the common case first - String value types
if (value.getValue() instanceof String) {
if (theChildName != null) {
theEventWriter.write(theChildName, valueStr);
} else {
theEventWriter.write(valueStr);
}
break;
}
if (value instanceof IBaseIntegerDatatype) {
if (theChildName != null) {
write(theEventWriter, theChildName, ((IBaseIntegerDatatype) value).getValue());
@ -262,7 +273,6 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
}
}
} else {
String valueStr = value.getValueAsString();
if (theChildName != null) {
write(theEventWriter, theChildName, valueStr);
} else {
@ -459,7 +469,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
if (nextValue instanceof IBaseHasModifierExtensions) {
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
List<? extends IBaseExtension<?, ?>> ext = element.getModifierExtension();
force |= addToHeldExtensions(valueIdx, ext, extensions, true, nextChildElem, theParent, theEncodeContext, theContainedResource, theElement);
force |= addToHeldExtensions(valueIdx, ext, modifierExtensions, true, nextChildElem, theParent, theEncodeContext, theContainedResource, theElement);
}
}
if (nextValue.hasFormatComment()) {

View File

@ -19,17 +19,6 @@ package ca.uhn.fhir.parser;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.*;
import java.util.*;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.*;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IMutator;
@ -37,21 +26,32 @@ import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
import ca.uhn.fhir.model.primitive.*;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
import ca.uhn.fhir.parser.json.JsonLikeValue.ScalarType;
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
import ca.uhn.fhir.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.Pair;
import org.hl7.fhir.instance.model.api.*;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.*;
class ParserState<T> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
private List<String> myComments = new ArrayList<String>(2);
private final FhirContext myContext;
private final IParserErrorHandler myErrorHandler;
private final boolean myJsonMode;
private T myObject;
private final IParser myParser;
private List<String> myComments = new ArrayList<String>(2);
private T myObject;
private IBase myPreviousElement;
private BaseState myState;
@ -152,38 +152,6 @@ class ParserState<T> {
}
}
/**
* @param theResourceType
* May be null
*/
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(IParser theParser, Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler)
throws DataFormatException {
ParserState<T> retVal = new ParserState<T>(theParser, theContext, theJsonMode, theErrorHandler);
if (theResourceType == null) {
if (theContext.getVersion().getVersion().isRi()) {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
}
} else {
if (IResource.class.isAssignableFrom(theResourceType)) {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
}
}
return retVal;
}
static ParserState<TagList> getPreTagListInstance(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
ParserState<TagList> retVal = new ParserState<TagList>(theParser, theContext, theJsonMode, theErrorHandler);
retVal.push(retVal.new PreTagListState());
return retVal;
}
private abstract class BaseState {
private PreResourceState myPreResourceState;
@ -195,8 +163,7 @@ class ParserState<T> {
}
/**
* @param theValue
* The attribute value
* @param theValue The attribute value
*/
public void attributeValue(String theName, String theValue) throws DataFormatException {
myErrorHandler.unknownAttribute(null, theName);
@ -211,8 +178,7 @@ class ParserState<T> {
}
/**
* @param theNamespaceUri
* The XML namespace (if XML) or null
* @param theNamespaceUri The XML namespace (if XML) or null
*/
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
myErrorHandler.unknownElement(null, theLocalPart);
@ -275,8 +241,7 @@ class ParserState<T> {
}
/**
* @param theData
* The string value
* @param theData The string value
*/
public void string(String theData) {
// ignore by default
@ -287,8 +252,7 @@ class ParserState<T> {
}
/**
* @param theNextEvent
* The XML event
* @param theNextEvent The XML event
*/
public void xmlEvent(XMLEvent theNextEvent) {
// ignore
@ -414,30 +378,30 @@ class ParserState<T> {
}
switch (target.getChildType()) {
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments());
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
ElementCompositeState newState = new ElementCompositeState(myPreResourceState, theLocalPart, compositeTarget, newChildInstance);
push(newState);
return;
}
case ID_DATATYPE:
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance(myDefinition.getInstanceConstructorArguments());
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
}
case PRIMITIVE_XHTML:
case RESOURCE:
case RESOURCE_BLOCK:
case UNDECL_EXT:
case EXTENSION_DECLARED:
default:
break;
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments());
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
ElementCompositeState newState = new ElementCompositeState(myPreResourceState, theLocalPart, compositeTarget, newChildInstance);
push(newState);
return;
}
case ID_DATATYPE:
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance(myDefinition.getInstanceConstructorArguments());
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
}
case PRIMITIVE_XHTML:
case RESOURCE:
case RESOURCE_BLOCK:
case UNDECL_EXT:
case EXTENSION_DECLARED:
default:
break;
}
}
@ -545,81 +509,81 @@ class ParserState<T> {
}
switch (target.getChildType()) {
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(child.getInstanceConstructorArguments());
child.getMutator().addValue(myInstance, newChildInstance);
ParserState<T>.ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, compositeTarget, newChildInstance);
push(newState);
return;
}
case ID_DATATYPE:
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance;
newChildInstance = primitiveTarget.newInstance(child.getInstanceConstructorArguments());
child.getMutator().addValue(myInstance, newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
}
case RESOURCE_BLOCK: {
RuntimeResourceBlockDefinition blockTarget = (RuntimeResourceBlockDefinition) target;
IBase newBlockInstance = blockTarget.newInstance();
child.getMutator().addValue(myInstance, newBlockInstance);
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, blockTarget, newBlockInstance);
push(newState);
return;
}
case PRIMITIVE_XHTML: {
RuntimePrimitiveDatatypeNarrativeDefinition xhtmlTarget = (RuntimePrimitiveDatatypeNarrativeDefinition) target;
XhtmlDt newDt = xhtmlTarget.newInstance();
child.getMutator().addValue(myInstance, newDt);
XhtmlState state = new XhtmlState(getPreResourceState(), newDt, true);
push(state);
return;
}
case PRIMITIVE_XHTML_HL7ORG: {
RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition xhtmlTarget = (RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition) target;
IBaseXhtml newDt = xhtmlTarget.newInstance();
child.getMutator().addValue(myInstance, newDt);
XhtmlStateHl7Org state = new XhtmlStateHl7Org(getPreResourceState(), newDt);
push(state);
return;
}
case CONTAINED_RESOURCES: {
List<? extends IBase> values = child.getAccessor().getValues(myInstance);
Object newDt;
if (values == null || values.isEmpty() || values.get(0) == null) {
newDt = newContainedDt((IResource) getPreResourceState().myInstance);
child.getMutator().addValue(myInstance, (IBase) newDt);
} else {
newDt = values.get(0);
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(child.getInstanceConstructorArguments());
child.getMutator().addValue(myInstance, newChildInstance);
ParserState<T>.ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, compositeTarget, newChildInstance);
push(newState);
return;
}
ContainedResourcesStateHapi state = new ContainedResourcesStateHapi(getPreResourceState());
push(state);
return;
}
case CONTAINED_RESOURCE_LIST: {
ContainedResourcesStateHl7Org state = new ContainedResourcesStateHl7Org(getPreResourceState());
push(state);
return;
}
case RESOURCE: {
if (myInstance instanceof IAnyResource || myInstance instanceof IBaseBackboneElement || myInstance instanceof IBaseElement) {
ParserState<T>.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
push(state);
} else {
ParserState<T>.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null);
push(state);
case ID_DATATYPE:
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance;
newChildInstance = primitiveTarget.newInstance(child.getInstanceConstructorArguments());
child.getMutator().addValue(myInstance, newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
}
case RESOURCE_BLOCK: {
RuntimeResourceBlockDefinition blockTarget = (RuntimeResourceBlockDefinition) target;
IBase newBlockInstance = blockTarget.newInstance();
child.getMutator().addValue(myInstance, newBlockInstance);
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, blockTarget, newBlockInstance);
push(newState);
return;
}
case PRIMITIVE_XHTML: {
RuntimePrimitiveDatatypeNarrativeDefinition xhtmlTarget = (RuntimePrimitiveDatatypeNarrativeDefinition) target;
XhtmlDt newDt = xhtmlTarget.newInstance();
child.getMutator().addValue(myInstance, newDt);
XhtmlState state = new XhtmlState(getPreResourceState(), newDt, true);
push(state);
return;
}
case PRIMITIVE_XHTML_HL7ORG: {
RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition xhtmlTarget = (RuntimePrimitiveDatatypeXhtmlHl7OrgDefinition) target;
IBaseXhtml newDt = xhtmlTarget.newInstance();
child.getMutator().addValue(myInstance, newDt);
XhtmlStateHl7Org state = new XhtmlStateHl7Org(getPreResourceState(), newDt);
push(state);
return;
}
case CONTAINED_RESOURCES: {
List<? extends IBase> values = child.getAccessor().getValues(myInstance);
Object newDt;
if (values == null || values.isEmpty() || values.get(0) == null) {
newDt = newContainedDt((IResource) getPreResourceState().myInstance);
child.getMutator().addValue(myInstance, (IBase) newDt);
} else {
newDt = values.get(0);
}
ContainedResourcesStateHapi state = new ContainedResourcesStateHapi(getPreResourceState());
push(state);
return;
}
case CONTAINED_RESOURCE_LIST: {
ContainedResourcesStateHl7Org state = new ContainedResourcesStateHl7Org(getPreResourceState());
push(state);
return;
}
case RESOURCE: {
if (myInstance instanceof IAnyResource || myInstance instanceof IBaseBackboneElement || myInstance instanceof IBaseElement) {
ParserState<T>.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
push(state);
} else {
ParserState<T>.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null);
push(state);
}
return;
}
case UNDECL_EXT:
case EXTENSION_DECLARED: {
// Throw an exception because this shouldn't happen here
break;
}
return;
}
case UNDECL_EXT:
case EXTENSION_DECLARED: {
// Throw an exception because this shouldn't happen here
break;
}
}
throw new DataFormatException("Illegal resource position: " + target.getChildType());
@ -716,32 +680,32 @@ class ParserState<T> {
if (target != null) {
switch (target.getChildType()) {
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance();
myExtension.setValue(newChildInstance);
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theLocalPart, compositeTarget, newChildInstance);
push(newState);
return;
}
case ID_DATATYPE:
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance();
myExtension.setValue(newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
}
case CONTAINED_RESOURCES:
case CONTAINED_RESOURCE_LIST:
case EXTENSION_DECLARED:
case PRIMITIVE_XHTML:
case PRIMITIVE_XHTML_HL7ORG:
case RESOURCE:
case RESOURCE_BLOCK:
case UNDECL_EXT:
break;
case COMPOSITE_DATATYPE: {
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance();
myExtension.setValue(newChildInstance);
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theLocalPart, compositeTarget, newChildInstance);
push(newState);
return;
}
case ID_DATATYPE:
case PRIMITIVE_DATATYPE: {
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance();
myExtension.setValue(newChildInstance);
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
push(newState);
return;
}
case CONTAINED_RESOURCES:
case CONTAINED_RESOURCE_LIST:
case EXTENSION_DECLARED:
case PRIMITIVE_XHTML:
case PRIMITIVE_XHTML_HL7ORG:
case RESOURCE:
case RESOURCE_BLOCK:
case UNDECL_EXT:
break;
}
}
@ -890,7 +854,6 @@ class ParserState<T> {
}
private abstract class PreResourceState extends BaseState {
private Map<String, IBaseResource> myContainedResources;
@ -1008,14 +971,14 @@ class ParserState<T> {
if (wantedProfileType != null && !wantedProfileType.equals(myInstance.getClass())) {
if (myResourceType == null || myResourceType.isAssignableFrom(wantedProfileType)) {
ourLog.debug("Converting resource of type {} to type defined for profile \"{}\": {}", new Object[] { myInstance.getClass().getName(), usedProfile, wantedProfileType });
ourLog.debug("Converting resource of type {} to type defined for profile \"{}\": {}", new Object[]{myInstance.getClass().getName(), usedProfile, wantedProfileType});
/*
* This isn't the most efficient thing really.. If we want a specific
* type we just re-parse into that type. The problem is that we don't know
* until we've parsed the resource which type we want to use because the
* profile declarations are in the text of the resource itself.
*
*
* At some point it would be good to write code which can present a view
* of one type backed by another type and use that.
*/
@ -1094,7 +1057,7 @@ class ParserState<T> {
@Override
public void acceptElement(IBaseResource theResource, IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
BaseRuntimeElementDefinition<?> theDefinition) {
BaseRuntimeElementDefinition<?> theDefinition) {
if (theElement instanceof BaseResourceReferenceDt) {
BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement;
String ref = nextRef.getReference().getValue();
@ -1137,7 +1100,7 @@ class ParserState<T> {
private class PreResourceStateHapi extends PreResourceState {
private IMutator myMutator;
private Object myTarget;
private IBase myTarget;
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
@ -1145,7 +1108,7 @@ class ParserState<T> {
assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType);
}
public PreResourceStateHapi(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
public PreResourceStateHapi(IBase theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myTarget = theTarget;
myMutator = theMutator;
@ -1175,18 +1138,18 @@ class ParserState<T> {
String resourceName = myContext.getResourceDefinition(nextResource).getName();
String bundleIdPart = nextResource.getId().getIdPart();
if (isNotBlank(bundleIdPart)) {
// if (isNotBlank(entryBaseUrl)) {
// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
// } else {
IdDt previousId = nextResource.getId();
nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
// Copy extensions
if (!previousId.getAllUndeclaredExtensions().isEmpty()) {
for (final ExtensionDt ext : previousId.getAllUndeclaredExtensions()) {
nextResource.getId().addUndeclaredExtension(ext);
}
}
// }
// if (isNotBlank(entryBaseUrl)) {
// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
// } else {
IdDt previousId = nextResource.getId();
nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
// Copy extensions
if (!previousId.getAllUndeclaredExtensions().isEmpty()) {
for (final ExtensionDt ext : previousId.getAllUndeclaredExtensions()) {
nextResource.getId().addUndeclaredExtension(ext);
}
}
// }
}
}
@ -1195,13 +1158,13 @@ class ParserState<T> {
private class PreResourceStateHl7Org extends PreResourceState {
private IMutator myMutator;
private Object myTarget;
private IBase myTarget;
public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
}
public PreResourceStateHl7Org(Object theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
public PreResourceStateHl7Org(IBase theTarget, IMutator theMutator, Class<? extends IBaseResource> theResourceType) {
super(theResourceType);
myMutator = theMutator;
myTarget = theTarget;
@ -1463,21 +1426,21 @@ class ParserState<T> {
String value = defaultIfBlank(theValue, null);
switch (mySubState) {
case TERM:
myTerm = (value);
break;
case LABEL:
myLabel = (value);
break;
case SCHEME:
myScheme = (value);
break;
case NONE:
// This handles JSON encoding, which is a bit weird
enteringNewElement(null, theName);
attributeValue(null, value);
endingElement();
break;
case TERM:
myTerm = (value);
break;
case LABEL:
myLabel = (value);
break;
case SCHEME:
myScheme = (value);
break;
case NONE:
// This handles JSON encoding, which is a bit weird
enteringNewElement(null, theName);
attributeValue(null, value);
endingElement();
break;
}
}
@ -1604,4 +1567,32 @@ class ParserState<T> {
}
/**
* @param theResourceType May be null
*/
static <T extends IBaseResource> ParserState<T> getPreResourceInstance(IParser theParser, Class<T> theResourceType, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler)
throws DataFormatException {
ParserState<T> retVal = new ParserState<T>(theParser, theContext, theJsonMode, theErrorHandler);
if (theResourceType == null) {
if (theContext.getVersion().getVersion().isRi()) {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
}
} else {
if (IResource.class.isAssignableFrom(theResourceType)) {
retVal.push(retVal.new PreResourceStateHapi(theResourceType));
} else {
retVal.push(retVal.new PreResourceStateHl7Org(theResourceType));
}
}
return retVal;
}
static ParserState<TagList> getPreTagListInstance(IParser theParser, FhirContext theContext, boolean theJsonMode, IParserErrorHandler theErrorHandler) {
ParserState<TagList> retVal = new ParserState<TagList>(theParser, theContext, theJsonMode, theErrorHandler);
retVal.push(retVal.new PreTagListState());
return retVal;
}
}

View File

@ -354,17 +354,10 @@ public class XmlParser extends BaseParser {
}
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
INarrative narr = (INarrative) nextChild.getAccessor().getFirstValueOrNull(theElement);
INarrativeGenerator gen = myContext.getNarrativeGenerator();
INarrative narr;
if (theResource instanceof IResource) {
narr = ((IResource) theResource).getText();
} else if (theResource instanceof IDomainResource) {
narr = ((IDomainResource) theResource).getText();
} else {
narr = null;
}
// FIXME potential null access on narr see line 623
if (gen != null && narr.isEmpty()) {
if (gen != null && (narr == null || narr.isEmpty())) {
gen.populateResourceNarrative(myContext, theResource);
}
if (narr != null && narr.isEmpty() == false) {

View File

@ -52,15 +52,6 @@ public class GsonStructure implements JsonLikeStructure {
super();
}
public GsonStructure (JsonObject json) {
super();
setNativeObject(json);
}
public GsonStructure (JsonArray json) {
super();
setNativeArray(json);
}
public void setNativeObject (JsonObject json) {
this.rootType = ROOT_TYPE.OBJECT;
this.nativeRoot = json;
@ -111,8 +102,7 @@ public class GsonStructure implements JsonLikeStructure {
if (nextInt == '{') {
JsonObject root = gson.fromJson(pbr, JsonObject.class);
setNativeObject(root);
} else
if (nextInt == '[') {
} else if (nextInt == '[') {
JsonArray root = gson.fromJson(pbr, JsonArray.class);
setNativeArray(root);
}

View File

@ -151,6 +151,8 @@ public class Constants {
public static final String PARAM_INCLUDE = "_include";
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
public static final String PARAM_INCLUDE_RECURSE = "_include" + PARAM_INCLUDE_QUALIFIER_RECURSE;
public static final String PARAM_INCLUDE_QUALIFIER_ITERATE = ":iterate";
public static final String PARAM_INCLUDE_ITERATE = "_include" + PARAM_INCLUDE_QUALIFIER_ITERATE;
public static final String PARAM_LASTUPDATED = "_lastUpdated";
public static final String PARAM_NARRATIVE = "_narrative";
public static final String PARAM_PAGINGACTION = "_getpages";
@ -163,6 +165,7 @@ public class Constants {
public static final String PARAM_RESPONSE_URL = "response-url"; //Used in messaging
public static final String PARAM_REVINCLUDE = "_revinclude";
public static final String PARAM_REVINCLUDE_RECURSE = PARAM_REVINCLUDE + PARAM_INCLUDE_QUALIFIER_RECURSE;
public static final String PARAM_REVINCLUDE_ITERATE = PARAM_REVINCLUDE + PARAM_INCLUDE_QUALIFIER_ITERATE;
public static final String PARAM_SEARCH = "_search";
public static final String PARAM_SECURITY = "_security";
public static final String PARAM_SINCE = "_since";
@ -220,17 +223,35 @@ public class Constants {
public static final String CASCADE_DELETE = "delete";
public static final int MAX_RESOURCE_NAME_LENGTH = 100;
public static final String CACHE_CONTROL_PRIVATE = "private";
public static final String CT_FHIR_NDJSON = "application/fhir+ndjson";
public static final String CT_APP_NDJSON = "application/ndjson";
public static final String CT_NDJSON = "ndjson";
public static final Set<String> CTS_NDJSON;
public static final String HEADER_PREFER_RESPOND_ASYNC = "respond-async";
public static final int STATUS_HTTP_412_PAYLOAD_TOO_LARGE = 413;
public static final String OPERATION_NAME_GRAPHQL = "$graphql";
/**
* Note that this constant is used in a number of places including DB column lengths! Be careful if you decide to change it.
*/
public static final int REQUEST_ID_LENGTH = 16;
public static final int STATUS_HTTP_202_ACCEPTED = 202;
public static final String HEADER_X_PROGRESS = "X-Progress";
public static final String HEADER_RETRY_AFTER = "Retry-After";
/**
* Operation name for the $lastn operation
*/
public static final String OPERATION_LASTN = "$lastn";
static {
CHARSET_UTF8 = StandardCharsets.UTF_8;
CHARSET_US_ASCII = StandardCharsets.ISO_8859_1;
HashSet<String> ctsNdjson = new HashSet<>();
ctsNdjson.add(CT_FHIR_NDJSON);
ctsNdjson.add(CT_APP_NDJSON);
ctsNdjson.add(CT_NDJSON);
CTS_NDJSON = Collections.unmodifiableSet(ctsNdjson);
HashMap<Integer, String> statusNames = new HashMap<>();
statusNames.put(200, "OK");
statusNames.put(201, "Created");

View File

@ -19,14 +19,17 @@ package ca.uhn.fhir.rest.api;
* limitations under the License.
* #L%
*/
import java.util.*;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.api.BundleInclusionRule;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* This interface should be considered experimental and will likely change in future releases of HAPI. Use with caution!
@ -39,7 +42,15 @@ public interface IVersionSpecificBundleFactory {
IBaseResource getResourceBundle();
void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType);
/**
* @deprecated This was deprecated in HAPI FHIR 4.1.0 as it provides duplicate functionality to the {@link #addRootPropertiesToBundle(String, String, String, String, String, Integer, BundleTypeEnum, IPrimitiveType)}
* and {@link #addResourcesToBundle(List, BundleTypeEnum, String, BundleInclusionRule, Set)} methods
*/
@Deprecated
default void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
addRootPropertiesToBundle(null, null, null, null, null, theResult.size(), theBundleType, null);
addResourcesToBundle(new ArrayList<>(theResult), theBundleType, null, null, null);
}
void initializeWithBundleResource(IBaseResource theResource);

View File

@ -0,0 +1,49 @@
package ca.uhn.fhir.rest.api;
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import javax.annotation.Nullable;
public class PreferHeader {
private PreferReturnEnum myReturn;
private boolean myRespondAsync;
public @Nullable
PreferReturnEnum getReturn() {
return myReturn;
}
public PreferHeader setReturn(PreferReturnEnum theReturn) {
myReturn = theReturn;
return this;
}
public boolean getRespondAsync() {
return myRespondAsync;
}
public PreferHeader setRespondAsync(boolean theRespondAsync) {
myRespondAsync = theRespondAsync;
return this;
}
}

View File

@ -1,6 +1,6 @@
package ca.uhn.fhir.rest.api;
/*
/*-
* #%L
* HAPI FHIR - Core Library
* %%
@ -29,16 +29,20 @@ public enum PreferReturnEnum {
REPRESENTATION("representation"), MINIMAL("minimal"), OPERATION_OUTCOME("OperationOutcome");
private String myHeaderValue;
private static HashMap<String, PreferReturnEnum> ourValues;
private String myHeaderValue;
private PreferReturnEnum(String theHeaderValue) {
PreferReturnEnum(String theHeaderValue) {
myHeaderValue = theHeaderValue;
}
public String getHeaderValue() {
return myHeaderValue;
}
public static PreferReturnEnum fromHeaderValue(String theHeaderValue) {
if (ourValues == null) {
HashMap<String, PreferReturnEnum> values = new HashMap<String, PreferReturnEnum>();
HashMap<String, PreferReturnEnum> values = new HashMap<>();
for (PreferReturnEnum next : PreferReturnEnum.values()) {
values.put(next.getHeaderValue(), next);
}
@ -47,8 +51,4 @@ public enum PreferReturnEnum {
return ourValues.get(theHeaderValue);
}
public String getHeaderValue() {
return myHeaderValue;
}
}

View File

@ -92,10 +92,11 @@ public interface IRestfulClient {
/**
* Register a new interceptor for this client. An interceptor can be used to add additional
* logging, or add security headers, or pre-process responses, etc.
*
* @deprecated Use {@link #getInterceptorService()} to access the list of inteerceptors, register them, and unregister them
* <p>
* This is a convenience method for performing the following call:
* <code>getInterceptorService().registerInterceptor(theInterceptor)</code>
* </p>
*/
@Deprecated
void registerInterceptor(IClientInterceptor theInterceptor);
/**
@ -114,11 +115,12 @@ public interface IRestfulClient {
void setSummary(SummaryEnum theSummary);
/**
* Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
*
* @deprecated Use {@link #getInterceptorService()} to access the list of inteerceptors, register them, and unregister them
* Remove an interceptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}.
* <p>
* This is a convenience method for performing the following call:
* <code>getInterceptorService().unregisterInterceptor(theInterceptor)</code>
* </p>
*/
@Deprecated
void unregisterInterceptor(IClientInterceptor theInterceptor);
/**

View File

@ -47,7 +47,7 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
break;
} else {
char nextChar = theString.charAt(offset);
if (nextChar == '-' || Character.isDigit(nextChar)) {
if (nextChar == '-' || nextChar == '%' || Character.isDigit(nextChar)) {
break;
}
}

View File

@ -19,25 +19,28 @@ package ca.uhn.fhir.rest.param;
* limitations under the License.
* #L%
*/
import static ca.uhn.fhir.model.primitive.IdDt.isValidLong;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.math.BigDecimal;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.util.CoverageIgnore;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.util.CoverageIgnore;
import java.math.BigDecimal;
import static ca.uhn.fhir.model.primitive.IdDt.isValidLong;
import static org.apache.commons.lang3.StringUtils.*;
public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/ {
private String myChain;
private String myResourceType;
private String myBaseUrl;
private String myValue;
private String myIdPart;
private final IdDt myId = new IdDt();
/**
* Constructor
*/
@ -64,12 +67,15 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
* Constructor
*/
public ReferenceParam(String theResourceType, String theChain, String theValue) {
String qualifier = "";
if (isNotBlank(theResourceType)) {
setValue(theResourceType + "/" + theValue);
} else {
setValue(theValue);
qualifier = ":" + theResourceType;
}
setChain(theChain);
if (isNotBlank(theChain)) {
qualifier = qualifier + "." + theChain;
}
setValueAsQueryToken(null, null, qualifier, theValue);
}
@Override
@ -91,55 +97,61 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
@Override
String doGetValueAsQueryToken(FhirContext theContext) {
if (isBlank(myId.getResourceType())) {
return myId.getValue(); // e.g. urn:asdjd or 123 or cid:wieiuru or #1
if (isBlank(getResourceType())) {
return myValue; // e.g. urn:asdjd or 123 or cid:wieiuru or #1
} else {
if (isBlank(getChain())) {
return getResourceType() + "/" + myId.getIdPart();
if (isBlank(getChain()) && isNotBlank(getResourceType())) {
return getResourceType() + "/" + getIdPart();
}
return myId.getIdPart();
return myValue;
}
}
@Override
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
String q = theQualifier;
String resourceType = null;
boolean skipSetValue = false;
if (isNotBlank(q)) {
if (q.startsWith(":")) {
int nextIdx = q.indexOf('.');
if (nextIdx != -1) {
resourceType = q.substring(1, nextIdx);
myChain = q.substring(nextIdx + 1);
// type is explicitly defined so use it
myId.setParts(null, resourceType, theValue, null);
skipSetValue = true;
myResourceType = q.substring(1, nextIdx);
} else {
resourceType = q.substring(1);
myChain = null;
myResourceType = q.substring(1);
}
myValue = theValue;
myIdPart = theValue;
IdDt id = new IdDt(theValue);
if (!id.hasBaseUrl() && id.hasIdPart() && id.hasResourceType()) {
if (id.getResourceType().equals(myResourceType)) {
myIdPart = id.getIdPart();
}
}
} else if (q.startsWith(".")) {
myChain = q.substring(1);
// type not defined but this is a chain, so treat value as opaque
myId.setParts(null, null, theValue, null);
skipSetValue = true;
myResourceType = null;
myValue = theValue;
myIdPart = theValue;
}
} else {
myChain = null;
myValue = theValue;
IdDt id = new IdDt(theValue);
myResourceType = id.getResourceType();
myIdPart = id.getIdPart();
myBaseUrl = id.getBaseUrl();
}
if (!skipSetValue) {
setValue(theValue);
if (isNotBlank(resourceType) && isBlank(getResourceType())) {
setValue(resourceType + '/' + theValue);
}
}
}
@CoverageIgnore
public String getBaseUrl() {
return myId.getBaseUrl();
return myBaseUrl;
}
@ -147,24 +159,34 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
return myChain;
}
public ReferenceParam setChain(String theChain) {
myChain = theChain;
return this;
}
@CoverageIgnore
public String getIdPart() {
return myId.getIdPart();
return myIdPart;
}
@CoverageIgnore
public BigDecimal getIdPartAsBigDecimal() {
return myId.getIdPartAsBigDecimal();
return new IdDt(myValue).getIdPartAsBigDecimal();
}
@CoverageIgnore
public Long getIdPartAsLong() {
return myId.getIdPartAsLong();
return new IdDt(myValue).getIdPartAsLong();
}
public String getResourceType() {
return myId.getResourceType();
if (isNotBlank(myResourceType)) {
return myResourceType;
}
if (isBlank(myChain)) {
return new IdDt(myValue).getResourceType();
}
return null;
}
public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) {
@ -175,11 +197,21 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
}
public String getValue() {
return myId.getValue();
return myValue;
}
public ReferenceParam setValue(String theValue) {
IdDt id = new IdDt(theValue);
String qualifier= null;
if (id.hasResourceType()) {
qualifier = ":" + id.getResourceType();
}
setValueAsQueryToken(null, null, qualifier, id.getIdPart());
return this;
}
public boolean hasResourceType() {
return myId.hasResourceType();
return isNotBlank(myResourceType);
}
@Override
@ -187,16 +219,6 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
return true;
}
public ReferenceParam setChain(String theChain) {
myChain = theChain;
return this;
}
public ReferenceParam setValue(String theValue) {
myId.setValue(theValue);
return this;
}
/**
* Returns a new param containing the same value as this param, but with the type copnverted
* to {@link DateParam}. This is useful if you are using reference parameters and want to handle

View File

@ -0,0 +1,45 @@
package ca.uhn.fhir.util;
/*-
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.*;
public class ArrayUtil {
/** Non instantiable */
private ArrayUtil() {}
/**
* Takes in a list like "foo, bar,, baz" and returns a set containing only ["foo", "bar", "baz"]
*/
public static Set<String> commaSeparatedListToCleanSet(String theValueAsString) {
Set<String> resourceTypes;
resourceTypes = Arrays.stream(split(theValueAsString, ","))
.map(t->trim(t))
.filter(t->isNotBlank(t))
.collect(Collectors.toSet());
return resourceTypes;
}
}

View File

@ -46,12 +46,14 @@ public class BundleUtil {
private final RequestTypeEnum myRequestType;
private final IBaseResource myResource;
private final String myUrl;
private final String myConditionalUrl;
BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource, String theConditionalUrl) {
super();
myRequestType = theRequestType;
myUrl = theUrl;
myResource = theResource;
myConditionalUrl = theConditionalUrl;
}
public RequestTypeEnum getRequestType() {
@ -62,6 +64,10 @@ public class BundleUtil {
return myResource;
}
public String getConditionalUrl() {
return myConditionalUrl;
}
public String getUrl() {
return myUrl;
}
@ -190,19 +196,21 @@ public class BundleUtil {
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
BaseRuntimeElementCompositeDefinition<?> requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
BaseRuntimeChildDefinition urlChild = requestElem.getChildByName("url");
BaseRuntimeChildDefinition requestUrlChild = requestElem.getChildByName("url");
BaseRuntimeChildDefinition requestIfNoneExistChild = requestElem.getChildByName("ifNoneExist");
BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
for (IBase nextEntry : entries) {
IBaseResource resource = null;
String url = null;
RequestTypeEnum requestType = null;
String conditionalUrl = null;
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
resource = (IBaseResource) next;
}
for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
for (IBase nextUrl : urlChild.getAccessor().getValues(nextRequest)) {
for (IBase nextUrl : requestUrlChild.getAccessor().getValues(nextRequest)) {
url = ((IPrimitiveType<?>) nextUrl).getValueAsString();
}
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
@ -211,13 +219,29 @@ public class BundleUtil {
requestType = RequestTypeEnum.valueOf(methodString);
}
}
if (requestType != null) {
//noinspection EnumSwitchStatementWhichMissesCases
switch (requestType) {
case PUT:
conditionalUrl = url != null && url.contains("?") ? url : null;
break;
case POST:
List<IBase> ifNoneExistReps = requestIfNoneExistChild.getAccessor().getValues(nextRequest);
if (ifNoneExistReps.size() > 0) {
IPrimitiveType<?> ifNoneExist = (IPrimitiveType<?>) ifNoneExistReps.get(0);
conditionalUrl = ifNoneExist.getValueAsString();
}
break;
}
}
}
/*
* All 3 might be null - That's ok because we still want to know the
* order in the original bundle.
*/
retVal.add(new BundleEntryParts(requestType, url, resource));
retVal.add(new BundleEntryParts(requestType, url, resource, conditionalUrl));
}

View File

@ -216,12 +216,12 @@ public class FhirTerser {
}
public Object getSingleValueOrNull(IBase theTarget, String thePath) {
Class<Object> wantedType = Object.class;
Class<IBase> wantedType = IBase.class;
return getSingleValueOrNull(theTarget, thePath, wantedType);
}
public <T> T getSingleValueOrNull(IBase theTarget, String thePath, Class<T> theWantedType) {
public <T extends IBase> T getSingleValueOrNull(IBase theTarget, String thePath, Class<T> theWantedType) {
Validate.notNull(theTarget, "theTarget must not be null");
Validate.notBlank(thePath, "thePath must not be empty");
@ -241,12 +241,12 @@ public class FhirTerser {
return retVal.get(0);
}
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass) {
private <T extends IBase> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, IBase theCurrentObj, List<String> theSubList, Class<T> theWantedClass) {
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
}
@SuppressWarnings("unchecked")
private <T> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, Object theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
private <T extends IBase> List<T> getValues(BaseRuntimeElementCompositeDefinition<?> theCurrentDef, IBase theCurrentObj, List<String> theSubList, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
String name = theSubList.get(0);
List<T> retVal = new ArrayList<>();
@ -325,7 +325,7 @@ public class FhirTerser {
List<T> values = retVal;
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass());
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
@ -410,7 +410,7 @@ public class FhirTerser {
List<T> values = retVal;
retVal = new ArrayList<>();
for (T nextElement : values) {
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition((Class<? extends IBase>) nextElement.getClass());
BaseRuntimeElementCompositeDefinition<?> nextChildDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(nextElement.getClass());
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
retVal.addAll(foundValues);
}
@ -476,9 +476,10 @@ public class FhirTerser {
* @return A list of values of type {@link Object}.
*/
public List<Object> getValues(IBaseResource theResource, String thePath) {
Class<Object> wantedClass = Object.class;
Class<IBase> wantedClass = IBase.class;
return getValues(theResource, thePath, wantedClass);
List values = getValues(theResource, thePath, wantedClass);
return values;
}
/**
@ -491,9 +492,10 @@ public class FhirTerser {
* @return A list of values of type {@link Object}.
*/
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate) {
Class<Object> wantedClass = Object.class;
Class<IBase> wantedClass = IBase.class;
return getValues(theResource, thePath, wantedClass, theCreate);
List retVal = getValues(theResource, thePath, wantedClass, theCreate);
return retVal;
}
/**
@ -507,9 +509,10 @@ public class FhirTerser {
* @return A list of values of type {@link Object}.
*/
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) {
Class<Object> wantedClass = Object.class;
Class<IBase> wantedClass = IBase.class;
return getValues(theResource, thePath, wantedClass, theCreate, theAddExtension);
List retVal = getValues(theResource, thePath, wantedClass, theCreate, theAddExtension);
return retVal;
}
/**
@ -522,7 +525,7 @@ public class FhirTerser {
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass) {
public <T extends IBase> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass);
@ -539,7 +542,7 @@ public class FhirTerser {
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate) {
public <T extends IBase> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, false);
@ -557,7 +560,7 @@ public class FhirTerser {
* @param <T> Type declared by <code>theWantedClass</code>
* @return A list of values of type <code>theWantedClass</code>.
*/
public <T> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
public <T extends IBase> List<T> getValues(IBaseResource theResource, String thePath, Class<T> theWantedClass, boolean theCreate, boolean theAddExtension) {
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List<String> parts = parsePath(def, thePath);
return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);
@ -728,7 +731,12 @@ public class FhirTerser {
continue;
}
BaseRuntimeElementDefinition<?> childElementDef;
childElementDef = nextChild.getChildElementDefinitionByDatatype(nextValue.getClass());
Class<? extends IBase> valueType = nextValue.getClass();
childElementDef = nextChild.getChildElementDefinitionByDatatype(valueType);
while (childElementDef == null && IBase.class.isAssignableFrom(valueType)) {
childElementDef = nextChild.getChildElementDefinitionByDatatype(valueType);
valueType = (Class<? extends IBase>) valueType.getSuperclass();
}
if (childElementDef == null) {
StringBuilder b = new StringBuilder();

View File

@ -108,9 +108,13 @@ public class OperationOutcomeUtil {
if (theOutcome == null) {
return false;
}
return getIssueCount(theCtx, theOutcome) > 0;
}
public static int getIssueCount(FhirContext theCtx, IBaseOperationOutcome theOutcome) {
RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
return issueChild.getAccessor().getValues(theOutcome).size() > 0;
return issueChild.getAccessor().getValues(theOutcome).size();
}
public static IBaseOperationOutcome newInstance(FhirContext theCtx) {
@ -152,5 +156,4 @@ public class OperationOutcomeUtil {
locationChild.getMutator().addValue(theIssue, locationElem);
}
}
}

View File

@ -63,6 +63,9 @@ public class StopWatch {
myStarted = theStart.getTime();
}
public StopWatch(long theL) {
}
private void addNewlineIfContentExists(StringBuilder theB) {
if (theB.length() > 0) {
theB.append("\n");
@ -231,7 +234,12 @@ public class StopWatch {
double denominator = ((double) millisElapsed) / ((double) periodMillis);
return (double) theNumOperations / denominator;
double throughput = (double) theNumOperations / denominator;
if (throughput > theNumOperations) {
throughput = theNumOperations;
}
return throughput;
}
public void restart() {

View File

@ -182,4 +182,13 @@ public class TestUtil {
return defaultString(theString).replace("\r", "");
}
/**
* <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b>
* <p>
* Strip \r chars from a string to account for line ending platform differences
*/
public static String stripWhitespace(String theString) {
return stripReturns(theString).replace(" ", "");
}
}

View File

@ -61,4 +61,14 @@ public interface IBase extends Serializable {
*/
default String fhirType() { return null; }
/**
* Retrieves any user suplied data in this element
*/
Object getUserData(String theName);
/**
* Sets a user supplied data value in this element
*/
void setUserData(String theName, Object theValue);
}

View File

@ -25,5 +25,9 @@ public interface IBaseElement {
IBaseElement setId(String theValue);
String getId();
Object getUserData(String theName);
void setUserData(String theName, Object theValue);
}

View File

@ -60,11 +60,13 @@ ca.uhn.fhir.validation.ValidationResult.noIssuesDetected=No issues detected duri
# JPA Messages
ca.uhn.fhir.jpa.bulk.BulkDataExportSvcImpl.onlyBinarySelected=Binary resources may not be exported with bulk export
ca.uhn.fhir.jpa.bulk.BulkDataExportSvcImpl.unknownResourceType=Unknown or unsupported resource type: {0}
ca.uhn.fhir.jpa.config.HapiFhirHibernateJpaDialect.resourceVersionConstraintFailure=The operation has failed with a version constraint failure. This generally means that two clients/threads were trying to update the same resource at the same time, and this request was chosen as the failing request.
ca.uhn.fhir.jpa.config.HapiFhirHibernateJpaDialect.resourceIndexedCompositeStringUniqueConstraintFailure=The operation has failed with a unique index constraint failure. This probably means that the operation was trying to create/update a resource that would have resulted in a duplicate value for a unique index.
ca.uhn.fhir.jpa.config.HapiFhirHibernateJpaDialect.forcedIdConstraintFailure=The operation has failed with a client-assigned ID constraint failure. This typically means that multiple client threads are trying to create a new resource with the same client-assigned ID at the same time, and this thread was chosen to be rejected.
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.externalizedBinaryStorageExtensionFoundInRequestBody=Illegal extension found in request payload: {0}
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.incomingNoopInTransaction=Transaction contains resource with operation NOOP. This is only valid as a response operation, not in a request
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlInvalidResourceType=Invalid match URL "{0}" - Unknown resource type: "{1}"
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlNoMatches=Invalid match URL "{0}" - No resources match this search

View File

@ -78,6 +78,7 @@ public abstract class BaseMigrateDatabaseCommand<T extends Enum> extends BaseCom
addRequiredOption(retVal, "t", "to", "Version", "The database schema version to migrate TO");
addRequiredOption(retVal, "d", "driver", "Driver", "The database driver to use (Options are " + driverOptions() + ")");
addOptionalOption(retVal, "x", "flags", "Flags", "A comma-separated list of any specific migration flags (these flags are version specific, see migrator documentation for details)");
addOptionalOption(retVal, null, "no-column-shrink", false, "If this flag is set, the system will not attempt to reduce the length of columns. This is useful in environments with a lot of existing data, where shrinking a column can take a very long time.");
return retVal;
}
@ -106,6 +107,7 @@ public abstract class BaseMigrateDatabaseCommand<T extends Enum> extends BaseCom
validateVersionSupported(to);
boolean dryRun = theCommandLine.hasOption("r");
boolean noColumnShrink = theCommandLine.hasOption("no-column-shrink");
String flags = theCommandLine.getOptionValue("x");
myFlags = Arrays.stream(defaultString(flags).split(","))
@ -119,6 +121,7 @@ public abstract class BaseMigrateDatabaseCommand<T extends Enum> extends BaseCom
migrator.setUsername(username);
migrator.setPassword(password);
migrator.setDryRun(dryRun);
migrator.setNoColumnShrink(noColumnShrink);
addTasks(migrator, from, to);
migrator.migrate();

View File

@ -715,7 +715,8 @@ public class ExampleDataUploader extends BaseCommand {
ourLog.info("About to upload {} examples in a transaction, {} remaining", subResourceList.size(), resources.size());
IVersionSpecificBundleFactory bundleFactory = ctx.newBundleFactory();
bundleFactory.initializeBundleFromResourceList(null, subResourceList, null, null, 0, BundleTypeEnum.TRANSACTION);
bundleFactory.addRootPropertiesToBundle(null, null, null, null, null, subResourceList.size(), BundleTypeEnum.TRANSACTION, null);
bundleFactory.addResourcesToBundle(new ArrayList<>(subResourceList), BundleTypeEnum.TRANSACTION, null, null, null);
IBaseResource subBundle = bundleFactory.getResourceBundle();
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(subBundle);

View File

@ -5,9 +5,9 @@
if you are using this file as a basis for your own project. -->
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<artifactId>hapi-deployable-pom</artifactId>
<version>4.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
<relativePath>../../hapi-deployable-pom</relativePath>
</parent>
<artifactId>hapi-fhir-cli-jpaserver</artifactId>
@ -131,6 +131,10 @@
<artifactId>Saxon-HE</artifactId>
<groupId>net.sf.saxon</groupId>
</exclusion>
<exclusion>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-core</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
@ -183,15 +187,6 @@
</configuration>
</plugin>
<!-- This plugin is just a part of the HAPI internal build process, you do not need to incude it in your own projects -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- This is to run the integration tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import org.apache.commons.cli.ParseException;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorR4;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

View File

@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.demo;
/*-
* #%L
* HAPI FHIR - Command Line Client - Server WAR
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;

View File

@ -104,14 +104,6 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<classFolders>
<classFolder>${basedir}/target/classes</classFolder>
<classFolder>${basedir}/../hapi-fhir-base/target/classes</classFolder>
</classFolders>
<sourceFolders>
<sourceFolder>${basedir}/src/main/java</sourceFolder>
<sourceFolder>${basedir}/../hapi-fhir-base/src/main/java</sourceFolder>
</sourceFolders>
<dumpOnExit>true</dumpOnExit>
</configuration>
<executions>

View File

@ -877,6 +877,16 @@ public class GenericOkHttpClientDstu2Test {
public List<String> getFormatCommentsPost() {
return null;
}
@Override
public Object getUserData(String theName) {
throw new UnsupportedOperationException();
}
@Override
public void setUserData(String theName, Object theValue) {
throw new UnsupportedOperationException();
}
};
client
@ -1530,53 +1540,6 @@ public class GenericOkHttpClientDstu2Test {
assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass());
}
@Test
public void testTransactionWithListOfResources() throws Exception {
ca.uhn.fhir.model.dstu2.resource.Bundle resp = new ca.uhn.fhir.model.dstu2.resource.Bundle();
resp.addEntry().getResponse().setLocation("Patient/1/_history/1");
resp.addEntry().getResponse().setLocation("Patient/2/_history/2");
String respString = ourCtx.newJsonParser().encodeResourceToString(resp);
ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
ourResponseBody = respString;
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
List<IBaseResource> input = new ArrayList<IBaseResource>();
Patient p1 = new Patient(); // No ID
p1.addName().addFamily("PATIENT1");
input.add(p1);
Patient p2 = new Patient(); // Yes ID
p2.addName().addFamily("PATIENT2");
p2.setId("Patient/2");
input.add(p2);
List<IBaseResource> response = client.transaction()
.withResources(input)
.encodedJson()
.execute();
assertEquals("http://localhost:" + ourPort + "/fhir", ourRequestUri);
assertEquals(2, response.size());
String requestString = ourRequestBodyString;
ca.uhn.fhir.model.dstu2.resource.Bundle requestBundle = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, requestString);
assertEquals(2, requestBundle.getEntry().size());
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
p1 = (Patient) response.get(0);
assertEquals(new IdDt("Patient/1/_history/1"), p1.getId().toUnqualified());
// assertEquals("PATIENT1", p1.getName().get(0).getFamily().get(0).getValue());
p2 = (Patient) response.get(1);
assertEquals(new IdDt("Patient/2/_history/2"), p2.getId().toUnqualified());
// assertEquals("PATIENT2", p2.getName().get(0).getFamily().get(0).getValue());
}
@Test
public void testTransactionWithString() throws Exception {
ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();

View File

@ -43,14 +43,6 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<configuration>
<classFolders>
<classFolder>${basedir}/target/classes</classFolder>
<classFolder>${basedir}/../hapi-fhir-base/target/classes</classFolder>
</classFolders>
<sourceFolders>
<sourceFolder>${basedir}/src/main/java</sourceFolder>
<sourceFolder>${basedir}/../hapi-fhir-base/src/main/java</sourceFolder>
</sourceFolders>
<dumpOnExit>true</dumpOnExit>
</configuration>
<executions>

View File

@ -0,0 +1,40 @@
package ca.uhn.fhir.rest.client.apache;
/*-
* #%L
* HAPI FHIR - Client Framework
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.Constants;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.nio.charset.UnsupportedCharsetException;
/**
* Apache HttpClient request content entity where the body is a FHIR resource, that will
* be encoded as JSON by default
*/
public class ResourceEntity extends StringEntity {
public ResourceEntity(FhirContext theContext, IBaseResource theResource) throws UnsupportedCharsetException {
super(theContext.newJsonParser().encodeResourceToString(theResource), ContentType.parse(Constants.CT_FHIR_JSON_NEW));
}
}

View File

@ -22,11 +22,14 @@ package ca.uhn.fhir.rest.client.impl;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
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.model.primitive.UriDt;
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*;
@ -1761,7 +1764,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
for (Include next : myInclude) {
if (next.isRecurse()) {
addParam(params, Constants.PARAM_INCLUDE_RECURSE, next.getValue());
if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
addParam(params, Constants.PARAM_INCLUDE_ITERATE, next.getValue());
} else {
addParam(params, Constants.PARAM_INCLUDE_RECURSE, next.getValue());
}
} else {
addParam(params, Constants.PARAM_INCLUDE, next.getValue());
}
@ -1769,7 +1776,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
for (Include next : myRevInclude) {
if (next.isRecurse()) {
addParam(params, Constants.PARAM_REVINCLUDE_RECURSE, next.getValue());
if (myContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
addParam(params, Constants.PARAM_REVINCLUDE_ITERATE, next.getValue());
} else {
addParam(params, Constants.PARAM_REVINCLUDE_RECURSE, next.getValue());
}
} else {
addParam(params, Constants.PARAM_REVINCLUDE, next.getValue());
}
@ -2038,7 +2049,35 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public ITransactionTyped<List<IBaseResource>> withResources(List<? extends IBaseResource> theResources) {
Validate.notNull(theResources, "theResources must not be null");
return new TransactionExecutable<List<IBaseResource>>(theResources);
for (IBaseResource next : theResources) {
String entryMethod = null;
if (next instanceof IResource) {
BundleEntryTransactionMethodEnum entryMethodEnum = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) next);
if (entryMethodEnum != null) {
entryMethod = entryMethodEnum.getCode();
}
} else {
entryMethod = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IAnyResource) next);
}
if (isBlank(entryMethod)) {
if (isBlank(next.getIdElement().getValue())) {
entryMethod = "POST";
} else {
entryMethod = "PUT";
}
if (next instanceof IResource) {
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put((IResource) next, BundleEntryTransactionMethodEnum.valueOf(entryMethod));
} else {
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put((IAnyResource) next, entryMethod);
}
}
}
return new TransactionExecutable<>(theResources);
}
}

View File

@ -22,6 +22,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* #L%
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -52,7 +53,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
private boolean myOmitResourceId = false;
private Map<String, List<String>> myParams;
private final IBaseResource myResource;
private final List<? extends IBaseResource> myResources;
private final List<IBaseResource> myResources;
private final String myUrlPath;
private IIdType myForceResourceId;
@ -70,7 +71,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
super(theContext);
myResource = null;
myUrlPath = null;
myResources = theResources;
myResources = new ArrayList<>(theResources);
myContents = null;
myBundleType = theBundleType;
}
@ -172,11 +173,8 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
parser.setOmitResourceId(myOmitResourceId);
if (myResources != null) {
IVersionSpecificBundleFactory bundleFactory = getContext().newBundleFactory();
bundleFactory.initializeBundleFromResourceList("", myResources, "", "", myResources.size(), myBundleType);
IBaseResource bundle = bundleFactory.getResourceBundle();
if (bundle != null) {
return parser.encodeResourceToString(bundle);
}
bundleFactory.addRootPropertiesToBundle(null, null, null, null, null, myResources.size(), myBundleType, null);
bundleFactory.addResourcesToBundle(myResources, myBundleType, null, null, null);
IBaseResource bundleRes = bundleFactory.getResourceBundle();
return parser.encodeResourceToString(bundleRes);
} else if (myContents != null) {

View File

@ -23,6 +23,7 @@ import java.util.*;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.api.*;
@ -64,23 +65,30 @@ class IncludeParameter extends BaseQueryParameter {
if (myInstantiableCollectionType == null) {
if (mySpecType == Include.class) {
convertAndAddIncludeToList(retVal, (Include) theObject);
convertAndAddIncludeToList(retVal, (Include) theObject, theContext);
} else {
retVal.add(QualifiedParamList.singleton(((String) theObject)));
}
} else {
Collection<Include> val = (Collection<Include>) theObject;
for (Include include : val) {
convertAndAddIncludeToList(retVal, include);
convertAndAddIncludeToList(retVal, include, theContext);
}
}
return retVal;
}
private void convertAndAddIncludeToList(ArrayList<QualifiedParamList> retVal, Include include) {
String qualifier = include.isRecurse() ? Constants.PARAM_INCLUDE_QUALIFIER_RECURSE : null;
retVal.add(QualifiedParamList.singleton(qualifier, include.getValue()));
private void convertAndAddIncludeToList(ArrayList<QualifiedParamList> theQualifiedParamLists, Include theInclude, FhirContext theContext) {
String qualifier = null;
if (theInclude.isRecurse()) {
if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
qualifier = Constants.PARAM_INCLUDE_QUALIFIER_ITERATE;
} else {
qualifier = Constants.PARAM_INCLUDE_QUALIFIER_RECURSE;
}
}
theQualifiedParamLists.add(QualifiedParamList.singleton(qualifier, theInclude.getValue()));
}
public Set<String> getAllow() {

109
hapi-fhir-docs/pom.xml Normal file
View File

@ -0,0 +1,109 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>4.1.0-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-docs</artifactId>
<packaging>jar</packaging>
<name>HAPI FHIR - Docs</name>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-client-okhttp</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
<version>1.1.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>4.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-subscription</artifactId>
<version>4.1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.28</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.java</include>
</includes>
</resource>
</resources>
</build>
</project>

View File

@ -0,0 +1,92 @@
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.jdom2.Content;
import org.jdom2.Element;
import org.jdom2.Namespace;
import org.jdom2.Text;
import org.jdom2.input.DOMBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* This is just here to force a javadoc to be built in order to keep
* Maven Central happy
*/
public class ChangelogMigrator {
private static final Logger ourLog = LoggerFactory.getLogger(ChangelogMigrator.class);
private static final Namespace NS = Namespace.getNamespace( "http://maven.apache.org/changes/1.0.0");
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
org.jdom2.Document document = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//If want to make namespace aware.
//factory.setNamespaceAware(true);
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
org.w3c.dom.Document w3cDocument = documentBuilder.parse(new File("src/changes/changes.xml"));
document = new DOMBuilder().build(w3cDocument);
int actionCount = 0;
int releaseCount = 0;
Element docElement = document.getRootElement();
Element bodyElement = docElement.getChild("body", NS);
List<Element> releases = bodyElement.getChildren("release", NS);
for (Element nextRelease : releases) {
String version = nextRelease.getAttributeValue("version");
String date = nextRelease.getAttributeValue("date");
String description = nextRelease.getAttributeValue("description");
ourLog.info("Found release {} - {} - {}", version, date, description);
releaseCount++;
for (Element nextAction : nextRelease.getChildren("action", NS)) {
StringBuilder contentBuilder = new StringBuilder();
for (Content nextContents : nextAction.getContent()) {
if (nextContents instanceof Text) {
String text = ((Text) nextContents).getTextNormalize();
contentBuilder.append(text);
} else {
throw new IllegalStateException("Unknown type: " + nextContents.getClass());
}
}
actionCount++;
}
}
ourLog.info("Found {} releases and {} actions", releaseCount, actionCount);
}
}

View File

@ -0,0 +1,233 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.interceptor.auth.*;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Patient;
import java.util.List;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@SuppressWarnings("unused")
public class AuthorizationInterceptors {
public class PatientResourceProvider implements IResourceProvider
{
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
public MethodOutcome create(@ResourceParam Patient thePatient, RequestDetails theRequestDetails) {
return new MethodOutcome(); // populate this
}
}
//START SNIPPET: patientAndAdmin
@SuppressWarnings("ConstantConditions")
public class PatientAndAdminAuthorizationInterceptor extends AuthorizationInterceptor {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
// Process authorization header - The following is a fake
// implementation. Obviously we'd want something more real
// for a production scenario.
//
// In this basic example we have two hardcoded bearer tokens,
// one which is for a user that has access to one patient, and
// another that has full access.
IdType userIdPatientId = null;
boolean userIsAdmin = false;
String authHeader = theRequestDetails.getHeader("Authorization");
if ("Bearer dfw98h38r".equals(authHeader)) {
// This user has access only to Patient/1 resources
userIdPatientId = new IdType("Patient", 1L);
} else if ("Bearer 39ff939jgg".equals(authHeader)) {
// This user has access to everything
userIsAdmin = true;
} else {
// Throw an HTTP 401
throw new AuthenticationException("Missing or invalid Authorization header value");
}
// If the user is a specific patient, we create the following rule chain:
// Allow the user to read anything in their own patient compartment
// Allow the user to write anything in their own patient compartment
// If a client request doesn't pass either of the above, deny it
if (userIdPatientId != null) {
return new RuleBuilder()
.allow().read().allResources().inCompartment("Patient", userIdPatientId).andThen()
.allow().write().allResources().inCompartment("Patient", userIdPatientId).andThen()
.denyAll()
.build();
}
// If the user is an admin, allow everything
if (userIsAdmin) {
return new RuleBuilder()
.allowAll()
.build();
}
// By default, deny everything. This should never get hit, but it's
// good to be defensive
return new RuleBuilder()
.denyAll()
.build();
}
}
//END SNIPPET: patientAndAdmin
//START SNIPPET: conditionalUpdate
@Update()
public MethodOutcome update(
@IdParam IdType theId,
@ResourceParam Patient theResource,
@ConditionalUrlParam String theConditionalUrl,
ServletRequestDetails theRequestDetails,
IInterceptorBroadcaster theInterceptorBroadcaster) {
// If we're processing a conditional URL...
if (isNotBlank(theConditionalUrl)) {
// Pretend we've done the conditional processing. Now let's
// notify the interceptors that an update has been performed
// and supply the actual ID that's being updated
IdType actual = new IdType("Patient", "1123");
}
// In a real server, perhaps we would process the conditional
// request differently and follow a separate path. Either way,
// let's pretend there is some storage code here.
theResource.setId(theId.withVersion("2"));
// Notify the interceptor framework when we're about to perform an update. This is
// useful as the authorization interceptor will pick this event up and use it
// to factor into a decision about whether the operation should be allowed to proceed.
IBaseResource previousContents = theResource;
IBaseResource newContents = theResource;
HookParams params = new HookParams()
.add(IBaseResource.class, previousContents)
.add(IBaseResource.class, newContents)
.add(RequestDetails.class, theRequestDetails)
.add(ServletRequestDetails.class, theRequestDetails);
theInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, params);
MethodOutcome retVal = new MethodOutcome();
retVal.setCreated(true);
retVal.setResource(theResource);
return retVal;
}
//END SNIPPET: conditionalUpdate
public void authorizeTenantAction() {
//START SNIPPET: authorizeTenantAction
new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
.allow().read().resourcesOfType(Patient.class).withAnyId().forTenantIds("TENANTA").andThen()
.build();
}
};
//END SNIPPET: authorizeTenantAction
//START SNIPPET: patchAll
new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
return new RuleBuilder()
// Authorize patch requests
.allow().patch().allRequests().andThen()
// Authorize actual writes that patch may perform
.allow().write().allResources().inCompartment("Patient", new IdType("Patient/123")).andThen()
.build();
}
};
//END SNIPPET: patchAll
}
//START SNIPPET: narrowing
public class MyPatientSearchNarrowingInterceptor extends SearchNarrowingInterceptor {
/**
* This method must be overridden to provide the list of compartments
* and/or resources that the current user should have access to
*/
@Override
protected AuthorizedList buildAuthorizedList(RequestDetails theRequestDetails) {
// Process authorization header - The following is a fake
// implementation. Obviously we'd want something more real
// for a production scenario.
//
// In this basic example we have two hardcoded bearer tokens,
// one which is for a user that has access to one patient, and
// another that has full access.
String authHeader = theRequestDetails.getHeader("Authorization");
if ("Bearer dfw98h38r".equals(authHeader)) {
// This user will have access to two compartments
return new AuthorizedList()
.addCompartment("Patient/123")
.addCompartment("Patient/456");
} else if ("Bearer 39ff939jgg".equals(authHeader)) {
// This user has access to everything
return new AuthorizedList();
} else {
throw new AuthenticationException("Unknown bearer token");
}
}
}
//END SNIPPET: narrowing
}

View File

@ -0,0 +1,43 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
import ca.uhn.fhir.rest.server.util.ITestingUiClientFactory;
import javax.servlet.http.HttpServletRequest;
public class AuthorizingTesterUiClientFactory implements ITestingUiClientFactory {
@Override
public IGenericClient newClient(FhirContext theFhirContext, HttpServletRequest theRequest, String theServerBaseUrl) {
// Create a client
IGenericClient client = theFhirContext.newRestfulGenericClient(theServerBaseUrl);
// Register an interceptor which adds credentials
client.registerInterceptor(new BasicAuthInterceptor("someusername", "somepassword"));
return client;
}
}

View File

@ -0,0 +1,86 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.RelatedPerson;
import java.util.HashSet;
import java.util.Set;
/**
* @author Bill de Beaubien on 1/13/2016.
*/
public class BundleFetcher {
public static void fetchRestOfBundle(IGenericClient theClient, Bundle theBundle) {
// we need to keep track of which resources are already in the bundle so that if other resources (e.g. Practitioner) are _included,
// we don't end up with multiple copies
Set<String> resourcesAlreadyAdded = new HashSet<String>();
addInitialUrlsToSet(theBundle, resourcesAlreadyAdded);
Bundle partialBundle = theBundle;
for (;;) {
if (partialBundle.getLink(IBaseBundle.LINK_NEXT) != null) {
partialBundle = theClient.loadPage().next(partialBundle).execute();
addAnyResourcesNotAlreadyPresentToBundle(theBundle, partialBundle, resourcesAlreadyAdded);
} else {
break;
}
}
// the self and next links for the aggregated bundle aren't really valid anymore, so remove them
theBundle.getLink().clear();
}
private static void addInitialUrlsToSet(Bundle theBundle, Set<String> theResourcesAlreadyAdded) {
for (Bundle.BundleEntryComponent entry : theBundle.getEntry()) {
theResourcesAlreadyAdded.add(entry.getFullUrl());
}
}
private static void addAnyResourcesNotAlreadyPresentToBundle(Bundle theAggregatedBundle, Bundle thePartialBundle, Set<String> theResourcesAlreadyAdded) {
for (Bundle.BundleEntryComponent entry : thePartialBundle.getEntry()) {
if (!theResourcesAlreadyAdded.contains(entry.getFullUrl())) {
theResourcesAlreadyAdded.add(entry.getFullUrl());
theAggregatedBundle.getEntry().add(entry);
}
}
}
public static void main(String[] args) {
FhirContext ctx = FhirContext.forR4();
String serverBase = "http://fhirtest.uhn.ca/baseR4";
IGenericClient client = ctx.newRestfulGenericClient(serverBase);
// use RelatedPerson because there aren't that many on the server
Bundle bundle = client.search().forResource(RelatedPerson.class).returnBundle(Bundle.class).execute();
BundleFetcher.fetchRestOfBundle(client, bundle);
if (bundle.getTotal() != bundle.getEntry().size()) {
System.out.println("Counts didn't match! Expected " + bundle.getTotal() + " but bundle only had " + bundle.getEntry().size() + " entries!");
}
// IParser parser = ctx.newXmlParser().setPrettyPrint(true);
// System.out.println(parser.encodeResourceToString(bundle));
}
}

View File

@ -0,0 +1,249 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.apache.GZipContentInterceptor;
import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor;
import ca.uhn.fhir.rest.client.interceptor.CookieInterceptor;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.Patient;
public class ClientExamples {
public interface IPatientClient extends IBasicClient {
// nothing yet
}
@SuppressWarnings("unused")
public void createProxy() {
// START SNIPPET: proxy
FhirContext ctx = FhirContext.forDstu2();
// Set connections to access the network via the HTTP proxy at
// example.com : 8888
ctx.getRestfulClientFactory().setProxy("example.com", 8888);
// If the proxy requires authentication, use the following as well
ctx.getRestfulClientFactory().setProxyCredentials("theUsername", "thePassword");
// Create the client
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
// END SNIPPET: proxy
}
@SuppressWarnings("unused")
public void processMessage() {
// START SNIPPET: processMessage
FhirContext ctx = FhirContext.forDstu3();
// Create the client
IGenericClient client = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
Bundle bundle = new Bundle();
// ..populate the bundle..
Bundle response = client
.operation()
.processMessage() // New operation for sending messages
.setMessageBundle(bundle)
.asynchronous(Bundle.class)
.execute();
// END SNIPPET: processMessage
}
@SuppressWarnings("unused")
public void cacheControl() {
FhirContext ctx = FhirContext.forDstu3();
// Create the client
IGenericClient client = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
Bundle bundle = new Bundle();
// ..populate the bundle..
// START SNIPPET: cacheControl
Bundle response = client
.search()
.forResource(Patient.class)
.returnBundle(Bundle.class)
.cacheControl(new CacheControlDirective().setNoCache(true)) // <-- add a directive
.execute();
// END SNIPPET: cacheControl
}
@SuppressWarnings("unused")
public void createOkHttp() {
// START SNIPPET: okhttp
FhirContext ctx = FhirContext.forDstu3();
// Use OkHttp
ctx.setRestfulClientFactory(new OkHttpRestfulClientFactory(ctx));
// Create the client
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
// END SNIPPET: okhttp
}
@SuppressWarnings("unused")
public void createTimeouts() {
// START SNIPPET: timeouts
FhirContext ctx = FhirContext.forDstu2();
// Set how long to try and establish the initial TCP connection (in ms)
ctx.getRestfulClientFactory().setConnectTimeout(20 * 1000);
// Set how long to block for individual read/write operations (in ms)
ctx.getRestfulClientFactory().setSocketTimeout(20 * 1000);
// Create the client
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
// END SNIPPET: timeouts
}
@SuppressWarnings("unused")
public void createSecurity() {
// START SNIPPET: security
// Create a context and get the client factory so it can be configured
FhirContext ctx = FhirContext.forDstu2();
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
// Create an HTTP basic auth interceptor
String username = "foobar";
String password = "boobear";
IClientInterceptor authInterceptor = new BasicAuthInterceptor(username, password);
// If you're usinf an annotation client, use this style to
// register it
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
annotationClient.registerInterceptor(authInterceptor);
// If you're using a generic client, use this instead
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
genericClient.registerInterceptor(authInterceptor);
// END SNIPPET: security
}
@SuppressWarnings("unused")
public void createCookie() {
// START SNIPPET: cookie
// Create a context and get the client factory so it can be configured
FhirContext ctx = FhirContext.forDstu2();
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
// Create a cookie interceptor. This cookie will have the name "mycookie" and
// the value "Chips Ahoy"
CookieInterceptor interceptor = new CookieInterceptor("mycookie=Chips Ahoy");
// Register the interceptor with your client (either style)
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
annotationClient.registerInterceptor(interceptor);
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
annotationClient.registerInterceptor(interceptor);
// END SNIPPET: cookie
}
@SuppressWarnings("unused")
public void gzip() {
// START SNIPPET: gzip
// Create a context and get the client factory so it can be configured
FhirContext ctx = FhirContext.forDstu2();
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
// Register the interceptor with your client (either style)
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
annotationClient.registerInterceptor(new GZipContentInterceptor());
// END SNIPPET: gzip
}
@SuppressWarnings("unused")
public void createSecurityBearer() {
// START SNIPPET: securityBearer
// Create a context and get the client factory so it can be configured
FhirContext ctx = FhirContext.forDstu2();
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
// In reality the token would have come from an authorization server
String token = "3w03fj.r3r3t";
BearerTokenAuthInterceptor authInterceptor = new BearerTokenAuthInterceptor(token);
// Register the interceptor with your client (either style)
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
annotationClient.registerInterceptor(authInterceptor);
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
annotationClient.registerInterceptor(authInterceptor);
// END SNIPPET: securityBearer
}
@SuppressWarnings("unused")
public void createLogging() {
{
// START SNIPPET: logging
// Create a context and get the client factory so it can be configured
FhirContext ctx = FhirContext.forDstu2();
IRestfulClientFactory clientFactory = ctx.getRestfulClientFactory();
// Create a logging interceptor
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
// Optionally you may configure the interceptor (by default only
// summary info is logged)
loggingInterceptor.setLogRequestSummary(true);
loggingInterceptor.setLogRequestBody(true);
// Register the interceptor with your client (either style)
IPatientClient annotationClient = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/fhir");
annotationClient.registerInterceptor(loggingInterceptor);
IGenericClient genericClient = ctx.newRestfulGenericClient("http://localhost:9999/fhir");
genericClient.registerInterceptor(loggingInterceptor);
// END SNIPPET: logging
}
/******************************/
{
// START SNIPPET: clientConfig
// Create a client
FhirContext ctx = FhirContext.forDstu2();
IPatientClient client = ctx.newRestfulClient(IPatientClient.class, "http://localhost:9999/");
// Request JSON encoding from the server (_format=json)
client.setEncoding(EncodingEnum.JSON);
// Request pretty printing from the server (_pretty=true)
client.setPrettyPrint(true);
// END SNIPPET: clientConfig
}
}
}

View File

@ -0,0 +1,110 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import org.hl7.fhir.r4.model.*;
public class ClientTransactionExamples {
public static void main(String[] args) {
conditionalCreate();
}
private static void conditionalCreate() {
//START SNIPPET: conditional
// Create a patient object
Patient patient = new Patient();
patient.addIdentifier()
.setSystem("http://acme.org/mrns")
.setValue("12345");
patient.addName()
.setFamily("Jameson")
.addGiven("J")
.addGiven("Jonah");
patient.setGender(Enumerations.AdministrativeGender.MALE);
// Give the patient a temporary UUID so that other resources in
// the transaction can refer to it
patient.setId(IdType.newRandomUuid());
// Create an observation object
Observation observation = new Observation();
observation.setStatus(Observation.ObservationStatus.FINAL);
observation
.getCode()
.addCoding()
.setSystem("http://loinc.org")
.setCode("789-8")
.setDisplay("Erythrocytes [#/volume] in Blood by Automated count");
observation.setValue(
new Quantity()
.setValue(4.12)
.setUnit("10 trillion/L")
.setSystem("http://unitsofmeasure.org")
.setCode("10*12/L"));
// The observation refers to the patient using the ID, which is already
// set to a temporary UUID
observation.setSubject(new Reference(patient.getIdElement().getValue()));
// Create a bundle that will be used as a transaction
Bundle bundle = new Bundle();
bundle.setType(Bundle.BundleType.TRANSACTION);
// Add the patient as an entry. This entry is a POST with an
// If-None-Exist header (conditional create) meaning that it
// will only be created if there isn't already a Patient with
// the identifier 12345
bundle.addEntry()
.setFullUrl(patient.getIdElement().getValue())
.setResource(patient)
.getRequest()
.setUrl("Patient")
.setIfNoneExist("identifier=http://acme.org/mrns|12345")
.setMethod(Bundle.HTTPVerb.POST);
// Add the observation. This entry is a POST with no header
// (normal create) meaning that it will be created even if
// a similar resource already exists.
bundle.addEntry()
.setResource(observation)
.getRequest()
.setUrl("Observation")
.setMethod(Bundle.HTTPVerb.POST);
// Log the request
FhirContext ctx = FhirContext.forR4();
System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle));
// Create a client and post the transaction to the server
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseR4");
Bundle resp = client.transaction().withBundle(bundle).execute();
// Log the response
System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
//END SNIPPET: conditional
}
}

View File

@ -0,0 +1,87 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
//START SNIPPET: client
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import java.io.IOException;
import java.util.List;
public class CompleteExampleClient {
/**
* This is a simple client interface. It can have many methods for various
* searches but in this case it has only 1.
*/
public interface ClientInterface extends IRestfulClient {
/**
* This is translated into a URL similar to the following:
* http://fhir.healthintersections.com.au/open/Patient?identifier=urn:oid:1.2.36.146.595.217.0.1%7C12345
*/
@Search
List<Patient> findPatientsForMrn(@RequiredParam(name = Patient.SP_IDENTIFIER) Identifier theIdentifier);
}
/**
* The main method here will directly call an open FHIR server and retrieve a
* list of resources matching a given criteria, then load a linked resource.
*/
public static void main(String[] args) throws IOException {
// Create a client factory
FhirContext ctx = FhirContext.forDstu2();
// Create the client
String serverBase = "http://fhir.healthintersections.com.au/open";
ClientInterface client = ctx.newRestfulClient(ClientInterface.class, serverBase);
// Invoke the client to search for patient
Identifier identifier = new Identifier().setSystem("urn:oid:1.2.36.146.595.217.0.1").setValue("12345");
List<Patient> patients = client.findPatientsForMrn(identifier);
System.out.println("Found " + patients.size() + " patients");
// Print a value from the loaded resource
Patient patient = patients.get(0);
System.out.println("Patient Last Name: " + patient.getName().get(0).getFamily());
// Load a referenced resource
Reference managingRef = patient.getManagingOrganization();
Organization org = client.getOrganizationById(managingRef.getReferenceElement());
// Print organization name
System.out.println(org.getName());
}
}
// END SNIPPET: client

View File

@ -0,0 +1,95 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.interceptor.consent.ConsentOutcome;
import ca.uhn.fhir.rest.server.interceptor.consent.IConsentContextServices;
import ca.uhn.fhir.rest.server.interceptor.consent.IConsentService;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Observation;
@SuppressWarnings("unused")
public class ConsentInterceptors {
//START SNIPPET: service
public class MyConsentService implements IConsentService {
/**
* Invoked once at the start of every request
*/
@Override
public ConsentOutcome startOperation(RequestDetails theRequestDetails, IConsentContextServices theContextServices) {
// This means that all requests should flow through the consent service
// This has performance implications - If you know that some requests
// don't need consent checking it is a good idea to return
// ConsentOutcome.AUTHORIZED instead for those requests.
return ConsentOutcome.PROCEED;
}
/**
* Can a given resource be returned to the user?
*/
@Override
public ConsentOutcome canSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
// In this basic example, we will filter out lab results so that they
// are never disclosed to the user. A real interceptor might do something
// more nuanced.
if (theResource instanceof Observation) {
Observation obs = (Observation)theResource;
if (obs.getCategoryFirstRep().hasCoding("http://hl7.org/fhir/codesystem-observation-category.html", "laboratory")) {
return ConsentOutcome.REJECT;
}
}
// Otherwise, allow the
return ConsentOutcome.PROCEED;
}
/**
* Modify resources that are being shown to the user
*/
@Override
public ConsentOutcome willSeeResource(RequestDetails theRequestDetails, IBaseResource theResource, IConsentContextServices theContextServices) {
// Don't return the subject for Observation resources
if (theResource instanceof Observation) {
Observation obs = (Observation)theResource;
obs.setSubject(null);
}
return ConsentOutcome.AUTHORIZED;
}
@Override
public void completeOperationSuccess(RequestDetails theRequestDetails, IConsentContextServices theContextServices) {
// We could write an audit trail entry in here
}
@Override
public void completeOperationFailure(RequestDetails theRequestDetails, BaseServerResponseException theException, IConsentContextServices theContextServices) {
// We could write an audit trail entry in here
}
}
//END SNIPPET: service
}

View File

@ -0,0 +1,60 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.convertors.NullVersionConverterAdvisor30;
import org.hl7.fhir.convertors.VersionConvertor_10_30;
import org.hl7.fhir.convertors.VersionConvertor_14_30;
import org.hl7.fhir.exceptions.FHIRException;
public class ConverterExamples {
@SuppressWarnings("unused")
public void c1020() throws FHIRException {
//START SNIPPET: 1020
// Create a converter
NullVersionConverterAdvisor30 advisor = new NullVersionConverterAdvisor30();
VersionConvertor_10_30 converter = new VersionConvertor_10_30(advisor);
// Create an input resource to convert
org.hl7.fhir.dstu2.model.Observation input = new org.hl7.fhir.dstu2.model.Observation();
input.setEncounter(new org.hl7.fhir.dstu2.model.Reference("Encounter/123"));
// Convert the resource
org.hl7.fhir.dstu3.model.Observation output = converter.convertObservation(input);
String context = output.getContext().getReference();
//END SNIPPET: 1020
}
@SuppressWarnings("unused")
public void c1420() throws FHIRException {
//START SNIPPET: 1420
// Create a resource to convert
org.hl7.fhir.dstu2016may.model.Questionnaire input = new org.hl7.fhir.dstu2016may.model.Questionnaire();
input.setTitle("My title");
// Convert the resource
org.hl7.fhir.dstu3.model.Questionnaire output = VersionConvertor_14_30.convertQuestionnaire(input);
String context = output.getTitle();
//END SNIPPET: 1420
}
}

View File

@ -0,0 +1,141 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.util.ResourceReferenceInfo;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@SuppressWarnings("unused")
public class Copier {
private static final Logger ourLog = LoggerFactory.getLogger(Copier.class);
public static void main(String[] args) {
FhirContext ctx = FhirContext.forDstu3();
IGenericClient source = ctx.newRestfulGenericClient("http://localhost:8080/baseDstu3");
IGenericClient target = ctx.newRestfulGenericClient("https://try.smilecdr.com:8000");
List<String> resType = Arrays.asList(
"Patient", "Organization", "Encounter", "Procedure",
"Observation", "ResearchSubject", "Specimen",
"ResearchStudy", "Location", "Practitioner"
);
List<IBaseResource> queued = new ArrayList<>();
Set<String> sent = new HashSet<>();
for (String next : resType) {
copy(ctx, source, target, next, queued, sent);
}
while (queued.size() > 0) {
ourLog.info("Have {} queued resources to deliver", queued.size());
for (IBaseResource nextQueued : new ArrayList<>(queued)) {
String missingRef = null;
for (ResourceReferenceInfo nextRefInfo : ctx.newTerser().getAllResourceReferences(nextQueued)) {
String nextRef = nextRefInfo.getResourceReference().getReferenceElement().getValue();
if (isNotBlank(nextRef) && !sent.contains(nextRef)) {
missingRef = nextRef;
}
}
if (missingRef != null) {
ourLog.info("Can't send {} because of missing ref {}", nextQueued.getIdElement().getIdPart(), missingRef);
continue;
}
IIdType newId = target
.update()
.resource(nextQueued)
.execute()
.getId();
ourLog.info("Copied resource {} and got ID {}", nextQueued.getIdElement().getValue(), newId);
sent.add(nextQueued.getIdElement().toUnqualifiedVersionless().getValue());
queued.remove(nextQueued);
}
}
}
private static void copy(FhirContext theCtx, IGenericClient theSource, IGenericClient theTarget, String theResType, List<IBaseResource> theQueued, Set<String> theSent) {
Bundle received = theSource
.search()
.forResource(theResType)
.returnBundle(Bundle.class)
.execute();
copy(theCtx, theTarget, theResType, theQueued, theSent, received);
while (received.getLink("next") != null) {
ourLog.info("Fetching next page...");
received = theSource.loadPage().next(received).execute();
copy(theCtx, theTarget, theResType, theQueued, theSent, received);
}
}
private static void copy(FhirContext theCtx, IGenericClient theTarget, String theResType, List<IBaseResource> theQueued, Set<String> theSent, Bundle theReceived) {
for (Bundle.BundleEntryComponent nextEntry : theReceived.getEntry()) {
Resource nextResource = nextEntry.getResource();
nextResource.setId(theResType + "/" + "CR-" + nextResource.getIdElement().getIdPart());
boolean haveUnsentReference = false;
for (ResourceReferenceInfo nextRefInfo : theCtx.newTerser().getAllResourceReferences(nextResource)) {
IIdType nextRef = nextRefInfo.getResourceReference().getReferenceElement();
if (nextRef.hasIdPart()) {
String newRef = nextRef.getResourceType() + "/" + "CR-" + nextRef.getIdPart();
ourLog.info("Changing reference {} to {}", nextRef.getValue(), newRef);
nextRefInfo.getResourceReference().setReference(newRef);
if (!theSent.contains(newRef)) {
haveUnsentReference = true;
}
}
}
if (haveUnsentReference) {
ourLog.info("Queueing {} for delivery after", nextResource.getId());
theQueued.add(nextResource);
continue;
}
IIdType newId = theTarget
.update()
.resource(nextResource)
.execute()
.getId();
ourLog.info("Copied resource {} and got ID {}", nextResource.getId(), newId);
theSent.add(nextResource.getIdElement().toUnqualifiedVersionless().getValue());
}
}
}

View File

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

View File

@ -0,0 +1,86 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import javax.servlet.ServletException;
import java.util.Collection;
@SuppressWarnings("serial")
public class Dstu2Examples {
private Collection<IResourceProvider> resourceProviderList;
public static void main(String[] args) {
new Dstu2Examples().getResourceTags();
}
@SuppressWarnings("unused")
public void getResourceTags() {
// START SNIPPET: context
// Create a DSTU2 context, which will use DSTU2 semantics
FhirContext ctx = FhirContext.forDstu2();
// This parser supports DSTU2
IParser parser = ctx.newJsonParser();
// This client supports DSTU2
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
// END SNIPPET: context
}
// START SNIPPET: server
public class MyServer extends RestfulServer
{
@Override
protected void initialize() throws ServletException {
// In your initialize method, assign a DSTU2 FhirContext. This
// is all that is required in order to put the server
// into DSTU2 mode
setFhirContext(FhirContext.forDstu2());
// Then set resource providers as normal, and do any other
// configuration you need to do.
setResourceProviders(resourceProviderList);
}
}
// END SNIPPET: server
public void upgrade() {
// START SNIPPET: client
FhirContext ctxDstu2 = FhirContext.forDstu2();
IGenericClient clientDstu2 = ctxDstu2.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
// END SNIPPET: client
}
}

View File

@ -0,0 +1,101 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.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 org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings(value= {"serial"})
public class ExampleProviders {
//START SNIPPET: plainProvider
public class PlainProvider {
/**
* This method is a Patient search, but HAPI can not automatically
* determine the resource type so it must be explicitly stated.
*/
@Search(type=Patient.class)
public Bundle searchForPatients(@RequiredParam(name=Patient.SP_NAME) StringDt theName) {
Bundle retVal = new Bundle();
// perform search
return retVal;
}
}
//END SNIPPET: plainProvider
//START SNIPPET: plainProviderServer
public class ExampleServlet extends ca.uhn.fhir.rest.server.RestfulServer {
/**
* Constructor
*/
public ExampleServlet() {
/*
* Plain providers are passed to the server in the same way
* as resource providers. You may pass both resource providers
* and and plain providers to the same server if you like.
*/
List<Object> plainProviders=new ArrayList<Object>();
plainProviders.add(new PlainProvider());
registerProviders(plainProviders);
List<IResourceProvider> resourceProviders = new ArrayList<IResourceProvider>();
// ...add some resource providers...
registerProviders(resourceProviders);
}
}
//END SNIPPET: plainProviderServer
//START SNIPPET: addressStrategy
public class MyServlet extends ca.uhn.fhir.rest.server.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

@ -0,0 +1,45 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.r4.model.*;
import java.util.List;
@SuppressWarnings("unused")
public class ExampleRestfulClient {
//START SNIPPET: client
public static void main(String[] args) {
FhirContext ctx = FhirContext.forDstu2();
String serverBase = "http://foo.com/fhirServerBase";
// Create the client
IRestfulClient client = ctx.newRestfulClient(IRestfulClient.class, serverBase);
// Try the client out! This method will invoke the server
List<Patient> patients = client.getPatient(new StringType("SMITH"));
}
//END SNIPPET: client
}

View File

@ -0,0 +1,65 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import java.util.ArrayList;
import java.util.List;
//START SNIPPET: servlet
/**
* In this example, we are using Servlet 3.0 annotations to define
* the URL pattern for this servlet, but we could also
* define this in a web.xml file.
*/
@WebServlet(urlPatterns= {"/fhir/*"}, displayName="FHIR Server")
public class ExampleRestfulServlet extends RestfulServer {
private static final long serialVersionUID = 1L;
/**
* The initialize method is automatically called when the servlet is starting up, so it can
* be used to configure the servlet to define resource providers, or set up
* configuration, interceptors, etc.
*/
@Override
protected void initialize() throws ServletException {
/*
* The servlet defines any number of resource providers, and
* configures itself to use them by calling
* setResourceProviders()
*/
List<IResourceProvider> resourceProviders = new ArrayList<IResourceProvider>();
resourceProviders.add(new RestfulPatientResourceProvider());
resourceProviders.add(new RestfulObservationResourceProvider());
setResourceProviders(resourceProviders);
}
}
//END SNIPPET: servlet

View File

@ -0,0 +1,125 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Questionnaire;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import java.io.IOException;
import java.util.List;
public class ExtensionsDstu2 {
@SuppressWarnings("unused")
public static void main(String[] args) throws DataFormatException, IOException {
{
Questionnaire q= new Questionnaire();
Questionnaire.GroupQuestion item = q.getGroup().addQuestion();
item.setText("Hello");
ExtensionDt extension = new ExtensionDt(false, "http://hl7.org/fhir/StructureDefinition/translation");
item.getTextElement().addUndeclaredExtension(extension);
extension.addUndeclaredExtension(new ExtensionDt(false, "lang", new CodeDt("es")));
extension.addUndeclaredExtension(new ExtensionDt(false, "cont", new StringDt("hola")));
System.out.println(FhirContext.forDstu2().newJsonParser().setPrettyPrint(true).encodeResourceToString(q));
}
// START SNIPPET: resourceExtension
// Create an example patient
Patient patient = new Patient();
patient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setSystem("urn:example").setValue("7000135");
// Create an extension
ExtensionDt ext = new ExtensionDt();
ext.setModifier(false);
ext.setUrl("http://example.com/extensions#someext");
ext.setValue(new DateTimeDt("2011-01-02T11:13:15"));
// Add the extension to the resource
patient.addUndeclaredExtension(ext);
//END SNIPPET: resourceExtension
//START SNIPPET: resourceStringExtension
// Continuing the example from above, we will add a name to the patient, and then
// add an extension to part of that name
HumanNameDt name = patient.addName();
name.addFamily().setValue("Shmoe");
// Add a new "given name", which is of type StringDt
StringDt given = name.addGiven();
given.setValue("Joe");
// Create an extension and add it to the StringDt
ExtensionDt givenExt = new ExtensionDt(false, "http://examples.com#moreext", new StringDt("Hello"));
given.addUndeclaredExtension(givenExt);
//END SNIPPET: resourceStringExtension
FhirContext ctx = FhirContext.forDstu2();
String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(output);
//START SNIPPET: parseExtension
// Get all extensions (modifier or not) for a given URL
List<ExtensionDt> resourceExts = patient.getUndeclaredExtensionsByUrl("http://fooextensions.com#exts");
// Get all non-modifier extensions regardless of URL
List<ExtensionDt> nonModExts = patient.getUndeclaredExtensions();
//Get all non-modifier extensions regardless of URL
List<ExtensionDt> modExts = patient.getUndeclaredModifierExtensions();
//END SNIPPET: parseExtension
}
public void foo() {
//START SNIPPET: subExtension
Patient patient = new Patient();
// Add an extension (initially with no contents) to the resource
ExtensionDt parent = new ExtensionDt(false, "http://example.com#parent");
patient.addUndeclaredExtension(parent);
// Add two extensions as children to the parent extension
ExtensionDt child1 = new ExtensionDt(false, "http://example.com#childOne", new StringDt("value1"));
parent.addUndeclaredExtension(child1);
ExtensionDt child2 = new ExtensionDt(false, "http://example.com#childTwo", new StringDt("value1"));
parent.addUndeclaredExtension(child2);
//END SNIPPET: subExtension
}
}

View File

@ -0,0 +1,178 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import org.hl7.fhir.r4.model.*;
import java.io.IOException;
import java.util.List;
public class ExtensionsDstu3 {
public void customType() {
IGenericClient client = FhirContext.forDstu3().newRestfulGenericClient("http://foo");
//START SNIPPET: customTypeClientSimple
// Create an example patient
MyPatient custPatient = new MyPatient();
custPatient.addName().setFamily("Smith").addGiven("John");
custPatient.setPetName(new StringType("Rover")); // populate the extension
// Create the resource like normal
client.create().resource(custPatient).execute();
// You can also read the resource back like normal
custPatient = client.read().resource(MyPatient.class).withId("123").execute();
//END SNIPPET: customTypeClientSimple
//START SNIPPET: customTypeClientSearch
// Perform the search using the custom type
Bundle bundle = client
.search()
.forResource(MyPatient.class)
.returnBundle(Bundle.class)
.execute();
// Entries in the return bundle will use the given type
MyPatient pat0 = (MyPatient) bundle.getEntry().get(0).getResource();
//END SNIPPET: customTypeClientSearch
//START SNIPPET: customTypeClientSearch2
//Perform the search using the custom type
bundle = client
.history()
.onInstance(new IdType("Patient/123"))
.andReturnBundle(Bundle.class)
.preferResponseType(MyPatient.class)
.execute();
//Entries in the return bundle will use the given type
MyPatient historyPatient0 = (MyPatient) bundle.getEntry().get(0).getResource();
//END SNIPPET: customTypeClientSearch2
}
public void customTypeDeclared() {
//START SNIPPET: customTypeClientDeclared
FhirContext ctx = FhirContext.forDstu3();
// Instruct the context that if it receives a resource which
// claims to conform to the given profile (by URL), it should
// use the MyPatient type to parse this resource
ctx.setDefaultTypeForProfile("http://example.com/StructureDefinition/mypatient", MyPatient.class);
// You can declare as many default types as you like
ctx.setDefaultTypeForProfile("http://foo.com/anotherProfile", CustomObservation.class);
// Create a client
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu3");
// You can also read the resource back like normal
Patient patient = client.read().resource(Patient.class).withId("123").execute();
if (patient instanceof MyPatient) {
// If the server supplied a resource which declared to conform
// to the given profile, MyPatient will have been returned so
// process it differently..
}
//END SNIPPET: customTypeClientDeclared
}
@SuppressWarnings("unused")
public static void main(String[] args) throws DataFormatException, IOException {
// START SNIPPET: resourceExtension
// Create an example patient
Patient patient = new Patient();
patient.addIdentifier().setUse(Identifier.IdentifierUse.OFFICIAL).setSystem("urn:example").setValue("7000135");
// Create an extension
Extension ext = new Extension();
ext.setUrl("http://example.com/extensions#someext");
ext.setValue(new DateTimeType("2011-01-02T11:13:15"));
// Add the extension to the resource
patient.addExtension(ext);
//END SNIPPET: resourceExtension
//START SNIPPET: resourceStringExtension
// Continuing the example from above, we will add a name to the patient, and then
// add an extension to part of that name
HumanName name = patient.addName();
name.setFamily("Shmoe");
// Add a new "given name", which is of type String
StringType given = name.addGivenElement();
given.setValue("Joe");
// Create an extension and add it to the String
Extension givenExt = new Extension("http://examples.com#moreext", new StringType("Hello"));
given.addExtension(givenExt);
//END SNIPPET: resourceStringExtension
FhirContext ctx = FhirContext.forDstu3();
String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(output);
//START SNIPPET: parseExtension
// Get all extensions (modifier or not) for a given URL
List<Extension> resourceExts = patient.getExtensionsByUrl("http://fooextensions.com#exts");
// Get all non-modifier extensions regardless of URL
List<Extension> nonModExts = patient.getExtension();
//Get all non-modifier extensions regardless of URL
List<Extension> modExts = patient.getModifierExtension();
//END SNIPPET: parseExtension
}
public void foo() {
//START SNIPPET: subExtension
Patient patient = new Patient();
// Add an extension (initially with no contents) to the resource
Extension parent = new Extension("http://example.com#parent");
patient.addExtension(parent);
// Add two extensions as children to the parent extension
Extension child1 = new Extension("http://example.com#childOne", new StringType("value1"));
parent.addExtension(child1);
Extension child2 = new Extension("http://example.com#chilwo", new StringType("value1"));
parent.addExtension(child2);
//END SNIPPET: subExtension
}
}

View File

@ -0,0 +1,145 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import org.hl7.fhir.r4.model.*;
public class FhirContextIntro {
@SuppressWarnings("unused")
public static void creatingContext() {
// START SNIPPET: creatingContext
// Create a context for DSTU2
FhirContext ctxDstu2 = FhirContext.forDstu2();
// Alternately, create a context for R4
FhirContext ctxR4 = FhirContext.forR4();
// END SNIPPET: creatingContext
}
@SuppressWarnings("unused")
public static void creatingContextHl7org() {
// START SNIPPET: creatingContextHl7org
// Create a context for DSTU3
FhirContext ctx = FhirContext.forDstu3();
// Working with RI structures is similar to how it works with the HAPI structures
org.hl7.fhir.dstu3.model.Patient patient = new org.hl7.fhir.dstu3.model.Patient();
patient.addName().addGiven("John").setFamily("Smith");
patient.getBirthDateElement().setValueAsString("1998-02-22");
// Parsing and encoding works the same way too
String encoded = ctx.newJsonParser().encodeResourceToString(patient);
// END SNIPPET: creatingContextHl7org
}
public void encodeMsg() throws DataFormatException {
FhirContext ctx = new FhirContext(Patient.class, Observation.class);
//START SNIPPET: encodeMsg
/**
* FHIR model types in HAPI are simple POJOs. To create a new
* one, invoke the default constructor and then
* start populating values.
*/
Patient patient = new Patient();
// Add an MRN (a patient identifier)
Identifier id = patient.addIdentifier();
id.setSystem("http://example.com/fictitious-mrns");
id.setValue("MRN001");
// Add a name
HumanName name = patient.addName();
name.setUse(HumanName.NameUse.OFFICIAL);
name.setFamily("Tester");
name.addGiven("John");
name.addGiven("Q");
// We can now use a parser to encode this resource into a string.
String encoded = ctx.newXmlParser().encodeResourceToString(patient);
System.out.println(encoded);
//END SNIPPET: encodeMsg
//START SNIPPET: encodeMsgJson
IParser jsonParser = ctx.newJsonParser();
jsonParser.setPrettyPrint(true);
encoded = jsonParser.encodeResourceToString(patient);
System.out.println(encoded);
//END SNIPPET: encodeMsgJson
}
public void fluent() throws DataFormatException {
FhirContext ctx = new FhirContext(Patient.class, Observation.class);
String encoded;
//START SNIPPET: encodeMsgFluent
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://example.com/fictitious-mrns").setValue("MRN001");
patient.addName().setUse(HumanName.NameUse.OFFICIAL).setFamily("Tester").addGiven("John").addGiven("Q");
encoded = ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(encoded);
//END SNIPPET: encodeMsgFluent
}
public static void parseMsg() {
FhirContext ctx = FhirContext.forR4();
//START SNIPPET: parseMsg
// The following is an example Patient resource
String msgString = "<Patient xmlns=\"http://hl7.org/fhir\">"
+ "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal</div></text>"
+ "<identifier><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>"
+ "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>"
+ "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
+ "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
+ "</Patient>";
// The hapi context object is used to create a new XML parser
// instance. The parser can then be used to parse (or unmarshall) the
// string message into a Patient object
IParser parser = ctx.newXmlParser();
Patient patient = parser.parseResource(Patient.class, msgString);
// The patient object has accessor methods to retrieve all of the
// data which has been parsed into the instance.
String patientId = patient.getIdentifier().get(0).getValue();
String familyName = patient.getName().get(0).getFamily();
Enumerations.AdministrativeGender gender = patient.getGender();
System.out.println(patientId); // PRP1660
System.out.println(familyName); // Cardinal
System.out.println(gender.toCode()); // male
//END SNIPPET: parseMsg
}
}

View File

@ -0,0 +1,205 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import java.util.Date;
import java.util.List;
import org.hl7.fhir.r4.model.*;
public class FhirDataModel {
public static void datatypes() {
// START SNIPPET: datatypes
Observation obs = new Observation();
// These are all equivalent
obs.setIssuedElement(new InstantType(new Date()));
obs.setIssuedElement(new InstantType(new Date(), TemporalPrecisionEnum.MILLI));
obs.setIssued(new Date());
// The InstantType also lets you work with the instant as a Java Date
// object or as a FHIR String.
Date date = obs.getIssuedElement().getValue(); // A date object
String dateString = obs.getIssuedElement().getValueAsString(); // "2014-03-08T12:59:58.068-05:00"
// END SNIPPET: datatypes
System.out.println(date);
System.out.println(dateString);
}
@SuppressWarnings("unused")
public void nonNull() {
// START SNIPPET: nonNull
Observation observation = new Observation();
// None of these calls will not return null, but instead create their
// respective
// child elements.
List<Identifier> identifierList = observation.getIdentifier();
CodeableConcept code = observation.getCode();
StringType textElement = observation.getCode().getTextElement();
// DateTimeDt is a FHIR primitive however, so the following will return
// null
// unless a value has been placed there.
Date active = observation.addIdentifier().getPeriod().getStartElement().getValue();
// END SNIPPET: nonNull
}
@SuppressWarnings("unused")
public static void codes() {
// START SNIPPET: codes
Patient patient = new Patient();
// You can set this code using a String if you want. Note that
// for "closed" valuesets (such as the one used for Patient.gender)
// you must use one of the strings defined by the FHIR specification.
// You must not define your own.
patient.getGenderElement().setValueAsString("male");
// HAPI also provides Java enumerated types which make it easier to
// deal with coded values. This code achieves the exact same result
// as the code above.
patient.setGender(Enumerations.AdministrativeGender.MALE);
// You can also retrieve coded values the same way
String genderString = patient.getGenderElement().getValueAsString();
Enumerations.AdministrativeGender genderEnum = patient.getGenderElement().getValue();
// END SNIPPET: codes
}
@SuppressWarnings("unused")
public static void codeableConcepts() {
// START SNIPPET: codeableConcepts
Patient patient = new Patient();
// Coded types can naturally be set using plain strings
Coding statusCoding = patient.getMaritalStatus().addCoding();
statusCoding.setSystem("http://hl7.org/fhir/v3/MaritalStatus");
statusCoding.setCode("M");
statusCoding.setDisplay("Married");
// You could add a second coding to the field if needed too. This
// can be useful if you want to convey the concept using different
// codesystems.
Coding secondStatus = patient.getMaritalStatus().addCoding();
secondStatus.setCode("H");
secondStatus.setSystem("http://example.com#maritalStatus");
secondStatus.setDisplay("Happily Married");
// CodeableConcept also has a text field meant to convey
// a user readable version of the concepts it conveys.
patient.getMaritalStatus().setText("Happily Married");
// There are also accessors for retrieving values
String firstCode = patient.getMaritalStatus().getCoding().get(0).getCode();
String secondCode = patient.getMaritalStatus().getCoding().get(1).getCode();
// END SNIPPET: codeableConcepts
}
public static void main(String[] args) {
tmp();
datatypes();
// START SNIPPET: observation
// Create an Observation instance
Observation observation = new Observation();
// Give the observation a status
observation.setStatus(Observation.ObservationStatus.FINAL);
// Give the observation a code (what kind of observation is this)
Coding coding = observation.getCode().addCoding();
coding.setCode("29463-7").setSystem("http://loinc.org").setDisplay("Body Weight");
// Create a quantity datatype
Quantity value = new Quantity();
value.setValue(83.9).setSystem("http://unitsofmeasure.org").setCode("kg");
observation.setValue(value);
// Set the reference range
SimpleQuantity low = new SimpleQuantity();
low.setValue(45).setSystem("http://unitsofmeasure.org").setCode("kg");
observation.getReferenceRangeFirstRep().setLow(low);
SimpleQuantity high = new SimpleQuantity();
low.setValue(90).setSystem("http://unitsofmeasure.org").setCode("kg");
observation.getReferenceRangeFirstRep().setHigh(high);
// END SNIPPET: observation
}
private static void tmp() {
// Create a FHIR Context
FhirContext ctx = FhirContext.forR4();
// Create a client
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseR4");
// Read a patient with the given ID
Patient patient = client
.read()
.resource(Patient.class)
.withId("952975")
.execute();
// Print the patient's name
String string = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(string);
}
public void namesHard() {
// START SNIPPET: namesHard
Patient patient = new Patient();
HumanName name = patient.addName();
name.setFamily("Smith");
StringType firstName = name.addGivenElement();
firstName.setValue("Rob");
StringType secondName = name.addGivenElement();
secondName.setValue("Bruce");
// END SNIPPET: namesHard
}
public void namesEasy() {
// START SNIPPET: namesEasy
Patient patient = new Patient();
patient.addName().setFamily("Smith").addGiven("Rob").addGiven("Bruce");
// END SNIPPET: namesEasy
}
}

View File

@ -0,0 +1,554 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.PerformanceOptionsEnum;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import java.util.ArrayList;
import java.util.List;
public class GenericClientExample {
public static void deferModelScanning() {
// START SNIPPET: deferModelScanning
// Create a context and configure it for deferred child scanning
FhirContext ctx = FhirContext.forDstu2();
ctx.setPerformanceOptions(PerformanceOptionsEnum.DEFERRED_MODEL_SCANNING);
// Now create a client and use it
String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
IGenericClient client = ctx.newRestfulGenericClient(serverBase);
// END SNIPPET: deferModelScanning
}
public static void performance() {
// START SNIPPET: dontValidate
// Create a context
FhirContext ctx = FhirContext.forDstu2();
// Disable server validation (don't pull the server's metadata first)
ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
// Now create a client and use it
String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
IGenericClient client = ctx.newRestfulGenericClient(serverBase);
// END SNIPPET: dontValidate
}
public static void simpleExample() {
// START SNIPPET: simple
// We're connecting to a DSTU1 compliant server in this example
FhirContext ctx = FhirContext.forDstu2();
String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
IGenericClient client = ctx.newRestfulGenericClient(serverBase);
// Perform a search
Bundle results = client
.search()
.forResource(Patient.class)
.where(Patient.FAMILY.matches().value("duck"))
.returnBundle(Bundle.class)
.execute();
System.out.println("Found " + results.getEntry().size() + " patients named 'duck'");
// END SNIPPET: simple
}
@SuppressWarnings("unused")
public static void fluentSearch() {
FhirContext ctx = FhirContext.forDstu2();
IGenericClient client = ctx.newRestfulGenericClient("http://fhir.healthintersections.com.au/open");
{
// START SNIPPET: create
Patient patient = new Patient();
// ..populate the patient object..
patient.addIdentifier().setSystem("urn:system").setValue("12345");
patient.addName().setFamily("Smith").addGiven("John");
// Invoke the server create method (and send pretty-printed JSON
// encoding to the server
// instead of the default which is non-pretty printed XML)
MethodOutcome outcome = client.create()
.resource(patient)
.prettyPrint()
.encodedJson()
.execute();
// The MethodOutcome object will contain information about the
// response from the server, including the ID of the created
// resource, the OperationOutcome response, etc. (assuming that
// any of these things were provided by the server! They may not
// always be)
IIdType id = outcome.getId();
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 Boolean.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
IIdType id = outcome.getId();
// END SNIPPET: createConditional
}
{
// START SNIPPET: validate
Patient patient = new Patient();
patient.addIdentifier().setSystem("http://hospital.com").setValue("123445");
patient.addName().setFamily("Smith").addGiven("John");
// Validate the resource
MethodOutcome outcome = client.validate()
.resource(patient)
.execute();
// The returned object will contain an operation outcome resource
OperationOutcome oo = (OperationOutcome) outcome.getOperationOutcome();
// If the OperationOutcome has any issues with a severity of ERROR or SEVERE,
// the validation failed.
for (OperationOutcome.OperationOutcomeIssueComponent nextIssue : oo.getIssue()) {
if (nextIssue.getSeverity().ordinal() >= OperationOutcome.IssueSeverity.ERROR.ordinal()) {
System.out.println("We failed validation!");
}
}
// END SNIPPET: validate
}
{
// START SNIPPET: update
Patient patient = new Patient();
// ..populate the patient object..
patient.addIdentifier().setSystem("urn:system").setValue("12345");
patient.addName().setFamily("Smith").addGiven("John");
// To update a resource, it should have an ID set (if the resource
// object
// comes from the results of a previous read or search, it will already
// have one though)
patient.setId("Patient/123");
// Invoke the server update method
MethodOutcome outcome = client.update()
.resource(patient)
.execute();
// The MethodOutcome object will contain information about the
// response from the server, including the ID of the created
// resource, the OperationOutcome response, etc. (assuming that
// any of these things were provided by the server! They may not
// always be)
IdType id = (IdType) outcome.getId();
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
// from the server
Patient patient = client.read().resource(Patient.class).withId("123").execute();
// If the server is a version aware server, we should now know the latest version
// of the resource
System.out.println("Version ID: " + patient.getIdElement().getVersionIdPart());
// Now let's make a change to the resource
patient.setGender(Enumerations.AdministrativeGender.FEMALE);
// Invoke the server update method - Because the resource has
// a version, it will be included in the request sent to
// the server
try {
MethodOutcome outcome = client
.update()
.resource(patient)
.execute();
} catch (PreconditionFailedException e) {
// If we get here, the latest version has changed
// on the server so our update failed.
}
// END SNIPPET: etagupdate
}
{
// START SNIPPET: conformance
// Retrieve the server's conformance statement and print its
// description
CapabilityStatement conf = client.capabilities().ofType(CapabilityStatement.class).execute();
System.out.println(conf.getDescriptionElement().getValue());
// END SNIPPET: conformance
}
{
// START SNIPPET: delete
IBaseOperationOutcome resp = client.delete().resourceById(new IdType("Patient", "1234")).execute();
// outcome may be null if the server didn't return one
if (resp != null) {
OperationOutcome outcome = (OperationOutcome) resp;
System.out.println(outcome.getIssueFirstRep().getDetails().getCodingFirstRep().getCode());
}
// 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()
.forResource(Patient.class)
.where(Patient.BIRTHDATE.beforeOrEquals().day("2011-01-01"))
.and(Patient.GENERAL_PRACTITIONER.hasChainedProperty(Organization.NAME.matches().value("Smith")))
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: search
// START SNIPPET: searchOr
response = client.search()
.forResource(Patient.class)
.where(Patient.FAMILY.matches().values("Smith", "Smyth"))
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchOr
// START SNIPPET: searchAnd
response = client.search()
.forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto"))
.and(Patient.ADDRESS.matches().values("Ontario"))
.and(Patient.ADDRESS.matches().values("Canada"))
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchAnd
// START SNIPPET: searchCompartment
response = client.search()
.forResource(Patient.class)
.withIdAndCompartment("123", "condition")
.where(Patient.ADDRESS.matches().values("Toronto"))
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchCompartment
// START SNIPPET: searchUrl
String searchUrl = "http://example.com/base/Patient?identifier=foo";
// Search URL can also be a relative URL in which case the client's base
// URL will be added to it
searchUrl = "Patient?identifier=foo";
response = client.search()
.byUrl(searchUrl)
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchUrl
// START SNIPPET: searchSubsetSummary
response = client.search()
.forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto"))
.returnBundle(Bundle.class)
.summaryMode(SummaryEnum.TRUE)
.execute();
// END SNIPPET: searchSubsetSummary
// START SNIPPET: searchSubsetElements
response = client.search()
.forResource(Patient.class)
.where(Patient.ADDRESS.matches().values("Toronto"))
.returnBundle(Bundle.class)
.elementsSubset("identifier", "name") // only include the identifier and name
.execute();
// END SNIPPET: searchSubsetElements
// START SNIPPET: searchAdv
response = client.search()
.forResource(Patient.class)
.encodedJson()
.where(Patient.BIRTHDATE.beforeOrEquals().day("2012-01-22"))
.and(Patient.BIRTHDATE.after().day("2011-01-01"))
.withTag("http://acme.org/codes", "needs-review")
.include(Patient.INCLUDE_ORGANIZATION.asRecursive())
.include(Patient.INCLUDE_GENERAL_PRACTITIONER.asNonRecursive())
.revInclude(Provenance.INCLUDE_TARGET)
.lastUpdated(new DateRangeParam("2011-01-01", null))
.sort().ascending(Patient.BIRTHDATE)
.sort().descending(Patient.NAME).limitTo(123)
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchAdv
// START SNIPPET: searchPost
response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("Tester"))
.usingStyle(SearchStyleEnum.POST)
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchPost
// START SNIPPET: searchComposite
response = client.search()
.forResource("Observation")
.where(Observation.CODE_VALUE_DATE
.withLeft(Observation.CODE.exactly().code("FOO$BAR"))
.withRight(Observation.VALUE_DATE.exactly().day("2001-01-01")))
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: searchComposite
}
{
// START SNIPPET: transaction
List<IResource> resources = new ArrayList<IResource>();
// .. populate this list - note that you can also pass in a populated
// Bundle if you want to create one manually ..
List<IBaseResource> response = client.transaction().withResources(resources).execute();
// END SNIPPET: transaction
}
{
// START SNIPPET: read
// search for patient 123
Patient patient = client.read()
.resource(Patient.class)
.withId("123")
.execute();
// END SNIPPET: read
}
{
// START SNIPPET: vread
// search for patient 123 (specific version 888)
Patient patient = client.read()
.resource(Patient.class)
.withIdAndVersion("123", "888")
.execute();
// END SNIPPET: vread
}
{
// START SNIPPET: readabsolute
// search for patient 123 on example.com
String url = "http://example.com/fhir/Patient/123";
Patient patient = client.read()
.resource(Patient.class)
.withUrl(url)
.execute();
// END SNIPPET: readabsolute
}
{
// START SNIPPET: etagread
// search for patient 123
Patient patient = client.read()
.resource(Patient.class)
.withId("123")
.ifVersionMatches("001").returnNull()
.execute();
if (patient == null) {
// resource has not changed
}
// END SNIPPET: etagread
}
}
@SuppressWarnings("unused")
public static void history() {
IGenericClient client = FhirContext.forDstu2().newRestfulGenericClient("");
{
Bundle response;
// START SNIPPET: historyDstu2
response = client
.history()
.onServer()
.returnBundle(Bundle.class)
.execute();
// END SNIPPET: historyDstu2
}
{
Bundle response;
// START SNIPPET: historyFeatures
response = client
.history()
.onServer()
.returnBundle(Bundle.class)
.since(new InstantType("2012-01-01T12:22:32.038Z"))
.count(100)
.execute();
// END SNIPPET: historyFeatures
}
}
public static void main(String[] args) {
paging();
}
private static void paging() {
{
// START SNIPPET: searchPaging
FhirContext ctx = FhirContext.forDstu2();
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
// Perform a search
Bundle resultBundle = client.search()
.forResource(Patient.class)
.where(Patient.NAME.matches().value("Smith"))
.returnBundle(Bundle.class)
.execute();
if (resultBundle.getLink(Bundle.LINK_NEXT) != null) {
// load next page
Bundle nextPage = client.loadPage().next(resultBundle).execute();
}
// END SNIPPET: searchPaging
}
}
@SuppressWarnings("unused")
private static void operationHttpGet() {
// START SNIPPET: operationHttpGet
// Create a client to talk to the HeathIntersections server
FhirContext ctx = FhirContext.forDstu2();
IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
client.registerInterceptor(new LoggingInterceptor(true));
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdType("Patient", "1"))
.named("$everything")
.withParameters(inParams)
.useHttpGet() // Use HTTP GET instead of POST
.execute();
// END SNIPPET: operationHttpGet
}
@SuppressWarnings("unused")
private static void operation() {
// START SNIPPET: operation
// Create a client to talk to the HeathIntersections server
FhirContext ctx = FhirContext.forDstu2();
IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
client.registerInterceptor(new LoggingInterceptor(true));
// Create the input parameters to pass to the server
Parameters inParams = new Parameters();
inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdType("Patient", "1"))
.named("$everything")
.withParameters(inParams)
.execute();
/*
* Note that the $everything operation returns a Bundle instead
* of a Parameters resource. The client operation methods return a
* Parameters instance however, so HAPI creates a Parameters object
* with a single parameter containing the value.
*/
Bundle responseBundle = (Bundle) outParams.getParameter().get(0).getResource();
// Print the response bundle
System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(responseBundle));
// END SNIPPET: operation
}
@SuppressWarnings("unused")
private static void operationNoIn() {
// START SNIPPET: operationNoIn
// Create a client to talk to the HeathIntersections server
FhirContext ctx = FhirContext.forDstu2();
IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
client.registerInterceptor(new LoggingInterceptor(true));
// Invoke $everything on "Patient/1"
Parameters outParams = client
.operation()
.onInstance(new IdType("Patient", "1"))
.named("$everything")
.withNoParameters(Parameters.class) // No input parameters
.execute();
// END SNIPPET: operationNoIn
}
}

View File

@ -0,0 +1,81 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.SearchParameter;
public class GenomicsUploader {
public static void main(String[] theArgs) {
FhirContext ctx = FhirContext.forR4();
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseR4");
client.registerInterceptor(new LoggingInterceptor(false));
SearchParameter dnaSequenceVariantName = new SearchParameter();
dnaSequenceVariantName.setId("SearchParameter/dnaSequenceVariantName");
dnaSequenceVariantName.setStatus(Enumerations.PublicationStatus.ACTIVE);
dnaSequenceVariantName.addBase("Observation");
dnaSequenceVariantName.setCode("dnaSequenceVariantName");
dnaSequenceVariantName.setType(Enumerations.SearchParamType.TOKEN);
dnaSequenceVariantName.setTitle("DNASequenceVariantName");
dnaSequenceVariantName.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsDNASequenceVariantName')");
dnaSequenceVariantName.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
client.update().resource(dnaSequenceVariantName).execute();
SearchParameter dNAVariantId = new SearchParameter();
dNAVariantId.setId("SearchParameter/dNAVariantId");
dNAVariantId.setStatus(Enumerations.PublicationStatus.ACTIVE);
dNAVariantId.addBase("Observation");
dNAVariantId.setCode("dnaVariantId");
dNAVariantId.setType(Enumerations.SearchParamType.TOKEN);
dNAVariantId.setTitle("DNAVariantId");
dNAVariantId.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsDNAVariantId')");
dNAVariantId.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
client.update().resource(dNAVariantId).execute();
SearchParameter gene = new SearchParameter();
gene.setId("SearchParameter/gene");
gene.setStatus(Enumerations.PublicationStatus.ACTIVE);
gene.addBase("Observation");
gene.setCode("gene");
gene.setType(Enumerations.SearchParamType.TOKEN);
gene.setTitle("Gene");
gene.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsGene')");
gene.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
client.update().resource(gene).execute();
SearchParameter alleleName = new SearchParameter();
alleleName.setId("SearchParameter/alleleName");
alleleName.setStatus(Enumerations.PublicationStatus.ACTIVE);
alleleName.addBase("Observation");
alleleName.setCode("alleleName");
alleleName.setType(Enumerations.SearchParamType.TOKEN);
alleleName.setTitle("AlleleName");
alleleName.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsAlleleName')");
alleleName.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
client.update().resource(alleleName).execute();
}
}

View File

@ -0,0 +1,70 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient;
public class HttpProxy {
public static void main(String[] args) {
/*
* This is out ot date - Just keeping
* it in case it's helpful...
*/
final String authUser = "username";
final String authPassword = "password";
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope("10.10.10.10", 8080),
new UsernamePasswordCredentials(authUser, authPassword));
HttpHost myProxy = new HttpHost("10.10.10.10", 8080);
HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder
.setProxy(myProxy)
.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy())
.setDefaultCredentialsProvider(credsProvider)
.disableCookieManagement();
CloseableHttpClient httpClient = clientBuilder.build();
FhirContext ctx = FhirContext.forDstu2();
String serverBase = "http://spark.furore.com/fhir/";
ctx.getRestfulClientFactory().setHttpClient(httpClient);
IGenericClient client = ctx.newRestfulGenericClient(serverBase);
IdType id = new IdType("Patient", "123");
Patient patient = client.read().resource(Patient.class).withId(id).execute();
}
}

View File

@ -0,0 +1,91 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.client.api.IBasicClient;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import java.util.List;
//START SNIPPET: provider
/**
* All RESTful clients must be an interface which extends IBasicClient
*/
public interface IRestfulClient extends IBasicClient {
/**
* The "@Read" annotation indicates that this method supports the
* read operation. Read operations should return a single resource
* instance.
*
* @param theId
* The read operation takes one parameter, which must be of type
* IdType and must be annotated with the "@Read.IdParam" annotation.
* @return
* Returns a resource matching this identifier, or null if none exists.
*/
@Read()
Patient getResourceById(@IdParam IIdType theId);
/**
* The "@Read" annotation indicates that this method supports the
* read operation. Read operations should return a single resource
* instance.
*
* @param theId
* The read operation takes one parameter, which must be of type
* IdType and must be annotated with the "@Read.IdParam" annotation.
* @return
* Returns a resource matching this identifier, or null if none exists.
*/
@Read()
Organization getOrganizationById(@IdParam IIdType theId);
/**
* The "@Search" annotation indicates that this method supports the
* search operation. You may have many different methods annotated with
* this annotation, to support many different search criteria. This
* example searches by family name.
*
* @param theFamilyName
* This operation takes one parameter which is the search criteria. It is
* annotated with the "@Required" annotation. This annotation takes one argument,
* a string containing the name of the search criteria. The datatype here
* is StringDt, but there are other possible parameter types depending on the
* specific search criteria.
* @return
* This method returns a list of Patients. This list may contain multiple
* matching resources, or it may also be empty.
*/
@Search()
List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringType theFamilyName);
}
//END SNIPPET: provider

View File

@ -0,0 +1,77 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.Search;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.hapi.rest.server.R4BundleFactory;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import java.util.ArrayList;
import java.util.List;
public class IncludesExamples {
public static void main(String[] args) {
testSearchForPatients();
}
private static void testSearchForPatients() {
List<IBaseResource> resources = new IncludesExamples().searchForPatients();
// Create a bundle with both
FhirContext ctx = FhirContext.forDstu2();
R4BundleFactory bf = new R4BundleFactory(ctx);
bf.addRootPropertiesToBundle(null, null, null, null, null, resources.size(), BundleTypeEnum.SEARCHSET, null);
bf.addResourcesToBundle(new ArrayList<>(resources), BundleTypeEnum.SEARCHSET, null, null, null);
IBaseResource b = bf.getResourceBundle();
// Encode the bundle
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
System.out.println(encoded);
}
// START SNIPPET: addIncludes
@Search
private List<IBaseResource> searchForPatients() {
// Create an organization
Organization org = new Organization();
org.setId("Organization/65546");
org.setName("Test Organization");
// Create a patient
Patient patient = new Patient();
patient.setId("Patient/1333");
patient.addIdentifier().setSystem("urn:mrns").setValue("253345");
patient.getManagingOrganization().setResource(org);
// Here we return only the patient object, which has links to other resources
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
retVal.add(patient);
return retVal;
}
// END SNIPPET: addIncludes
}

View File

@ -0,0 +1,48 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jaxrs.client.JaxRsRestfulClientFactory;
import ca.uhn.fhir.rest.client.api.IGenericClient;
@SuppressWarnings(value= {"serial"})
public class JaxRsClient {
public static void main(String[] args) {
//START SNIPPET: createClient
// Create a client
FhirContext ctx = FhirContext.forDstu2();
// Create an instance of the JAX RS client factory and
// set it on the context
JaxRsRestfulClientFactory clientFactory = new JaxRsRestfulClientFactory(ctx);
ctx.setRestfulClientFactory(clientFactory);
// This client uses JAX-RS!
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
//END SNIPPET: createClient
}
}

View File

@ -0,0 +1,60 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsConformanceProvider;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IResourceProvider;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import java.util.concurrent.ConcurrentHashMap;
/**
* Conformance Rest Service
*
* @author Peter Van Houte
*/
// START SNIPPET: jax-rs-conformance
@Path("")
@Stateless
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class JaxRsConformanceProvider extends AbstractJaxRsConformanceProvider {
@EJB
private JaxRsPatientRestProvider provider;
public JaxRsConformanceProvider() {
super("My Server Description", "My Server Name", "My Server Version");
}
@Override
protected ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> getProviders() {
ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider> map = new ConcurrentHashMap<Class<? extends IResourceProvider>, IResourceProvider>();
map.put(JaxRsConformanceProvider.class, this);
map.put(JaxRsPatientRestProvider.class, provider);
return map;
}
}
// END SNIPPET: jax-rs-conformance

View File

@ -0,0 +1,92 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import javax.ejb.Local;
import javax.ejb.Stateless;
import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
/**
* A demo JaxRs Patient Rest Provider
*/
@Local
@Stateless
// START SNIPPET: jax-rs-provider-construction
@Path("/Patient")
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Patient> {
public JaxRsPatientRestProvider() {
super(JaxRsPatientRestProvider.class);
}
// END SNIPPET: jax-rs-provider-construction
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
@Create
public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional) {
// create the patient ...
return new MethodOutcome(new IdType(1L)).setCreated(true);
}
// START SNIPPET: jax-rs-provider-operation
@GET
@Path("/{id}/$someCustomOperation")
public Response someCustomOperationUsingGet(@PathParam("id") String id, String resource) throws Exception {
return customOperation(resource, RequestTypeEnum.GET, id, "$someCustomOperation",
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
@Operation(name = "someCustomOperation", idempotent = true, returnParameters = {
@OperationParam(name = "return", type = StringDt.class) })
public Parameters someCustomOperation(@IdParam IdType myId, @OperationParam(name = "dummy") StringDt dummyInput) {
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(new StringType("My Dummy Result"));
return parameters;
}
// END SNIPPET: jax-rs-provider-operation
@POST
@Path("/{id}/$someCustomOperation")
public Response someCustomOperationUsingPost(@PathParam("id") String id, String resource) throws Exception {
return customOperation(resource, RequestTypeEnum.POST, id, "$someCustomOperation",
RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
}
}

View File

@ -0,0 +1,70 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient;
public class Multitenancy {
//START SNIPPET: enableUrlBaseTenantIdentificationStrategy
public class MyServer extends RestfulServer {
@Override
protected void initialize() {
setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
// ... do other initialization ...
}
}
//END SNIPPET: enableUrlBaseTenantIdentificationStrategy
//START SNIPPET: resourceProvider
public class MyPatientResourceProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Read
public Patient read(RequestDetails theRequestDetails, @IdParam IdType theId) {
String tenantId = theRequestDetails.getTenantId();
String resourceId = theId.getIdPart();
// Use these two values to fetch the patient
return new Patient();
}
}
//END SNIPPET: resourceProvider
}

View File

@ -0,0 +1,43 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// START SNIPPET: sampleClass
@Interceptor
public class MyInterceptor {
private static final Logger ourLog = LoggerFactory.getLogger(MyInterceptor.class);
@Hook(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED)
public void logRequests(RequestDetails theRequest) {
ourLog.info("Request of type {} with request ID: {}", theRequest.getOperation(), theRequest.getRequestId());
}
}
// END SNIPPET: sampleClass

View File

@ -0,0 +1,119 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
//START SNIPPET: patientDef
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.util.ElementUtil;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import java.util.ArrayList;
import java.util.List;
/**
* Definition class for adding extensions to the built-in
* Patient resource type.
*
* Note the "profile" attribute below, which indicates the URL/ID of the
* profile implemented by this resource. You are not required to supply this,
* but if you do it will be automatically populated in the resource meta
* tag if the resource is returned by a server.
*/
@ResourceDef(name="Patient", profile="http://example.com/StructureDefinition/mypatient")
public class MyPatient extends Patient {
private static final long serialVersionUID = 1L;
/**
* Each extension is defined in a field. Any valid HAPI Data Type
* can be used for the field type. Note that the [name=""] attribute
* in the @Child annotation needs to match the name for the bean accessor
* and mutator methods.
*/
@Child(name="petName")
@Extension(url="http://example.com/dontuse#petname", definedLocally=false, isModifier=false)
@Description(shortDefinition="The name of the patient's favourite pet")
private StringType myPetName;
/**
* The second example extension uses a List type to provide
* repeatable values. Note that a [max=] value has been placed in
* the @Child annotation.
*
* Note also that this extension is a modifier extension
*/
@Child(name="importantDates", max=Child.MAX_UNLIMITED)
@Extension(url="http://example.com/dontuse#importantDates", definedLocally=false, isModifier=true)
@Description(shortDefinition="Some dates of note for this patient")
private List<DateTimeType> myImportantDates;
/**
* It is important to override the isEmpty() method, adding a check for any
* newly added fields.
*/
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(myPetName, myImportantDates);
}
/********
* Accessors and mutators follow
*
* IMPORTANT:
* Each extension is required to have an getter/accessor and a stter/mutator.
* You are highly recommended to create getters which create instances if they
* do not already exist, since this is how the rest of the HAPI FHIR API works.
********/
/** Getter for important dates */
public List<DateTimeType> getImportantDates() {
if (myImportantDates==null) {
myImportantDates = new ArrayList<DateTimeType>();
}
return myImportantDates;
}
/** Getter for pet name */
public StringType getPetName() {
if (myPetName == null) {
myPetName = new StringType();
}
return myPetName;
}
/** Setter for important dates */
public void setImportantDates(List<DateTimeType> theImportantDates) {
myImportantDates = theImportantDates;
}
/** Setter for pet name */
public void setPetName(StringType thePetName) {
myPetName = thePetName;
}
}
//END SNIPPET: patientDef

View File

@ -0,0 +1,106 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MyPatientUse {
@ResourceDef()
public static class MyPatient extends Patient {
@Child(name="petName")
@Extension(url="http://example.com/dontuse#petname", definedLocally=false, isModifier=false)
@Description(shortDefinition="The name of the patient's favourite pet")
private StringType myPetName;
public StringType getPetName() {
if(myPetName==null) {
myPetName = new StringType();
}
return myPetName;
}
public void setPetName(StringType thePetName) {
myPetName = thePetName;
}
public List<DateTimeType> getImportantDates() {
if (myImportantDates==null) {
myImportantDates= new ArrayList<>();
}
return myImportantDates;
}
public void setImportantDates(List<DateTimeType> theImportantDates) {
myImportantDates = theImportantDates;
}
@Child(name="importantDates", max=Child.MAX_UNLIMITED)
@Extension(url="http://example.com/dontuse#importantDates", definedLocally=false, isModifier=true)
@Description(shortDefinition="Some dates of note for the patient")
private List<DateTimeType> myImportantDates;
}
@SuppressWarnings("unused")
public static void main(String[] args) throws DataFormatException, IOException {
//START SNIPPET: patientUse
MyPatient patient = new MyPatient();
patient.setPetName(new StringType("Fido"));
patient.getImportantDates().add(new DateTimeType("2010-01-02"));
patient.getImportantDates().add(new DateTimeType("2014-01-26T11:11:11"));
patient.addName().setFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr");
IParser p = FhirContext.forDstu2().newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(patient);
System.out.println(messageString);
//END SNIPPET: patientUse
//START SNIPPET: patientParse
IParser parser = FhirContext.forDstu2().newXmlParser();
MyPatient newPatient = parser.parseResource(MyPatient.class, messageString);
//END SNIPPET: patientParse
{
FhirContext ctx2 = FhirContext.forDstu2();
RuntimeResourceDefinition def = ctx2.getResourceDefinition(patient);
System.out.println(ctx2.newXmlParser().setPrettyPrint(true).encodeResourceToString(def.toProfile()));
}
}
}

View File

@ -0,0 +1,59 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.parser.DataFormatException;
import org.hl7.fhir.r4.model.Patient;
@SuppressWarnings("unused")
public class Narrative {
public static void main(String[] args) throws DataFormatException {
//START SNIPPET: example1
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:foo").setValue("7000135");
patient.addName().setFamily("Smith").addGiven("John").addGiven("Edward");
patient.addAddress().addLine("742 Evergreen Terrace").setCity("Springfield").setState("ZZ");
FhirContext ctx = FhirContext.forDstu2();
// Use the narrative generator
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
// Encode the output, including the narrative
String output = ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(output);
//END SNIPPET: example1
}
public void simple() {
//START SNIPPET: simple
Patient pat = new Patient();
pat.getText().setStatus(org.hl7.fhir.r4.model.Narrative.NarrativeStatus.GENERATED);
pat.getText().setDivAsString("<div>This is the narrative text<br/>this is line 2</div>");
//END SNIPPET: simple
}
}

View File

@ -0,0 +1,41 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator;
@SuppressWarnings("unused")
public class NarrativeGenerator {
public void testGenerator() {
//START SNIPPET: gen
FhirContext ctx = FhirContext.forDstu2();
String propFile = "classpath:/com/foo/customnarrative.properties";
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator(propFile);
ctx.setNarrativeGenerator(gen);
//END SNIPPET: gen
}
}

View File

@ -0,0 +1,105 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.IResourceProvider;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.InstantType;
import org.hl7.fhir.r4.model.Patient;
import javax.annotation.Nonnull;
import java.util.List;
@SuppressWarnings("null")
// START SNIPPET: provider
public class PagingPatientProvider implements IResourceProvider {
/**
* Search for Patient resources matching a given family name
*/
@Search
public IBundleProvider search(@RequiredParam(name = Patient.SP_FAMILY) StringParam theFamily) {
final InstantType searchTime = InstantType.withCurrentTime();
/**
* 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
public Integer size() {
return matchingResourceIds.size();
}
@Nonnull
@Override
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
int end = Math.max(theToIndex, matchingResourceIds.size() - 1);
List<Long> idsToReturn = matchingResourceIds.subList(theFromIndex, end);
return loadResourcesByIds(idsToReturn);
}
@Override
public InstantType getPublished() {
return searchTime;
}
@Override
public Integer preferredPageSize() {
// Typically this method just returns null
return null;
}
@Override
public String getUuid() {
return null;
}
};
}
/**
* Load a list of patient resources given their IDs
*/
private List<IBaseResource> loadResourcesByIds(List<Long> theIdsToReturn) {
// .. implement this search against the database ..
return null;
}
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
}
// END SNIPPET: provider

View File

@ -0,0 +1,53 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@SuppressWarnings({ "serial" })
//START SNIPPET: provider
public class PagingServer extends RestfulServer {
public PagingServer() {
/*
* Set the resource providers as always. Here we are using the paging
* provider from the example below, but it is not strictly neccesary
* to use a paging resource provider as well. If a normal resource
* provider is used (one which returns List<?> instead of IBundleProvider)
* then the loaded resources will be stored by the IPagingProvider.
*/
setResourceProviders(new PagingPatientProvider());
/*
* Set a paging provider. Here a simple in-memory implementation
* is used, but you may create your own.
*/
FifoMemoryPagingProvider pp = new FifoMemoryPagingProvider(10);
pp.setDefaultPageSize(10);
pp.setMaximumPageSize(100);
setPagingProvider(pp);
}
}
//END SNIPPET: provider

View File

@ -0,0 +1,62 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import java.io.IOException;
public class Parser {
public static void main(String[] args) throws DataFormatException, IOException {
{
//START SNIPPET: disableStripVersions
FhirContext ctx = FhirContext.forDstu2();
IParser parser = ctx.newJsonParser();
// Disable the automatic stripping of versions from references on the parser
parser.setStripVersionsFromReferences(false);
//END SNIPPET: disableStripVersions
//START SNIPPET: disableStripVersionsCtx
ctx.getParserOptions().setStripVersionsFromReferences(false);
//END SNIPPET: disableStripVersionsCtx
}
{
//START SNIPPET: disableStripVersionsField
FhirContext ctx = FhirContext.forDstu2();
IParser parser = ctx.newJsonParser();
// Preserve versions only on these two fields (for the given parser)
parser.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference", "Patient.managingOrganization");
// You can also apply this setting to the context so that it will
// flow to all parsers
ctx.getParserOptions().setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.reference", "Patient.managingOrganization");
//END SNIPPET: disableStripVersionsField
}
}
}

View File

@ -0,0 +1,51 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Patch;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.api.PatchTypeEnum;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.OperationOutcome;
public class PatchExamples {
//START SNIPPET: patch
@Patch
public OperationOutcome patientPatch(@IdParam IdType theId, PatchTypeEnum thePatchType, @ResourceParam String theBody) {
if (thePatchType == PatchTypeEnum.JSON_PATCH) {
// do something
}
if (thePatchType == PatchTypeEnum.XML_PATCH) {
// do something
}
OperationOutcome retVal = new OperationOutcome();
retVal.getText().setDivAsString("<div>OK</div>");
return retVal;
}
//END SNIPPET: patch
}

View File

@ -0,0 +1,73 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.MethodOutcome;
import java.io.IOException;
import java.util.List;
public class QuickUsage {
@SuppressWarnings("unused")
public static void main(String[] args) throws DataFormatException, IOException {
Patient patient = new Patient();
patient.addIdentifier().setUse(IdentifierUseEnum.OFFICIAL).setSystem("urn:fake:mrns").setValue("7000135");
patient.addIdentifier().setUse(IdentifierUseEnum.SECONDARY).setSystem("urn:fake:otherids").setValue("3287486");
patient.addName().addFamily("Smith").addGiven("John").addGiven("Q").addSuffix("Junior");
patient.setGender(AdministrativeGenderEnum.MALE);
FhirContext ctx = FhirContext.forDstu2();
String xmlEncoded = ctx.newXmlParser().encodeResourceToString(patient);
String jsonEncoded = ctx.newJsonParser().encodeResourceToString(patient);
MyClientInterface client = ctx.newRestfulClient(MyClientInterface.class, "http://foo/fhir");
IdentifierDt searchParam = new IdentifierDt("urn:someidentifiers", "7000135");
List<Patient> clients = client.findPatientsByIdentifier(searchParam);
}
public interface MyClientInterface extends IRestfulClient
{
/** A FHIR search */
@Search
public List<Patient> findPatientsByIdentifier(@RequiredParam(name = "identifier") IdentifierDt theIdentifier);
/** A FHIR create */
@Create
public MethodOutcome createPatient(@ResourceParam Patient thePatient);
}
}

View File

@ -0,0 +1,49 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
//START SNIPPET: interceptor
public class RequestCounterInterceptor extends InterceptorAdapter
{
private int myRequestCount;
public int getRequestCount() {
return myRequestCount;
}
/**
* Override the incomingRequestPreProcessed method, which is called
* for each incoming request before any processing is done
*/
@Override
public boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse) {
myRequestCount++;
return true;
}
}
//END SNIPPET: interceptor

View File

@ -0,0 +1,55 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
//START SNIPPET: interceptor
public class RequestExceptionInterceptor extends InterceptorAdapter
{
@Override
public boolean handleException(RequestDetails theRequestDetails, BaseServerResponseException theException, HttpServletRequest theServletRequest,
HttpServletResponse theServletResponse) throws ServletException, IOException {
// HAPI's server exceptions know what the appropriate HTTP status code is
theServletResponse.setStatus(theException.getStatusCode());
// Provide a response ourself
theServletResponse.setContentType("text/plain");
theServletResponse.getWriter().append("Failed to process!");
theServletResponse.getWriter().close();
// Since we handled this response in the interceptor, we must return false
// to stop processing immediately
return false;
}
}
//END SNIPPET: interceptor

View File

@ -0,0 +1,56 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
public class ResourceRefs {
private static FhirContext ourCtx = FhirContext.forDstu2();
public static void main(String[] args) {
manualContained();
}
public static void manualContained() {
// START SNIPPET: manualContained
// Create an organization, and give it a local ID
Organization org = new Organization();
org.setId("#localOrganization");
org.getNameElement().setValue("Contained Test Organization");
// Create a patient
Patient patient = new Patient();
patient.setId("Patient/1333");
patient.addIdentifier().setSystem("urn:mrns").setValue("253345");
// Set the reference, and manually add the contained resource
patient.getManagingOrganization().setReference("#localOrganization");
patient.getContained().add(org);
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
System.out.println(encoded);
// END SNIPPET: manualContained
}
}

View File

@ -0,0 +1,107 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.server.IResourceProvider;
import org.hl7.fhir.r4.model.Enumerations;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Patient;
import java.util.Collections;
import java.util.List;
//START SNIPPET: provider
/**
* All resource providers must implement IResourceProvider
*/
public class RestfulObservationResourceProvider implements IResourceProvider {
/**
* The getResourceType method comes from IResourceProvider, and must
* be overridden to indicate what type of resource this provider
* supplies.
*/
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
/**
* The "@Read" annotation indicates that this method supports the
* read operation. It takes one argument, the Resource type being returned.
*
* @param theId
* The read operation takes one parameter, which must be of type
* IdType and must be annotated with the "@Read.IdParam" annotation.
* @return
* Returns a resource matching this identifier, or null if none exists.
*/
@Read()
public Patient getResourceById(@IdParam IdType theId) {
Patient patient = new Patient();
patient.addIdentifier();
patient.getIdentifier().get(0).setSystem("urn:hapitest:mrns");
patient.getIdentifier().get(0).setValue("00002");
patient.addName().setFamily("Test");
patient.getName().get(0).addGiven("PatientOne");
patient.setGender(Enumerations.AdministrativeGender.FEMALE);
return patient;
}
/**
* The "@Search" annotation indicates that this method supports the
* search operation. You may have many different methods annotated with
* this annotation, to support many different search criteria. This
* example searches by family name.
*
* @param theFamilyName
* This operation takes one parameter which is the search criteria. It is
* annotated with the "@Required" annotation. This annotation takes one argument,
* a string containing the name of the search criteria. The datatype here
* is StringDt, but there are other possible parameter types depending on the
* specific search criteria.
* @return
* This method returns a list of Patients. This list may contain multiple
* matching resources, or it may also be empty.
*/
@Search()
public List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringDt theFamilyName) {
Patient patient = new Patient();
patient.addIdentifier();
patient.getIdentifier().get(0).setUse(Identifier.IdentifierUse.OFFICIAL);
patient.getIdentifier().get(0).setSystem("urn:hapitest:mrns");
patient.getIdentifier().get(0).setValue("00001");
patient.addName();
patient.getName().get(0).setFamily("Test");
patient.getName().get(0).addGiven("PatientOne");
patient.setGender(Enumerations.AdministrativeGender.MALE);
return Collections.singletonList(patient);
}
}
//END SNIPPET: provider

View File

@ -0,0 +1,111 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.IResourceProvider;
import org.hl7.fhir.r4.model.IdType;
import java.util.Collections;
import java.util.List;
//START SNIPPET: provider
/**
* All resource providers must implement IResourceProvider
*/
public class RestfulPatientResourceProvider implements IResourceProvider {
/**
* The getResourceType method comes from IResourceProvider, and must
* be overridden to indicate what type of resource this provider
* supplies.
*/
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
/**
* The "@Read" annotation indicates that this method supports the
* read operation. Read operations should return a single resource
* instance.
*
* @param theId
* The read operation takes one parameter, which must be of type
* IdType and must be annotated with the "@Read.IdParam" annotation.
* @return
* Returns a resource matching this identifier, or null if none exists.
*/
@Read()
public Patient getResourceById(@IdParam IdType theId) {
Patient patient = new Patient();
patient.addIdentifier();
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
patient.getIdentifier().get(0).setValue("00002");
patient.addName().addFamily("Test");
patient.getName().get(0).addGiven("PatientOne");
patient.setGender(AdministrativeGenderEnum.FEMALE);
return patient;
}
/**
* The "@Search" annotation indicates that this method supports the
* search operation. You may have many different methods annotated with
* this annotation, to support many different search criteria. This
* example searches by family name.
*
* @param theFamilyName
* This operation takes one parameter which is the search criteria. It is
* annotated with the "@Required" annotation. This annotation takes one argument,
* a string containing the name of the search criteria. The datatype here
* is StringParam, but there are other possible parameter types depending on the
* specific search criteria.
* @return
* This method returns a list of Patients. This list may contain multiple
* matching resources, or it may also be empty.
*/
@Search()
public List<Patient> getPatient(@RequiredParam(name = Patient.SP_FAMILY) StringParam theFamilyName) {
Patient patient = new Patient();
patient.addIdentifier();
patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL);
patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns"));
patient.getIdentifier().get(0).setValue("00001");
patient.addName();
patient.getName().get(0).addFamily(theFamilyName.getValue());
patient.getName().get(0).addGiven("PatientOne");
patient.setGender(AdministrativeGenderEnum.MALE);
return Collections.singletonList(patient);
}
}
//END SNIPPET: provider

View File

@ -0,0 +1,85 @@
package ca.uhn.hapi.fhir.docs;
/*-
* #%L
* HAPI FHIR - Docs
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import org.apache.commons.codec.binary.Base64;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class SecurityInterceptors {
// START SNIPPET: basicAuthInterceptor
public class BasicSecurityInterceptor extends InterceptorAdapter
{
/**
* This interceptor implements HTTP Basic Auth, which specifies that
* a username and password are provided in a header called Authorization.
*/
@Override
public boolean incomingRequestPostProcessed(RequestDetails theRequestDetails, HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException {
String authHeader = theRequest.getHeader("Authorization");
// The format of the header must be:
// Authorization: Basic [base64 of username:password]
if (authHeader == null || authHeader.startsWith("Basic ") == false) {
throw new AuthenticationException("Missing or invalid Authorization header");
}
String base64 = authHeader.substring("Basic ".length());
String base64decoded = new String(Base64.decodeBase64(base64));
String[] parts = base64decoded.split("\\:");
String username = parts[0];
String password = parts[1];
/*
* Here we test for a hardcoded username & password. This is
* not typically how you would implement this in a production
* system of course..
*/
if (!username.equals("someuser") || !password.equals("thepassword")) {
throw new AuthenticationException("Invalid username or password");
}
// Return true to allow the request to proceed
return true;
}
}
//END SNIPPET: basicAuthInterceptor
public void basicAuthInterceptorRealm() {
//START SNIPPET: basicAuthInterceptorRealm
AuthenticationException ex = new AuthenticationException();
ex.addAuthenticateHeaderForRealm("myRealm");
throw ex;
//END SNIPPET: basicAuthInterceptorRealm
}
}

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