mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-03-09 14:33:32 +00:00
Merge branch 'master' into missing-date-fields-fix
This commit is contained in:
commit
1a2271f751
@ -3,15 +3,13 @@ HAPI FHIR
|
|||||||
|
|
||||||
HAPI FHIR - Java API for HL7 FHIR Clients and Servers
|
HAPI FHIR - Java API for HL7 FHIR Clients and Servers
|
||||||
|
|
||||||
[](https://coveralls.io/github/jamesagnew/hapi-fhir?branch=master)
|
[](https://dev.azure.com/jamesagnew214/jamesagnew214/_build/latest?definitionId=1&branchName=master)
|
||||||
|
[](https://codecov.io/gh/jamesagnew/hapi-fhir)
|
||||||
[](http://search.maven.org/#search|ga|1|ca.uhn.hapi.fhir)
|
[](http://search.maven.org/#search|ga|1|ca.uhn.hapi.fhir)
|
||||||
[](http://jamesagnew.github.io/hapi-fhir/license.html)
|
[](http://jamesagnew.github.io/hapi-fhir/license.html)
|
||||||
|
|
||||||
* Linux Build: [](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:
|
Complete project documentation is available here:
|
||||||
http://jamesagnew.github.io/hapi-fhir/
|
http://hapifhir.io
|
||||||
|
|
||||||
A demonstration of this project is available here:
|
A demonstration of this project is available here:
|
||||||
http://hapi.fhir.org/
|
http://hapi.fhir.org/
|
||||||
|
@ -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
55
azure-pipelines.yml
Normal 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
|
@ -25,8 +25,9 @@ public class IncludesExamples {
|
|||||||
FhirContext ctx = FhirContext.forDstu2();
|
FhirContext ctx = FhirContext.forDstu2();
|
||||||
|
|
||||||
Dstu2BundleFactory bf = new Dstu2BundleFactory(ctx);
|
Dstu2BundleFactory bf = new Dstu2BundleFactory(ctx);
|
||||||
bf.initializeBundleFromResourceList(null, resources, "http://example.com/base", "http://example.com/base/Patient", 1, BundleTypeEnum.SEARCHSET);
|
bf.addRootPropertiesToBundle(null, null, null, null, null, resources.size(), BundleTypeEnum.SEARCHSET, null);
|
||||||
IBaseResource b = bf.getResourceBundle();
|
bf.addResourcesToBundle(new ArrayList<>(resources), BundleTypeEnum.SEARCHSET, null, null, null);
|
||||||
|
IBaseResource b = bf.getResourceBundle();
|
||||||
|
|
||||||
// Encode the bundle
|
// Encode the bundle
|
||||||
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
|
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
|
||||||
|
@ -143,10 +143,15 @@
|
|||||||
<groupId>org.checkerframework</groupId>
|
<groupId>org.checkerframework</groupId>
|
||||||
<artifactId>checker-compat-qual</artifactId>
|
<artifactId>checker-compat-qual</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>ooxml-schemas</artifactId>
|
||||||
|
</dependency>
|
||||||
</ignoredDependencies>
|
</ignoredDependencies>
|
||||||
<ignoredResourcePatterns>
|
<ignoredResourcePatterns>
|
||||||
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
|
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
|
||||||
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
|
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
|
||||||
|
<ignoredResourcePattern>schemaorg_apache_xmlbeans.*</ignoredResourcePattern>
|
||||||
<ignoredResource>javac.bat</ignoredResource>
|
<ignoredResource>javac.bat</ignoredResource>
|
||||||
<ignoredResource>about.html</ignoredResource>
|
<ignoredResource>about.html</ignoredResource>
|
||||||
<ignoredResource>changelog.xml</ignoredResource>
|
<ignoredResource>changelog.xml</ignoredResource>
|
||||||
@ -181,6 +186,7 @@
|
|||||||
</links>
|
</links>
|
||||||
<additionalparam>-Xdoclint:none</additionalparam>
|
<additionalparam>-Xdoclint:none</additionalparam>
|
||||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||||
|
<source>8</source>
|
||||||
</configuration>
|
</configuration>
|
||||||
</reportSet>
|
</reportSet>
|
||||||
</reportSets>
|
</reportSets>
|
||||||
@ -204,11 +210,13 @@
|
|||||||
<verbose>false</verbose>
|
<verbose>false</verbose>
|
||||||
<debug>false</debug>
|
<debug>false</debug>
|
||||||
<additionalJOption>-Xdoclint:none</additionalJOption>
|
<additionalJOption>-Xdoclint:none</additionalJOption>
|
||||||
|
<source>8</source>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
<execution>
|
<execution>
|
||||||
<phase>package</phase>
|
<phase>package</phase>
|
||||||
<goals>
|
<goals>
|
||||||
|
<!--<goal>aggregate-jar</goal>-->
|
||||||
<goal>jar</goal>
|
<goal>jar</goal>
|
||||||
</goals>
|
</goals>
|
||||||
</execution>
|
</execution>
|
||||||
|
@ -8,6 +8,7 @@ import java.io.IOException;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||||
import org.hl7.fhir.dstu3.model.*;
|
import org.hl7.fhir.dstu3.model.*;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
@ -20,7 +21,6 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
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.IGenericClient;
|
||||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
||||||
|
@ -69,12 +69,21 @@
|
|||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-lang3</artifactId>
|
<artifactId>commons-lang3</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- JENA Dependencies - Used for Turtle encoding -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.jena</groupId>
|
<groupId>org.apache.jena</groupId>
|
||||||
<artifactId>apache-jena-libs</artifactId>
|
<artifactId>apache-jena-libs</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.github.jsonld-java</groupId>
|
||||||
|
<artifactId>jsonld-java</artifactId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.commons</groupId>
|
<groupId>org.apache.commons</groupId>
|
||||||
<artifactId>commons-text</artifactId>
|
<artifactId>commons-text</artifactId>
|
||||||
@ -111,6 +120,7 @@
|
|||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@ -119,12 +129,6 @@
|
|||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<classFolders>
|
|
||||||
<classFolder>${basedir}/target/classes</classFolder>
|
|
||||||
</classFolders>
|
|
||||||
<sourceFolders>
|
|
||||||
<sourceFolder>${basedir}/src/main/java</sourceFolder>
|
|
||||||
</sourceFolders>
|
|
||||||
<dumpOnExit>true</dumpOnExit>
|
<dumpOnExit>true</dumpOnExit>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
@ -143,20 +147,6 @@
|
|||||||
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
|
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</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>
|
<plugin>
|
||||||
<groupId>org.apache.felix</groupId>
|
<groupId>org.apache.felix</groupId>
|
||||||
<artifactId>maven-bundle-plugin</artifactId>
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
@ -66,13 +66,17 @@ public abstract class BaseRuntimeChildDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public interface IAccessor {
|
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 {
|
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) {
|
BaseRuntimeElementDefinition<?> findResourceReferenceDefinition(Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
|
||||||
|
@ -20,34 +20,33 @@ package ca.uhn.fhir.context;
|
|||||||
* #L%
|
* #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.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
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 {
|
public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChildDefinition {
|
||||||
private final IAccessor myAccessor;
|
private final IAccessor myAccessor;
|
||||||
private String myBindingValueSet;
|
|
||||||
private final String myElementName;
|
private final String myElementName;
|
||||||
private final Field myField;
|
private final Field myField;
|
||||||
private final String myFormalDefinition;
|
private final String myFormalDefinition;
|
||||||
private final int myMax;
|
private final int myMax;
|
||||||
private final int myMin;
|
private final int myMin;
|
||||||
private boolean myModifier;
|
|
||||||
|
|
||||||
private final IMutator myMutator;
|
private final IMutator myMutator;
|
||||||
private final String myShortDefinition;
|
private final String myShortDefinition;
|
||||||
|
private String myBindingValueSet;
|
||||||
|
private boolean myModifier;
|
||||||
private boolean mySummary;
|
private boolean mySummary;
|
||||||
|
|
||||||
BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
|
BaseRuntimeDeclaredChildDefinition(Field theField, Child theChildAnnotation, Description theDescriptionAnnotation, String theElementName) throws ConfigurationException {
|
||||||
super();
|
super();
|
||||||
Validate.notNull(theField, "No field speficied");
|
Validate.notNull(theField, "No field specified");
|
||||||
ValidateUtil.isGreaterThanOrEqualTo(theChildAnnotation.min(), 0, "Min must be >= 0");
|
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.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");
|
Validate.notBlank(theElementName, "Element name must not be blank");
|
||||||
@ -87,6 +86,10 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
|
|||||||
return myBindingValueSet;
|
return myBindingValueSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBindingValueSet(String theBindingValueSet) {
|
||||||
|
myBindingValueSet = theBindingValueSet;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getElementName() {
|
public String getElementName() {
|
||||||
return myElementName;
|
return myElementName;
|
||||||
@ -119,107 +122,99 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
|
|||||||
return myShortDefinition;
|
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() {
|
public boolean isModifier() {
|
||||||
return myModifier;
|
return myModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setModifier(boolean theModifier) {
|
||||||
|
myModifier = theModifier;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSummary() {
|
public boolean isSummary() {
|
||||||
return mySummary;
|
return mySummary;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setBindingValueSet(String theBindingValueSet) {
|
|
||||||
myBindingValueSet = theBindingValueSet;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setModifier(boolean theModifier) {
|
|
||||||
myModifier = theModifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class FieldListAccessor implements IAccessor {
|
private final class FieldListAccessor implements IAccessor {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public List<IBase> getValues(Object theTarget) {
|
public List<IBase> getValues(IBase theTarget) {
|
||||||
List<IBase> retVal;
|
List<IBase> retVal = (List<IBase>) getFieldValue(theTarget, myField);
|
||||||
try {
|
|
||||||
retVal = (List<IBase>) myField.get(theTarget);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ConfigurationException("Failed to get value", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
retVal = Collections.emptyList();
|
retVal = Collections.emptyList();
|
||||||
}
|
}
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final class FieldListMutator implements IMutator {
|
protected final class FieldListMutator implements IMutator {
|
||||||
@Override
|
@Override
|
||||||
public void addValue(Object theTarget, IBase theValue) {
|
public void addValue(IBase theTarget, IBase theValue) {
|
||||||
addValue(theTarget, theValue, false);
|
addValue(theTarget, theValue, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addValue(Object theTarget, IBase theValue, boolean theClear) {
|
private void addValue(IBase theTarget, IBase theValue, boolean theClear) {
|
||||||
try {
|
@SuppressWarnings("unchecked")
|
||||||
@SuppressWarnings("unchecked")
|
List<IBase> existingList = (List<IBase>) getFieldValue(theTarget, myField);
|
||||||
List<IBase> existingList = (List<IBase>) myField.get(theTarget);
|
if (existingList == null) {
|
||||||
if (existingList == null) {
|
existingList = new ArrayList<>(2);
|
||||||
existingList = new ArrayList<IBase>(2);
|
setFieldValue(theTarget, existingList, myField);
|
||||||
myField.set(theTarget, existingList);
|
|
||||||
}
|
|
||||||
if (theClear) {
|
|
||||||
existingList.clear();
|
|
||||||
}
|
|
||||||
existingList.add(theValue);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ConfigurationException("Failed to set value", e);
|
|
||||||
}
|
}
|
||||||
|
if (theClear) {
|
||||||
|
existingList.clear();
|
||||||
|
}
|
||||||
|
existingList.add(theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Object theTarget, IBase theValue) {
|
public void setValue(IBase theTarget, IBase theValue) {
|
||||||
addValue(theTarget, theValue, true);
|
addValue(theTarget, theValue, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class FieldPlainAccessor implements IAccessor {
|
private final class FieldPlainAccessor implements IAccessor {
|
||||||
@Override
|
@Override
|
||||||
public List<IBase> getValues(Object theTarget) {
|
public List<IBase> getValues(IBase theTarget) {
|
||||||
try {
|
Object values = getFieldValue(theTarget, myField);
|
||||||
Object values = myField.get(theTarget);
|
if (values == null) {
|
||||||
if (values == null) {
|
return Collections.emptyList();
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
List<IBase> retVal = Collections.singletonList((IBase) values);
|
|
||||||
return retVal;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ConfigurationException("Failed to get value", e);
|
|
||||||
}
|
}
|
||||||
|
return Collections.singletonList((IBase) values);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBase getFirstValueOrNull(IBase theTarget) {
|
||||||
|
return (IBase) getFieldValue(theTarget, myField);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final class FieldPlainMutator implements IMutator {
|
protected final class FieldPlainMutator implements IMutator {
|
||||||
@Override
|
@Override
|
||||||
public void addValue(Object theTarget, IBase theValue) {
|
public void addValue(IBase theTarget, IBase theValue) {
|
||||||
try {
|
setFieldValue(theTarget, theValue, myField);
|
||||||
myField.set(theTarget, theValue);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ConfigurationException("Failed to set value", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Object theTarget, IBase theValue) {
|
public void setValue(IBase theTarget, IBase theValue) {
|
||||||
addValue(theTarget, 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
|
|||||||
public IAccessor getAccessor() {
|
public IAccessor getAccessor() {
|
||||||
return new IAccessor() {
|
return new IAccessor() {
|
||||||
@Override
|
@Override
|
||||||
public List<IBase> getValues(Object theTarget) {
|
public List<IBase> getValues(IBase theTarget) {
|
||||||
ExtensionDt target = (ExtensionDt) theTarget;
|
ExtensionDt target = (ExtensionDt) theTarget;
|
||||||
if (target.getValue() != null) {
|
if (target.getValue() != null) {
|
||||||
return Collections.singletonList((IBase) target.getValue());
|
return Collections.singletonList((IBase) target.getValue());
|
||||||
@ -76,6 +76,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
|
|||||||
ArrayList<IBase> retVal = new ArrayList<IBase>(target.getUndeclaredExtensions());
|
ArrayList<IBase> retVal = new ArrayList<IBase>(target.getUndeclaredExtensions());
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +114,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
|
|||||||
public IMutator getMutator() {
|
public IMutator getMutator() {
|
||||||
return new IMutator() {
|
return new IMutator() {
|
||||||
@Override
|
@Override
|
||||||
public void addValue(Object theTarget, IBase theValue) {
|
public void addValue(IBase theTarget, IBase theValue) {
|
||||||
ExtensionDt target = (ExtensionDt) theTarget;
|
ExtensionDt target = (ExtensionDt) theTarget;
|
||||||
if (theValue instanceof IDatatype) {
|
if (theValue instanceof IDatatype) {
|
||||||
target.setValue((IDatatype) theTarget);
|
target.setValue((IDatatype) theTarget);
|
||||||
@ -123,7 +124,7 @@ public class RuntimeChildUndeclaredExtensionDefinition extends BaseRuntimeChildD
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setValue(Object theTarget, IBase theValue) {
|
public void setValue(IBase theTarget, IBase theValue) {
|
||||||
ExtensionDt target = (ExtensionDt) theTarget;
|
ExtensionDt target = (ExtensionDt) theTarget;
|
||||||
if (theValue instanceof IDatatype) {
|
if (theValue instanceof IDatatype) {
|
||||||
target.setValue((IDatatype) theTarget);
|
target.setValue((IDatatype) theTarget);
|
||||||
|
@ -20,31 +20,29 @@ package ca.uhn.fhir.model.api;
|
|||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
import java.util.Collections;
|
import ca.uhn.fhir.model.api.annotation.Description;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.api.annotation.Child;
|
import java.util.*;
|
||||||
import ca.uhn.fhir.model.api.annotation.Description;
|
|
||||||
|
|
||||||
public abstract class BaseElement implements /*IElement, */ISupportsUndeclaredExtensions {
|
public abstract class BaseElement implements /*IElement, */ISupportsUndeclaredExtensions {
|
||||||
|
|
||||||
private static final long serialVersionUID = -3092659584634499332L;
|
private static final long serialVersionUID = -3092659584634499332L;
|
||||||
private List<String> myFormatCommentsPost;
|
private List<String> myFormatCommentsPost;
|
||||||
private List<String> myFormatCommentsPre;
|
private List<String> myFormatCommentsPre;
|
||||||
|
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." )
|
@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;
|
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.
|
* 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)
|
@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." )
|
@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;
|
private List<ExtensionDt> myUndeclaredModifierExtensions;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -148,6 +146,21 @@ public abstract class BaseElement implements /*IElement, */ISupportsUndeclaredEx
|
|||||||
return (myFormatCommentsPre != null && !myFormatCommentsPre.isEmpty()) || (myFormatCommentsPost != null && !myFormatCommentsPost.isEmpty());
|
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
|
* 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()}.
|
* content in this superclass instance is empty per the semantics of {@link #isEmpty()}.
|
||||||
|
@ -25,5 +25,6 @@ import org.hl7.fhir.instance.model.api.IBase;
|
|||||||
|
|
||||||
|
|
||||||
public interface IElement extends IBase {
|
public interface IElement extends IBase {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ public class Include implements Serializable {
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final boolean myImmutable;
|
private final boolean myImmutable;
|
||||||
private boolean myRecurse;
|
private boolean myIterate;
|
||||||
private String myValue;
|
private String myValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,12 +59,12 @@ public class Include implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param theValue
|
* @param theValue
|
||||||
* The <code>_include</code> value, e.g. "Patient:name"
|
* The <code>_include</code> value, e.g. "Patient:name"
|
||||||
* @param theRecurse
|
* @param theIterate
|
||||||
* Should the include recurse
|
* Should the include recurse
|
||||||
*/
|
*/
|
||||||
public Include(String theValue, boolean theRecurse) {
|
public Include(String theValue, boolean theIterate) {
|
||||||
myValue = theValue;
|
myValue = theValue;
|
||||||
myRecurse = theRecurse;
|
myIterate = theIterate;
|
||||||
myImmutable = false;
|
myImmutable = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,12 +73,12 @@ public class Include implements Serializable {
|
|||||||
*
|
*
|
||||||
* @param theValue
|
* @param theValue
|
||||||
* The <code>_include</code> value, e.g. "Patient:name"
|
* The <code>_include</code> value, e.g. "Patient:name"
|
||||||
* @param theRecurse
|
* @param theIterate
|
||||||
* Should the include recurse
|
* Should the include recurse
|
||||||
*/
|
*/
|
||||||
public Include(String theValue, boolean theRecurse, boolean theImmutable) {
|
public Include(String theValue, boolean theIterate, boolean theImmutable) {
|
||||||
myValue = theValue;
|
myValue = theValue;
|
||||||
myRecurse = theRecurse;
|
myIterate = theIterate;
|
||||||
myImmutable = theImmutable;
|
myImmutable = theImmutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ public class Include implements Serializable {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Include other = (Include) obj;
|
Include other = (Include) obj;
|
||||||
if (myRecurse != other.myRecurse) {
|
if (myIterate != other.myIterate) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (myValue == null) {
|
if (myValue == null) {
|
||||||
@ -177,7 +177,7 @@ public class Include implements Serializable {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
result = prime * result + (myRecurse ? 1231 : 1237);
|
result = prime * result + (myIterate ? 1231 : 1237);
|
||||||
result = prime * result + ((myValue == null) ? 0 : myValue.hashCode());
|
result = prime * result + ((myValue == null) ? 0 : myValue.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -190,7 +190,7 @@ public class Include implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRecurse() {
|
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
|
* @return Returns a reference to <code>this</code> for easy method chaining
|
||||||
*/
|
*/
|
||||||
public Include setRecurse(boolean theRecurse) {
|
public Include setRecurse(boolean theRecurse) {
|
||||||
myRecurse = theRecurse;
|
myIterate = theRecurse;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +214,7 @@ public class Include implements Serializable {
|
|||||||
* Return a new
|
* Return a new
|
||||||
*/
|
*/
|
||||||
public Include toLocked() {
|
public Include toLocked() {
|
||||||
Include retVal = new Include(myValue, myRecurse, true);
|
Include retVal = new Include(myValue, myIterate, true);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ public class Include implements Serializable {
|
|||||||
public String toString() {
|
public String toString() {
|
||||||
ToStringBuilder builder = new ToStringBuilder(this);
|
ToStringBuilder builder = new ToStringBuilder(this);
|
||||||
builder.append("value", myValue);
|
builder.append("value", myValue);
|
||||||
builder.append("recurse", myRecurse);
|
builder.append("iterate", myIterate);
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,7 +273,7 @@ public class Include implements Serializable {
|
|||||||
b.append(':');
|
b.append(':');
|
||||||
b.append(theResourceType);
|
b.append(theResourceType);
|
||||||
}
|
}
|
||||||
Include retVal = new Include(b.toString(), myRecurse, myImmutable);
|
Include retVal = new Include(b.toString(), myIterate, myImmutable);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
|||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
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 org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -629,5 +630,5 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -282,4 +282,14 @@ public class TagList implements Set<Tag>, Serializable, IBase {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getUserData(String theName) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUserData(String theName, Object theValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,21 +20,20 @@ package ca.uhn.fhir.model.primitive;
|
|||||||
* #L%
|
* #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.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
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;
|
|
||||||
|
|
||||||
public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
||||||
static final long NANOS_PER_MILLIS = 1000000L;
|
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 ourHumanDateFormat = FastDateFormat.getDateInstance(FastDateFormat.MEDIUM);
|
||||||
private static final FastDateFormat ourHumanDateTimeFormat = FastDateFormat.getDateTimeInstance(FastDateFormat.MEDIUM, 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 String myFractionalSeconds;
|
||||||
private TemporalPrecisionEnum myPrecision = null;
|
private TemporalPrecisionEnum myPrecision = null;
|
||||||
private TimeZone myTimeZone;
|
private TimeZone myTimeZone;
|
||||||
@ -635,7 +635,12 @@ public abstract class BaseDateTimeDt extends BasePrimitive<Date> {
|
|||||||
@Override
|
@Override
|
||||||
public void setValueAsString(String theValue) throws DataFormatException {
|
public void setValueAsString(String theValue) throws DataFormatException {
|
||||||
clearTimeZone();
|
clearTimeZone();
|
||||||
super.setValueAsString(theValue);
|
|
||||||
|
if (NOW_DATE_CONSTANT.equalsIgnoreCase(theValue)) {
|
||||||
|
super.setValueAsString(ourXmlDateTimeFormat.format(new Date()));
|
||||||
|
} else {
|
||||||
|
super.setValueAsString(theValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -128,114 +128,41 @@ public abstract class BaseParser implements IParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final CompositeChildElement theParent, EncodeContext theEncodeContext) {
|
protected Iterable<CompositeChildElement> compositeChildIterator(IBase theCompositeElement, final boolean theContainedResource, final CompositeChildElement theParent, EncodeContext theEncodeContext) {
|
||||||
|
|
||||||
BaseRuntimeElementCompositeDefinition<?> elementDef = (BaseRuntimeElementCompositeDefinition<?>) myContext.getElementDefinition(theCompositeElement.getClass());
|
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
|
for (final BaseRuntimeChildDefinition child : children) {
|
||||||
public Iterator<CompositeChildElement> iterator() {
|
CompositeChildElement myNext = new CompositeChildElement(theParent, child, theEncodeContext);
|
||||||
|
|
||||||
return new Iterator<CompositeChildElement>() {
|
/*
|
||||||
private Iterator<? extends BaseRuntimeChildDefinition> myChildrenIter;
|
* There are lots of reasons we might skip encoding a particular child
|
||||||
private Boolean myHasNext = null;
|
*/
|
||||||
private CompositeChildElement myNext;
|
if (myNext.getDef().getElementName().equals("id")) {
|
||||||
|
continue;
|
||||||
/**
|
} else if (!myNext.shouldBeEncoded(theContainedResource)) {
|
||||||
* Constructor
|
continue;
|
||||||
*/ {
|
} else if (myNext.getDef() instanceof RuntimeChildNarrativeDefinition) {
|
||||||
myChildrenIter = children.iterator();
|
if (isSuppressNarratives() || isSummaryMode()) {
|
||||||
|
continue;
|
||||||
|
} else if (theContainedResource) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
} else if (myNext.getDef() instanceof RuntimeChildContainedResources) {
|
||||||
@Override
|
if (theContainedResource) {
|
||||||
public boolean hasNext() {
|
continue;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@Override
|
result.add(myNext);
|
||||||
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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
return result;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void containResourcesForEncoding(ContainedResources theContained, IBaseResource theResource, IBaseResource theTarget) {
|
private void containResourcesForEncoding(ContainedResources theContained, IBaseResource theResource, IBaseResource theTarget) {
|
||||||
|
List<IBaseReference> allReferences = getAllBaseReferences(theResource);
|
||||||
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);
|
|
||||||
for (IBaseReference next : allReferences) {
|
for (IBaseReference next : allReferences) {
|
||||||
IBaseResource resource = next.getResource();
|
IBaseResource resource = next.getResource();
|
||||||
if (resource == null && next.getReferenceElement().isLocal()) {
|
if (resource == null && next.getReferenceElement().isLocal()) {
|
||||||
@ -274,12 +201,117 @@ public abstract class BaseParser implements IParser {
|
|||||||
|
|
||||||
protected void containResourcesForEncoding(IBaseResource theResource) {
|
protected void containResourcesForEncoding(IBaseResource theResource) {
|
||||||
ContainedResources contained = new ContainedResources();
|
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);
|
containResourcesForEncoding(contained, theResource, theResource);
|
||||||
contained.assignIdsToContainedResources();
|
contained.assignIdsToContainedResources();
|
||||||
myContainedResources = contained;
|
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) {
|
private String determineReferenceText(IBaseReference theRef, CompositeChildElement theCompositeChildElement) {
|
||||||
IIdType ref = theRef.getReferenceElement();
|
IIdType ref = theRef.getReferenceElement();
|
||||||
if (isBlank(ref.getIdPart())) {
|
if (isBlank(ref.getIdPart())) {
|
||||||
@ -1193,6 +1225,37 @@ public abstract class BaseParser implements IParser {
|
|||||||
|
|
||||||
return retVal;
|
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 {
|
protected class EncodeContextPath {
|
||||||
@ -1264,13 +1327,17 @@ public abstract class BaseParser implements IParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EncodeContext is a shared state object that is passed around the
|
* EncodeContext is a shared state object that is passed around the
|
||||||
* encode process
|
* encode process
|
||||||
*/
|
*/
|
||||||
protected class EncodeContext extends EncodeContextPath {
|
protected class EncodeContext extends EncodeContextPath {
|
||||||
private final ArrayList<EncodeContextPathElement> myResourcePath = new ArrayList<>(10);
|
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() {
|
protected ArrayList<EncodeContextPathElement> getResourcePath() {
|
||||||
return myResourcePath;
|
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 {
|
static class ContainedResources {
|
||||||
private long myNextContainedId = 1;
|
private long myNextContainedId = 1;
|
||||||
|
|
||||||
|
@ -224,13 +224,24 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||||||
}
|
}
|
||||||
case PRIMITIVE_DATATYPE: {
|
case PRIMITIVE_DATATYPE: {
|
||||||
final IPrimitiveType<?> value = (IPrimitiveType<?>) theNextValue;
|
final IPrimitiveType<?> value = (IPrimitiveType<?>) theNextValue;
|
||||||
if (isBlank(value.getValueAsString())) {
|
final String valueStr = value.getValueAsString();
|
||||||
|
if (isBlank(valueStr)) {
|
||||||
if (theForceEmpty) {
|
if (theForceEmpty) {
|
||||||
theEventWriter.writeNull();
|
theEventWriter.writeNull();
|
||||||
}
|
}
|
||||||
break;
|
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 (value instanceof IBaseIntegerDatatype) {
|
||||||
if (theChildName != null) {
|
if (theChildName != null) {
|
||||||
write(theEventWriter, theChildName, ((IBaseIntegerDatatype) value).getValue());
|
write(theEventWriter, theChildName, ((IBaseIntegerDatatype) value).getValue());
|
||||||
@ -262,7 +273,6 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String valueStr = value.getValueAsString();
|
|
||||||
if (theChildName != null) {
|
if (theChildName != null) {
|
||||||
write(theEventWriter, theChildName, valueStr);
|
write(theEventWriter, theChildName, valueStr);
|
||||||
} else {
|
} else {
|
||||||
@ -459,7 +469,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||||||
if (nextValue instanceof IBaseHasModifierExtensions) {
|
if (nextValue instanceof IBaseHasModifierExtensions) {
|
||||||
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
|
IBaseHasModifierExtensions element = (IBaseHasModifierExtensions) nextValue;
|
||||||
List<? extends IBaseExtension<?, ?>> ext = element.getModifierExtension();
|
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()) {
|
if (nextValue.hasFormatComment()) {
|
||||||
|
@ -19,17 +19,6 @@ package ca.uhn.fhir.parser;
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #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.*;
|
||||||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IMutator;
|
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.api.annotation.Child;
|
||||||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||||
import ca.uhn.fhir.model.base.resource.ResourceMetadataMap;
|
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.ScalarType;
|
||||||
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
import ca.uhn.fhir.parser.json.JsonLikeValue.ValueType;
|
||||||
import ca.uhn.fhir.util.*;
|
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> {
|
class ParserState<T> {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ParserState.class);
|
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 FhirContext myContext;
|
||||||
private final IParserErrorHandler myErrorHandler;
|
private final IParserErrorHandler myErrorHandler;
|
||||||
private final boolean myJsonMode;
|
private final boolean myJsonMode;
|
||||||
private T myObject;
|
|
||||||
private final IParser myParser;
|
private final IParser myParser;
|
||||||
|
private List<String> myComments = new ArrayList<String>(2);
|
||||||
|
private T myObject;
|
||||||
private IBase myPreviousElement;
|
private IBase myPreviousElement;
|
||||||
private BaseState myState;
|
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 abstract class BaseState {
|
||||||
|
|
||||||
private PreResourceState myPreResourceState;
|
private PreResourceState myPreResourceState;
|
||||||
@ -195,8 +163,7 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theValue
|
* @param theValue The attribute value
|
||||||
* The attribute value
|
|
||||||
*/
|
*/
|
||||||
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
public void attributeValue(String theName, String theValue) throws DataFormatException {
|
||||||
myErrorHandler.unknownAttribute(null, theName);
|
myErrorHandler.unknownAttribute(null, theName);
|
||||||
@ -211,8 +178,7 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theNamespaceUri
|
* @param theNamespaceUri The XML namespace (if XML) or null
|
||||||
* The XML namespace (if XML) or null
|
|
||||||
*/
|
*/
|
||||||
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
public void enteringNewElement(String theNamespaceUri, String theLocalPart) throws DataFormatException {
|
||||||
myErrorHandler.unknownElement(null, theLocalPart);
|
myErrorHandler.unknownElement(null, theLocalPart);
|
||||||
@ -275,8 +241,7 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theData
|
* @param theData The string value
|
||||||
* The string value
|
|
||||||
*/
|
*/
|
||||||
public void string(String theData) {
|
public void string(String theData) {
|
||||||
// ignore by default
|
// ignore by default
|
||||||
@ -287,8 +252,7 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theNextEvent
|
* @param theNextEvent The XML event
|
||||||
* The XML event
|
|
||||||
*/
|
*/
|
||||||
public void xmlEvent(XMLEvent theNextEvent) {
|
public void xmlEvent(XMLEvent theNextEvent) {
|
||||||
// ignore
|
// ignore
|
||||||
@ -414,30 +378,30 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (target.getChildType()) {
|
switch (target.getChildType()) {
|
||||||
case COMPOSITE_DATATYPE: {
|
case COMPOSITE_DATATYPE: {
|
||||||
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
||||||
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments());
|
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(myDefinition.getInstanceConstructorArguments());
|
||||||
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
|
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
|
||||||
ElementCompositeState newState = new ElementCompositeState(myPreResourceState, theLocalPart, compositeTarget, newChildInstance);
|
ElementCompositeState newState = new ElementCompositeState(myPreResourceState, theLocalPart, compositeTarget, newChildInstance);
|
||||||
push(newState);
|
push(newState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ID_DATATYPE:
|
case ID_DATATYPE:
|
||||||
case PRIMITIVE_DATATYPE: {
|
case PRIMITIVE_DATATYPE: {
|
||||||
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
||||||
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance(myDefinition.getInstanceConstructorArguments());
|
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance(myDefinition.getInstanceConstructorArguments());
|
||||||
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
|
myDefinition.getMutator().addValue(myParentInstance, newChildInstance);
|
||||||
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
|
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
|
||||||
push(newState);
|
push(newState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case PRIMITIVE_XHTML:
|
case PRIMITIVE_XHTML:
|
||||||
case RESOURCE:
|
case RESOURCE:
|
||||||
case RESOURCE_BLOCK:
|
case RESOURCE_BLOCK:
|
||||||
case UNDECL_EXT:
|
case UNDECL_EXT:
|
||||||
case EXTENSION_DECLARED:
|
case EXTENSION_DECLARED:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,81 +509,81 @@ class ParserState<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (target.getChildType()) {
|
switch (target.getChildType()) {
|
||||||
case COMPOSITE_DATATYPE: {
|
case COMPOSITE_DATATYPE: {
|
||||||
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
||||||
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(child.getInstanceConstructorArguments());
|
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance(child.getInstanceConstructorArguments());
|
||||||
child.getMutator().addValue(myInstance, newChildInstance);
|
child.getMutator().addValue(myInstance, newChildInstance);
|
||||||
ParserState<T>.ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, compositeTarget, newChildInstance);
|
ParserState<T>.ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, compositeTarget, newChildInstance);
|
||||||
push(newState);
|
push(newState);
|
||||||
return;
|
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);
|
|
||||||
}
|
}
|
||||||
ContainedResourcesStateHapi state = new ContainedResourcesStateHapi(getPreResourceState());
|
case ID_DATATYPE:
|
||||||
push(state);
|
case PRIMITIVE_DATATYPE: {
|
||||||
return;
|
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
||||||
}
|
IPrimitiveType<?> newChildInstance;
|
||||||
case CONTAINED_RESOURCE_LIST: {
|
newChildInstance = primitiveTarget.newInstance(child.getInstanceConstructorArguments());
|
||||||
ContainedResourcesStateHl7Org state = new ContainedResourcesStateHl7Org(getPreResourceState());
|
child.getMutator().addValue(myInstance, newChildInstance);
|
||||||
push(state);
|
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
|
||||||
return;
|
push(newState);
|
||||||
}
|
return;
|
||||||
case RESOURCE: {
|
}
|
||||||
if (myInstance instanceof IAnyResource || myInstance instanceof IBaseBackboneElement || myInstance instanceof IBaseElement) {
|
case RESOURCE_BLOCK: {
|
||||||
ParserState<T>.PreResourceStateHl7Org state = new PreResourceStateHl7Org(myInstance, child.getMutator(), null);
|
RuntimeResourceBlockDefinition blockTarget = (RuntimeResourceBlockDefinition) target;
|
||||||
push(state);
|
IBase newBlockInstance = blockTarget.newInstance();
|
||||||
} else {
|
child.getMutator().addValue(myInstance, newBlockInstance);
|
||||||
ParserState<T>.PreResourceStateHapi state = new PreResourceStateHapi(myInstance, child.getMutator(), null);
|
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theChildName, blockTarget, newBlockInstance);
|
||||||
push(state);
|
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());
|
throw new DataFormatException("Illegal resource position: " + target.getChildType());
|
||||||
@ -716,32 +680,32 @@ class ParserState<T> {
|
|||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
switch (target.getChildType()) {
|
switch (target.getChildType()) {
|
||||||
case COMPOSITE_DATATYPE: {
|
case COMPOSITE_DATATYPE: {
|
||||||
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
BaseRuntimeElementCompositeDefinition<?> compositeTarget = (BaseRuntimeElementCompositeDefinition<?>) target;
|
||||||
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance();
|
ICompositeType newChildInstance = (ICompositeType) compositeTarget.newInstance();
|
||||||
myExtension.setValue(newChildInstance);
|
myExtension.setValue(newChildInstance);
|
||||||
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theLocalPart, compositeTarget, newChildInstance);
|
ElementCompositeState newState = new ElementCompositeState(getPreResourceState(), theLocalPart, compositeTarget, newChildInstance);
|
||||||
push(newState);
|
push(newState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case ID_DATATYPE:
|
case ID_DATATYPE:
|
||||||
case PRIMITIVE_DATATYPE: {
|
case PRIMITIVE_DATATYPE: {
|
||||||
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
RuntimePrimitiveDatatypeDefinition primitiveTarget = (RuntimePrimitiveDatatypeDefinition) target;
|
||||||
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance();
|
IPrimitiveType<?> newChildInstance = primitiveTarget.newInstance();
|
||||||
myExtension.setValue(newChildInstance);
|
myExtension.setValue(newChildInstance);
|
||||||
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
|
PrimitiveState newState = new PrimitiveState(getPreResourceState(), newChildInstance);
|
||||||
push(newState);
|
push(newState);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case CONTAINED_RESOURCES:
|
case CONTAINED_RESOURCES:
|
||||||
case CONTAINED_RESOURCE_LIST:
|
case CONTAINED_RESOURCE_LIST:
|
||||||
case EXTENSION_DECLARED:
|
case EXTENSION_DECLARED:
|
||||||
case PRIMITIVE_XHTML:
|
case PRIMITIVE_XHTML:
|
||||||
case PRIMITIVE_XHTML_HL7ORG:
|
case PRIMITIVE_XHTML_HL7ORG:
|
||||||
case RESOURCE:
|
case RESOURCE:
|
||||||
case RESOURCE_BLOCK:
|
case RESOURCE_BLOCK:
|
||||||
case UNDECL_EXT:
|
case UNDECL_EXT:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -890,7 +854,6 @@ class ParserState<T> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private abstract class PreResourceState extends BaseState {
|
private abstract class PreResourceState extends BaseState {
|
||||||
|
|
||||||
private Map<String, IBaseResource> myContainedResources;
|
private Map<String, IBaseResource> myContainedResources;
|
||||||
@ -1008,14 +971,14 @@ class ParserState<T> {
|
|||||||
|
|
||||||
if (wantedProfileType != null && !wantedProfileType.equals(myInstance.getClass())) {
|
if (wantedProfileType != null && !wantedProfileType.equals(myInstance.getClass())) {
|
||||||
if (myResourceType == null || myResourceType.isAssignableFrom(wantedProfileType)) {
|
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
|
* 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
|
* 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
|
* until we've parsed the resource which type we want to use because the
|
||||||
* profile declarations are in the text of the resource itself.
|
* 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
|
* 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.
|
* of one type backed by another type and use that.
|
||||||
*/
|
*/
|
||||||
@ -1094,7 +1057,7 @@ class ParserState<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void acceptElement(IBaseResource theResource, IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
|
public void acceptElement(IBaseResource theResource, IBase theElement, List<String> thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
|
||||||
BaseRuntimeElementDefinition<?> theDefinition) {
|
BaseRuntimeElementDefinition<?> theDefinition) {
|
||||||
if (theElement instanceof BaseResourceReferenceDt) {
|
if (theElement instanceof BaseResourceReferenceDt) {
|
||||||
BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement;
|
BaseResourceReferenceDt nextRef = (BaseResourceReferenceDt) theElement;
|
||||||
String ref = nextRef.getReference().getValue();
|
String ref = nextRef.getReference().getValue();
|
||||||
@ -1137,7 +1100,7 @@ class ParserState<T> {
|
|||||||
|
|
||||||
private class PreResourceStateHapi extends PreResourceState {
|
private class PreResourceStateHapi extends PreResourceState {
|
||||||
private IMutator myMutator;
|
private IMutator myMutator;
|
||||||
private Object myTarget;
|
private IBase myTarget;
|
||||||
|
|
||||||
|
|
||||||
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
|
public PreResourceStateHapi(Class<? extends IBaseResource> theResourceType) {
|
||||||
@ -1145,7 +1108,7 @@ class ParserState<T> {
|
|||||||
assert theResourceType == null || IResource.class.isAssignableFrom(theResourceType);
|
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);
|
super(theResourceType);
|
||||||
myTarget = theTarget;
|
myTarget = theTarget;
|
||||||
myMutator = theMutator;
|
myMutator = theMutator;
|
||||||
@ -1175,18 +1138,18 @@ class ParserState<T> {
|
|||||||
String resourceName = myContext.getResourceDefinition(nextResource).getName();
|
String resourceName = myContext.getResourceDefinition(nextResource).getName();
|
||||||
String bundleIdPart = nextResource.getId().getIdPart();
|
String bundleIdPart = nextResource.getId().getIdPart();
|
||||||
if (isNotBlank(bundleIdPart)) {
|
if (isNotBlank(bundleIdPart)) {
|
||||||
// if (isNotBlank(entryBaseUrl)) {
|
// if (isNotBlank(entryBaseUrl)) {
|
||||||
// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
|
// nextResource.setId(new IdDt(entryBaseUrl, resourceName, bundleIdPart, version));
|
||||||
// } else {
|
// } else {
|
||||||
IdDt previousId = nextResource.getId();
|
IdDt previousId = nextResource.getId();
|
||||||
nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
|
nextResource.setId(new IdDt(null, resourceName, bundleIdPart, version));
|
||||||
// Copy extensions
|
// Copy extensions
|
||||||
if (!previousId.getAllUndeclaredExtensions().isEmpty()) {
|
if (!previousId.getAllUndeclaredExtensions().isEmpty()) {
|
||||||
for (final ExtensionDt ext : previousId.getAllUndeclaredExtensions()) {
|
for (final ExtensionDt ext : previousId.getAllUndeclaredExtensions()) {
|
||||||
nextResource.getId().addUndeclaredExtension(ext);
|
nextResource.getId().addUndeclaredExtension(ext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1195,13 +1158,13 @@ class ParserState<T> {
|
|||||||
private class PreResourceStateHl7Org extends PreResourceState {
|
private class PreResourceStateHl7Org extends PreResourceState {
|
||||||
|
|
||||||
private IMutator myMutator;
|
private IMutator myMutator;
|
||||||
private Object myTarget;
|
private IBase myTarget;
|
||||||
|
|
||||||
public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
|
public PreResourceStateHl7Org(Class<? extends IBaseResource> theResourceType) {
|
||||||
super(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);
|
super(theResourceType);
|
||||||
myMutator = theMutator;
|
myMutator = theMutator;
|
||||||
myTarget = theTarget;
|
myTarget = theTarget;
|
||||||
@ -1463,21 +1426,21 @@ class ParserState<T> {
|
|||||||
String value = defaultIfBlank(theValue, null);
|
String value = defaultIfBlank(theValue, null);
|
||||||
|
|
||||||
switch (mySubState) {
|
switch (mySubState) {
|
||||||
case TERM:
|
case TERM:
|
||||||
myTerm = (value);
|
myTerm = (value);
|
||||||
break;
|
break;
|
||||||
case LABEL:
|
case LABEL:
|
||||||
myLabel = (value);
|
myLabel = (value);
|
||||||
break;
|
break;
|
||||||
case SCHEME:
|
case SCHEME:
|
||||||
myScheme = (value);
|
myScheme = (value);
|
||||||
break;
|
break;
|
||||||
case NONE:
|
case NONE:
|
||||||
// This handles JSON encoding, which is a bit weird
|
// This handles JSON encoding, which is a bit weird
|
||||||
enteringNewElement(null, theName);
|
enteringNewElement(null, theName);
|
||||||
attributeValue(null, value);
|
attributeValue(null, value);
|
||||||
endingElement();
|
endingElement();
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -354,17 +354,10 @@ public class XmlParser extends BaseParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
|
if (nextChild instanceof RuntimeChildNarrativeDefinition) {
|
||||||
|
INarrative narr = (INarrative) nextChild.getAccessor().getFirstValueOrNull(theElement);
|
||||||
|
|
||||||
INarrativeGenerator gen = myContext.getNarrativeGenerator();
|
INarrativeGenerator gen = myContext.getNarrativeGenerator();
|
||||||
INarrative narr;
|
if (gen != null && (narr == null || narr.isEmpty())) {
|
||||||
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()) {
|
|
||||||
gen.populateResourceNarrative(myContext, theResource);
|
gen.populateResourceNarrative(myContext, theResource);
|
||||||
}
|
}
|
||||||
if (narr != null && narr.isEmpty() == false) {
|
if (narr != null && narr.isEmpty() == false) {
|
||||||
|
@ -52,15 +52,6 @@ public class GsonStructure implements JsonLikeStructure {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public GsonStructure (JsonObject json) {
|
|
||||||
super();
|
|
||||||
setNativeObject(json);
|
|
||||||
}
|
|
||||||
public GsonStructure (JsonArray json) {
|
|
||||||
super();
|
|
||||||
setNativeArray(json);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNativeObject (JsonObject json) {
|
public void setNativeObject (JsonObject json) {
|
||||||
this.rootType = ROOT_TYPE.OBJECT;
|
this.rootType = ROOT_TYPE.OBJECT;
|
||||||
this.nativeRoot = json;
|
this.nativeRoot = json;
|
||||||
@ -111,8 +102,7 @@ public class GsonStructure implements JsonLikeStructure {
|
|||||||
if (nextInt == '{') {
|
if (nextInt == '{') {
|
||||||
JsonObject root = gson.fromJson(pbr, JsonObject.class);
|
JsonObject root = gson.fromJson(pbr, JsonObject.class);
|
||||||
setNativeObject(root);
|
setNativeObject(root);
|
||||||
} else
|
} else if (nextInt == '[') {
|
||||||
if (nextInt == '[') {
|
|
||||||
JsonArray root = gson.fromJson(pbr, JsonArray.class);
|
JsonArray root = gson.fromJson(pbr, JsonArray.class);
|
||||||
setNativeArray(root);
|
setNativeArray(root);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +151,8 @@ public class Constants {
|
|||||||
public static final String PARAM_INCLUDE = "_include";
|
public static final String PARAM_INCLUDE = "_include";
|
||||||
public static final String PARAM_INCLUDE_QUALIFIER_RECURSE = ":recurse";
|
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_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_LASTUPDATED = "_lastUpdated";
|
||||||
public static final String PARAM_NARRATIVE = "_narrative";
|
public static final String PARAM_NARRATIVE = "_narrative";
|
||||||
public static final String PARAM_PAGINGACTION = "_getpages";
|
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_RESPONSE_URL = "response-url"; //Used in messaging
|
||||||
public static final String PARAM_REVINCLUDE = "_revinclude";
|
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_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_SEARCH = "_search";
|
||||||
public static final String PARAM_SECURITY = "_security";
|
public static final String PARAM_SECURITY = "_security";
|
||||||
public static final String PARAM_SINCE = "_since";
|
public static final String PARAM_SINCE = "_since";
|
||||||
@ -220,17 +223,35 @@ public class Constants {
|
|||||||
public static final String CASCADE_DELETE = "delete";
|
public static final String CASCADE_DELETE = "delete";
|
||||||
public static final int MAX_RESOURCE_NAME_LENGTH = 100;
|
public static final int MAX_RESOURCE_NAME_LENGTH = 100;
|
||||||
public static final String CACHE_CONTROL_PRIVATE = "private";
|
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 int STATUS_HTTP_412_PAYLOAD_TOO_LARGE = 413;
|
||||||
public static final String OPERATION_NAME_GRAPHQL = "$graphql";
|
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.
|
* 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 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 {
|
static {
|
||||||
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
||||||
CHARSET_US_ASCII = StandardCharsets.ISO_8859_1;
|
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<>();
|
HashMap<Integer, String> statusNames = new HashMap<>();
|
||||||
statusNames.put(200, "OK");
|
statusNames.put(200, "OK");
|
||||||
statusNames.put(201, "Created");
|
statusNames.put(201, "Created");
|
||||||
|
@ -19,14 +19,17 @@ package ca.uhn.fhir.rest.api;
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #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.context.api.BundleInclusionRule;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
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!
|
* 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();
|
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);
|
void initializeWithBundleResource(IBaseResource theResource);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package ca.uhn.fhir.rest.api;
|
package ca.uhn.fhir.rest.api;
|
||||||
|
|
||||||
/*
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR - Core Library
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
@ -29,16 +29,20 @@ public enum PreferReturnEnum {
|
|||||||
|
|
||||||
REPRESENTATION("representation"), MINIMAL("minimal"), OPERATION_OUTCOME("OperationOutcome");
|
REPRESENTATION("representation"), MINIMAL("minimal"), OPERATION_OUTCOME("OperationOutcome");
|
||||||
|
|
||||||
private String myHeaderValue;
|
|
||||||
private static HashMap<String, PreferReturnEnum> ourValues;
|
private static HashMap<String, PreferReturnEnum> ourValues;
|
||||||
|
private String myHeaderValue;
|
||||||
|
|
||||||
private PreferReturnEnum(String theHeaderValue) {
|
PreferReturnEnum(String theHeaderValue) {
|
||||||
myHeaderValue = theHeaderValue;
|
myHeaderValue = theHeaderValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getHeaderValue() {
|
||||||
|
return myHeaderValue;
|
||||||
|
}
|
||||||
|
|
||||||
public static PreferReturnEnum fromHeaderValue(String theHeaderValue) {
|
public static PreferReturnEnum fromHeaderValue(String theHeaderValue) {
|
||||||
if (ourValues == null) {
|
if (ourValues == null) {
|
||||||
HashMap<String, PreferReturnEnum> values = new HashMap<String, PreferReturnEnum>();
|
HashMap<String, PreferReturnEnum> values = new HashMap<>();
|
||||||
for (PreferReturnEnum next : PreferReturnEnum.values()) {
|
for (PreferReturnEnum next : PreferReturnEnum.values()) {
|
||||||
values.put(next.getHeaderValue(), next);
|
values.put(next.getHeaderValue(), next);
|
||||||
}
|
}
|
||||||
@ -47,8 +51,4 @@ public enum PreferReturnEnum {
|
|||||||
return ourValues.get(theHeaderValue);
|
return ourValues.get(theHeaderValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getHeaderValue() {
|
|
||||||
return myHeaderValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -92,10 +92,11 @@ public interface IRestfulClient {
|
|||||||
/**
|
/**
|
||||||
* Register a new interceptor for this client. An interceptor can be used to add additional
|
* 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.
|
* logging, or add security headers, or pre-process responses, etc.
|
||||||
*
|
* <p>
|
||||||
* @deprecated Use {@link #getInterceptorService()} to access the list of inteerceptors, register them, and unregister them
|
* This is a convenience method for performing the following call:
|
||||||
|
* <code>getInterceptorService().registerInterceptor(theInterceptor)</code>
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
void registerInterceptor(IClientInterceptor theInterceptor);
|
void registerInterceptor(IClientInterceptor theInterceptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -114,11 +115,12 @@ public interface IRestfulClient {
|
|||||||
void setSummary(SummaryEnum theSummary);
|
void setSummary(SummaryEnum theSummary);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
|
* Remove an interceptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}.
|
||||||
*
|
* <p>
|
||||||
* @deprecated Use {@link #getInterceptorService()} to access the list of inteerceptors, register them, and unregister them
|
* This is a convenience method for performing the following call:
|
||||||
|
* <code>getInterceptorService().unregisterInterceptor(theInterceptor)</code>
|
||||||
|
* </p>
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
|
||||||
void unregisterInterceptor(IClientInterceptor theInterceptor);
|
void unregisterInterceptor(IClientInterceptor theInterceptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,7 +47,7 @@ public abstract class BaseParamWithPrefix<T extends BaseParam> extends BaseParam
|
|||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
char nextChar = theString.charAt(offset);
|
char nextChar = theString.charAt(offset);
|
||||||
if (nextChar == '-' || Character.isDigit(nextChar)) {
|
if (nextChar == '-' || nextChar == '%' || Character.isDigit(nextChar)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,25 +19,28 @@ package ca.uhn.fhir.rest.param;
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #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.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import java.math.BigDecimal;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
|
||||||
import ca.uhn.fhir.util.CoverageIgnore;
|
import static ca.uhn.fhir.model.primitive.IdDt.isValidLong;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/ {
|
public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/ {
|
||||||
|
|
||||||
private String myChain;
|
private String myChain;
|
||||||
|
private String myResourceType;
|
||||||
|
private String myBaseUrl;
|
||||||
|
private String myValue;
|
||||||
|
private String myIdPart;
|
||||||
|
|
||||||
private final IdDt myId = new IdDt();
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
@ -64,12 +67,15 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
|
|||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public ReferenceParam(String theResourceType, String theChain, String theValue) {
|
public ReferenceParam(String theResourceType, String theChain, String theValue) {
|
||||||
|
String qualifier = "";
|
||||||
if (isNotBlank(theResourceType)) {
|
if (isNotBlank(theResourceType)) {
|
||||||
setValue(theResourceType + "/" + theValue);
|
qualifier = ":" + theResourceType;
|
||||||
} else {
|
|
||||||
setValue(theValue);
|
|
||||||
}
|
}
|
||||||
setChain(theChain);
|
if (isNotBlank(theChain)) {
|
||||||
|
qualifier = qualifier + "." + theChain;
|
||||||
|
}
|
||||||
|
|
||||||
|
setValueAsQueryToken(null, null, qualifier, theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -91,55 +97,61 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
String doGetValueAsQueryToken(FhirContext theContext) {
|
String doGetValueAsQueryToken(FhirContext theContext) {
|
||||||
if (isBlank(myId.getResourceType())) {
|
if (isBlank(getResourceType())) {
|
||||||
return myId.getValue(); // e.g. urn:asdjd or 123 or cid:wieiuru or #1
|
return myValue; // e.g. urn:asdjd or 123 or cid:wieiuru or #1
|
||||||
} else {
|
} else {
|
||||||
if (isBlank(getChain())) {
|
if (isBlank(getChain()) && isNotBlank(getResourceType())) {
|
||||||
return getResourceType() + "/" + myId.getIdPart();
|
return getResourceType() + "/" + getIdPart();
|
||||||
}
|
}
|
||||||
return myId.getIdPart();
|
return myValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
|
void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
|
||||||
String q = theQualifier;
|
String q = theQualifier;
|
||||||
String resourceType = null;
|
|
||||||
boolean skipSetValue = false;
|
|
||||||
if (isNotBlank(q)) {
|
if (isNotBlank(q)) {
|
||||||
if (q.startsWith(":")) {
|
if (q.startsWith(":")) {
|
||||||
int nextIdx = q.indexOf('.');
|
int nextIdx = q.indexOf('.');
|
||||||
if (nextIdx != -1) {
|
if (nextIdx != -1) {
|
||||||
resourceType = q.substring(1, nextIdx);
|
|
||||||
myChain = q.substring(nextIdx + 1);
|
myChain = q.substring(nextIdx + 1);
|
||||||
// type is explicitly defined so use it
|
myResourceType = q.substring(1, nextIdx);
|
||||||
myId.setParts(null, resourceType, theValue, null);
|
|
||||||
skipSetValue = true;
|
|
||||||
} else {
|
} 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(".")) {
|
} else if (q.startsWith(".")) {
|
||||||
myChain = q.substring(1);
|
myChain = q.substring(1);
|
||||||
// type not defined but this is a chain, so treat value as opaque
|
myResourceType = null;
|
||||||
myId.setParts(null, null, theValue, null);
|
myValue = theValue;
|
||||||
skipSetValue = true;
|
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
|
@CoverageIgnore
|
||||||
public String getBaseUrl() {
|
public String getBaseUrl() {
|
||||||
return myId.getBaseUrl();
|
return myBaseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -147,24 +159,34 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
|
|||||||
return myChain;
|
return myChain;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ReferenceParam setChain(String theChain) {
|
||||||
|
myChain = theChain;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@CoverageIgnore
|
@CoverageIgnore
|
||||||
public String getIdPart() {
|
public String getIdPart() {
|
||||||
return myId.getIdPart();
|
return myIdPart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@CoverageIgnore
|
@CoverageIgnore
|
||||||
public BigDecimal getIdPartAsBigDecimal() {
|
public BigDecimal getIdPartAsBigDecimal() {
|
||||||
return myId.getIdPartAsBigDecimal();
|
return new IdDt(myValue).getIdPartAsBigDecimal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@CoverageIgnore
|
@CoverageIgnore
|
||||||
public Long getIdPartAsLong() {
|
public Long getIdPartAsLong() {
|
||||||
return myId.getIdPartAsLong();
|
return new IdDt(myValue).getIdPartAsLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getResourceType() {
|
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) {
|
public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) {
|
||||||
@ -175,11 +197,21 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getValue() {
|
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() {
|
public boolean hasResourceType() {
|
||||||
return myId.hasResourceType();
|
return isNotBlank(myResourceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -187,16 +219,6 @@ public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/
|
|||||||
return true;
|
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
|
* 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
|
* to {@link DateParam}. This is useful if you are using reference parameters and want to handle
|
||||||
|
45
hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ArrayUtil.java
Normal file
45
hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ArrayUtil.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -46,12 +46,14 @@ public class BundleUtil {
|
|||||||
private final RequestTypeEnum myRequestType;
|
private final RequestTypeEnum myRequestType;
|
||||||
private final IBaseResource myResource;
|
private final IBaseResource myResource;
|
||||||
private final String myUrl;
|
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();
|
super();
|
||||||
myRequestType = theRequestType;
|
myRequestType = theRequestType;
|
||||||
myUrl = theUrl;
|
myUrl = theUrl;
|
||||||
myResource = theResource;
|
myResource = theResource;
|
||||||
|
myConditionalUrl = theConditionalUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestTypeEnum getRequestType() {
|
public RequestTypeEnum getRequestType() {
|
||||||
@ -62,6 +64,10 @@ public class BundleUtil {
|
|||||||
return myResource;
|
return myResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConditionalUrl() {
|
||||||
|
return myConditionalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return myUrl;
|
return myUrl;
|
||||||
}
|
}
|
||||||
@ -190,19 +196,21 @@ public class BundleUtil {
|
|||||||
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
||||||
BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
|
BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
|
||||||
BaseRuntimeElementCompositeDefinition<?> requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.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");
|
BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
|
||||||
|
|
||||||
for (IBase nextEntry : entries) {
|
for (IBase nextEntry : entries) {
|
||||||
IBaseResource resource = null;
|
IBaseResource resource = null;
|
||||||
String url = null;
|
String url = null;
|
||||||
RequestTypeEnum requestType = null;
|
RequestTypeEnum requestType = null;
|
||||||
|
String conditionalUrl = null;
|
||||||
|
|
||||||
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
||||||
resource = (IBaseResource) next;
|
resource = (IBaseResource) next;
|
||||||
}
|
}
|
||||||
for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
|
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();
|
url = ((IPrimitiveType<?>) nextUrl).getValueAsString();
|
||||||
}
|
}
|
||||||
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
|
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
|
||||||
@ -211,13 +219,29 @@ public class BundleUtil {
|
|||||||
requestType = RequestTypeEnum.valueOf(methodString);
|
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
|
* All 3 might be null - That's ok because we still want to know the
|
||||||
* order in the original bundle.
|
* order in the original bundle.
|
||||||
*/
|
*/
|
||||||
retVal.add(new BundleEntryParts(requestType, url, resource));
|
retVal.add(new BundleEntryParts(requestType, url, resource, conditionalUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -216,12 +216,12 @@ public class FhirTerser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object getSingleValueOrNull(IBase theTarget, String thePath) {
|
public Object getSingleValueOrNull(IBase theTarget, String thePath) {
|
||||||
Class<Object> wantedType = Object.class;
|
Class<IBase> wantedType = IBase.class;
|
||||||
|
|
||||||
return getSingleValueOrNull(theTarget, thePath, wantedType);
|
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.notNull(theTarget, "theTarget must not be null");
|
||||||
Validate.notBlank(thePath, "thePath must not be empty");
|
Validate.notBlank(thePath, "thePath must not be empty");
|
||||||
|
|
||||||
@ -241,12 +241,12 @@ public class FhirTerser {
|
|||||||
return retVal.get(0);
|
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);
|
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@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);
|
String name = theSubList.get(0);
|
||||||
List<T> retVal = new ArrayList<>();
|
List<T> retVal = new ArrayList<>();
|
||||||
|
|
||||||
@ -325,7 +325,7 @@ public class FhirTerser {
|
|||||||
List<T> values = retVal;
|
List<T> values = retVal;
|
||||||
retVal = new ArrayList<>();
|
retVal = new ArrayList<>();
|
||||||
for (T nextElement : values) {
|
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);
|
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
|
||||||
retVal.addAll(foundValues);
|
retVal.addAll(foundValues);
|
||||||
}
|
}
|
||||||
@ -410,7 +410,7 @@ public class FhirTerser {
|
|||||||
List<T> values = retVal;
|
List<T> values = retVal;
|
||||||
retVal = new ArrayList<>();
|
retVal = new ArrayList<>();
|
||||||
for (T nextElement : values) {
|
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);
|
List<T> foundValues = getValues(nextChildDef, nextElement, theSubList.subList(1, theSubList.size()), theWantedClass, theCreate, theAddExtension);
|
||||||
retVal.addAll(foundValues);
|
retVal.addAll(foundValues);
|
||||||
}
|
}
|
||||||
@ -476,9 +476,10 @@ public class FhirTerser {
|
|||||||
* @return A list of values of type {@link Object}.
|
* @return A list of values of type {@link Object}.
|
||||||
*/
|
*/
|
||||||
public List<Object> getValues(IBaseResource theResource, String thePath) {
|
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}.
|
* @return A list of values of type {@link Object}.
|
||||||
*/
|
*/
|
||||||
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate) {
|
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}.
|
* @return A list of values of type {@link Object}.
|
||||||
*/
|
*/
|
||||||
public List<Object> getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) {
|
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>
|
* @param <T> Type declared by <code>theWantedClass</code>
|
||||||
* @return A list of values of type <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);
|
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||||
List<String> parts = parsePath(def, thePath);
|
List<String> parts = parsePath(def, thePath);
|
||||||
return getValues(def, theResource, parts, theWantedClass);
|
return getValues(def, theResource, parts, theWantedClass);
|
||||||
@ -539,7 +542,7 @@ public class FhirTerser {
|
|||||||
* @param <T> Type declared by <code>theWantedClass</code>
|
* @param <T> Type declared by <code>theWantedClass</code>
|
||||||
* @return A list of values of type <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);
|
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||||
List<String> parts = parsePath(def, thePath);
|
List<String> parts = parsePath(def, thePath);
|
||||||
return getValues(def, theResource, parts, theWantedClass, theCreate, false);
|
return getValues(def, theResource, parts, theWantedClass, theCreate, false);
|
||||||
@ -557,7 +560,7 @@ public class FhirTerser {
|
|||||||
* @param <T> Type declared by <code>theWantedClass</code>
|
* @param <T> Type declared by <code>theWantedClass</code>
|
||||||
* @return A list of values of type <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);
|
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||||
List<String> parts = parsePath(def, thePath);
|
List<String> parts = parsePath(def, thePath);
|
||||||
return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);
|
return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);
|
||||||
@ -728,7 +731,12 @@ public class FhirTerser {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BaseRuntimeElementDefinition<?> childElementDef;
|
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) {
|
if (childElementDef == null) {
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
|
@ -108,9 +108,13 @@ public class OperationOutcomeUtil {
|
|||||||
if (theOutcome == null) {
|
if (theOutcome == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return getIssueCount(theCtx, theOutcome) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getIssueCount(FhirContext theCtx, IBaseOperationOutcome theOutcome) {
|
||||||
RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
|
RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
|
||||||
BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
|
BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
|
||||||
return issueChild.getAccessor().getValues(theOutcome).size() > 0;
|
return issueChild.getAccessor().getValues(theOutcome).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IBaseOperationOutcome newInstance(FhirContext theCtx) {
|
public static IBaseOperationOutcome newInstance(FhirContext theCtx) {
|
||||||
@ -152,5 +156,4 @@ public class OperationOutcomeUtil {
|
|||||||
locationChild.getMutator().addValue(theIssue, locationElem);
|
locationChild.getMutator().addValue(theIssue, locationElem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,9 @@ public class StopWatch {
|
|||||||
myStarted = theStart.getTime();
|
myStarted = theStart.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public StopWatch(long theL) {
|
||||||
|
}
|
||||||
|
|
||||||
private void addNewlineIfContentExists(StringBuilder theB) {
|
private void addNewlineIfContentExists(StringBuilder theB) {
|
||||||
if (theB.length() > 0) {
|
if (theB.length() > 0) {
|
||||||
theB.append("\n");
|
theB.append("\n");
|
||||||
@ -231,7 +234,12 @@ public class StopWatch {
|
|||||||
|
|
||||||
double denominator = ((double) millisElapsed) / ((double) periodMillis);
|
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() {
|
public void restart() {
|
||||||
|
@ -182,4 +182,13 @@ public class TestUtil {
|
|||||||
return defaultString(theString).replace("\r", "");
|
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(" ", "");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -61,4 +61,14 @@ public interface IBase extends Serializable {
|
|||||||
*/
|
*/
|
||||||
default String fhirType() { return null; }
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -25,5 +25,9 @@ public interface IBaseElement {
|
|||||||
IBaseElement setId(String theValue);
|
IBaseElement setId(String theValue);
|
||||||
|
|
||||||
String getId();
|
String getId();
|
||||||
|
|
||||||
|
Object getUserData(String theName);
|
||||||
|
|
||||||
|
void setUserData(String theName, Object theValue);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,11 +60,13 @@ ca.uhn.fhir.validation.ValidationResult.noIssuesDetected=No issues detected duri
|
|||||||
|
|
||||||
# JPA Messages
|
# 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.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.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.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.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.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
|
ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.invalidMatchUrlNoMatches=Invalid match URL "{0}" - No resources match this search
|
||||||
|
@ -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, "t", "to", "Version", "The database schema version to migrate TO");
|
||||||
addRequiredOption(retVal, "d", "driver", "Driver", "The database driver to use (Options are " + driverOptions() + ")");
|
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, "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;
|
return retVal;
|
||||||
}
|
}
|
||||||
@ -106,6 +107,7 @@ public abstract class BaseMigrateDatabaseCommand<T extends Enum> extends BaseCom
|
|||||||
validateVersionSupported(to);
|
validateVersionSupported(to);
|
||||||
|
|
||||||
boolean dryRun = theCommandLine.hasOption("r");
|
boolean dryRun = theCommandLine.hasOption("r");
|
||||||
|
boolean noColumnShrink = theCommandLine.hasOption("no-column-shrink");
|
||||||
|
|
||||||
String flags = theCommandLine.getOptionValue("x");
|
String flags = theCommandLine.getOptionValue("x");
|
||||||
myFlags = Arrays.stream(defaultString(flags).split(","))
|
myFlags = Arrays.stream(defaultString(flags).split(","))
|
||||||
@ -119,6 +121,7 @@ public abstract class BaseMigrateDatabaseCommand<T extends Enum> extends BaseCom
|
|||||||
migrator.setUsername(username);
|
migrator.setUsername(username);
|
||||||
migrator.setPassword(password);
|
migrator.setPassword(password);
|
||||||
migrator.setDryRun(dryRun);
|
migrator.setDryRun(dryRun);
|
||||||
|
migrator.setNoColumnShrink(noColumnShrink);
|
||||||
addTasks(migrator, from, to);
|
addTasks(migrator, from, to);
|
||||||
|
|
||||||
migrator.migrate();
|
migrator.migrate();
|
||||||
|
@ -715,7 +715,8 @@ public class ExampleDataUploader extends BaseCommand {
|
|||||||
ourLog.info("About to upload {} examples in a transaction, {} remaining", subResourceList.size(), resources.size());
|
ourLog.info("About to upload {} examples in a transaction, {} remaining", subResourceList.size(), resources.size());
|
||||||
|
|
||||||
IVersionSpecificBundleFactory bundleFactory = ctx.newBundleFactory();
|
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();
|
IBaseResource subBundle = bundleFactory.getResourceBundle();
|
||||||
|
|
||||||
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(subBundle);
|
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(subBundle);
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
if you are using this file as a basis for your own project. -->
|
if you are using this file as a basis for your own project. -->
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-cli</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>4.1.0-SNAPSHOT</version>
|
<version>4.1.0-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>hapi-fhir-cli-jpaserver</artifactId>
|
<artifactId>hapi-fhir-cli-jpaserver</artifactId>
|
||||||
@ -131,6 +131,10 @@
|
|||||||
<artifactId>Saxon-HE</artifactId>
|
<artifactId>Saxon-HE</artifactId>
|
||||||
<groupId>net.sf.saxon</groupId>
|
<groupId>net.sf.saxon</groupId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>org.glassfish.jaxb</groupId>
|
||||||
|
<artifactId>jaxb-core</artifactId>
|
||||||
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@ -183,15 +187,6 @@
|
|||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</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 -->
|
<!-- This is to run the integration tests -->
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.config.BaseJavaConfigDstu2;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.config.BaseJavaConfigDstu3;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.config.BaseJavaConfigR4;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorR4;
|
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorR4;
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
package ca.uhn.fhir.jpa.demo;
|
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.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
|
@ -104,14 +104,6 @@
|
|||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
<configuration>
|
<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>
|
<dumpOnExit>true</dumpOnExit>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
@ -877,6 +877,16 @@ public class GenericOkHttpClientDstu2Test {
|
|||||||
public List<String> getFormatCommentsPost() {
|
public List<String> getFormatCommentsPost() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getUserData(String theName) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUserData(String theName, Object theValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
client
|
client
|
||||||
@ -1530,53 +1540,6 @@ public class GenericOkHttpClientDstu2Test {
|
|||||||
assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass());
|
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
|
@Test
|
||||||
public void testTransactionWithString() throws Exception {
|
public void testTransactionWithString() throws Exception {
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
||||||
|
@ -43,14 +43,6 @@
|
|||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
<configuration>
|
<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>
|
<dumpOnExit>true</dumpOnExit>
|
||||||
</configuration>
|
</configuration>
|
||||||
<executions>
|
<executions>
|
||||||
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
@ -22,11 +22,14 @@ package ca.uhn.fhir.rest.client.impl;
|
|||||||
|
|
||||||
import ca.uhn.fhir.context.*;
|
import ca.uhn.fhir.context.*;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
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.Include;
|
||||||
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
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.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.*;
|
||||||
@ -1761,7 +1764,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||||||
|
|
||||||
for (Include next : myInclude) {
|
for (Include next : myInclude) {
|
||||||
if (next.isRecurse()) {
|
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 {
|
} else {
|
||||||
addParam(params, Constants.PARAM_INCLUDE, next.getValue());
|
addParam(params, Constants.PARAM_INCLUDE, next.getValue());
|
||||||
}
|
}
|
||||||
@ -1769,7 +1776,11 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||||||
|
|
||||||
for (Include next : myRevInclude) {
|
for (Include next : myRevInclude) {
|
||||||
if (next.isRecurse()) {
|
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 {
|
} else {
|
||||||
addParam(params, Constants.PARAM_REVINCLUDE, next.getValue());
|
addParam(params, Constants.PARAM_REVINCLUDE, next.getValue());
|
||||||
}
|
}
|
||||||
@ -2038,7 +2049,35 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||||||
@Override
|
@Override
|
||||||
public ITransactionTyped<List<IBaseResource>> withResources(List<? extends IBaseResource> theResources) {
|
public ITransactionTyped<List<IBaseResource>> withResources(List<? extends IBaseResource> theResources) {
|
||||||
Validate.notNull(theResources, "theResources must not be null");
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||||||
private boolean myOmitResourceId = false;
|
private boolean myOmitResourceId = false;
|
||||||
private Map<String, List<String>> myParams;
|
private Map<String, List<String>> myParams;
|
||||||
private final IBaseResource myResource;
|
private final IBaseResource myResource;
|
||||||
private final List<? extends IBaseResource> myResources;
|
private final List<IBaseResource> myResources;
|
||||||
private final String myUrlPath;
|
private final String myUrlPath;
|
||||||
private IIdType myForceResourceId;
|
private IIdType myForceResourceId;
|
||||||
|
|
||||||
@ -70,7 +71,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||||||
super(theContext);
|
super(theContext);
|
||||||
myResource = null;
|
myResource = null;
|
||||||
myUrlPath = null;
|
myUrlPath = null;
|
||||||
myResources = theResources;
|
myResources = new ArrayList<>(theResources);
|
||||||
myContents = null;
|
myContents = null;
|
||||||
myBundleType = theBundleType;
|
myBundleType = theBundleType;
|
||||||
}
|
}
|
||||||
@ -172,11 +173,8 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||||||
parser.setOmitResourceId(myOmitResourceId);
|
parser.setOmitResourceId(myOmitResourceId);
|
||||||
if (myResources != null) {
|
if (myResources != null) {
|
||||||
IVersionSpecificBundleFactory bundleFactory = getContext().newBundleFactory();
|
IVersionSpecificBundleFactory bundleFactory = getContext().newBundleFactory();
|
||||||
bundleFactory.initializeBundleFromResourceList("", myResources, "", "", myResources.size(), myBundleType);
|
bundleFactory.addRootPropertiesToBundle(null, null, null, null, null, myResources.size(), myBundleType, null);
|
||||||
IBaseResource bundle = bundleFactory.getResourceBundle();
|
bundleFactory.addResourcesToBundle(myResources, myBundleType, null, null, null);
|
||||||
if (bundle != null) {
|
|
||||||
return parser.encodeResourceToString(bundle);
|
|
||||||
}
|
|
||||||
IBaseResource bundleRes = bundleFactory.getResourceBundle();
|
IBaseResource bundleRes = bundleFactory.getResourceBundle();
|
||||||
return parser.encodeResourceToString(bundleRes);
|
return parser.encodeResourceToString(bundleRes);
|
||||||
} else if (myContents != null) {
|
} else if (myContents != null) {
|
||||||
|
@ -23,6 +23,7 @@ import java.util.*;
|
|||||||
|
|
||||||
import ca.uhn.fhir.context.ConfigurationException;
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.*;
|
||||||
@ -64,23 +65,30 @@ class IncludeParameter extends BaseQueryParameter {
|
|||||||
|
|
||||||
if (myInstantiableCollectionType == null) {
|
if (myInstantiableCollectionType == null) {
|
||||||
if (mySpecType == Include.class) {
|
if (mySpecType == Include.class) {
|
||||||
convertAndAddIncludeToList(retVal, (Include) theObject);
|
convertAndAddIncludeToList(retVal, (Include) theObject, theContext);
|
||||||
} else {
|
} else {
|
||||||
retVal.add(QualifiedParamList.singleton(((String) theObject)));
|
retVal.add(QualifiedParamList.singleton(((String) theObject)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Collection<Include> val = (Collection<Include>) theObject;
|
Collection<Include> val = (Collection<Include>) theObject;
|
||||||
for (Include include : val) {
|
for (Include include : val) {
|
||||||
convertAndAddIncludeToList(retVal, include);
|
convertAndAddIncludeToList(retVal, include, theContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void convertAndAddIncludeToList(ArrayList<QualifiedParamList> retVal, Include include) {
|
private void convertAndAddIncludeToList(ArrayList<QualifiedParamList> theQualifiedParamLists, Include theInclude, FhirContext theContext) {
|
||||||
String qualifier = include.isRecurse() ? Constants.PARAM_INCLUDE_QUALIFIER_RECURSE : null;
|
String qualifier = null;
|
||||||
retVal.add(QualifiedParamList.singleton(qualifier, include.getValue()));
|
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() {
|
public Set<String> getAllow() {
|
||||||
|
109
hapi-fhir-docs/pom.xml
Normal file
109
hapi-fhir-docs/pom.xml
Normal 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>
|
92
hapi-fhir-docs/src/main/java/ChangelogMigrator.java
Normal file
92
hapi-fhir-docs/src/main/java/ChangelogMigrator.java
Normal 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
141
hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/Copier.java
Normal file
141
hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/Copier.java
Normal 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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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
|
@ -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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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
|
@ -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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
@ -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
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
@ -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
Loading…
x
Reference in New Issue
Block a user