Merging master into working branch to resolve conflicts.
# Conflicts: # src/changes/changes.xml
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
<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>
|
||||||
|
</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>
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*-
|
||||||
|
* #%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%
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This is just here to force a javadoc to be built in order to keep
|
||||||
|
* Maven Central happy
|
||||||
|
*/
|
||||||
|
public class DocsMarker {
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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,76 @@
|
||||||
|
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.initializeBundleFromResourceList(null, resources, "http://example.com/base", "http://example.com/base/Patient", 1, BundleTypeEnum.SEARCHSET);
|
||||||
|
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,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,24 @@
|
||||||
|
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%
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class NewInterceptors {
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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.ETagSupportEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class ServerETagExamples {
|
||||||
|
|
||||||
|
// START SNIPPET: disablingETags
|
||||||
|
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
|
||||||
|
public class RestfulServerWithLogging extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
// ... define your resource providers here ...
|
||||||
|
|
||||||
|
// ETag support is enabled by default
|
||||||
|
setETagSupport(ETagSupportEnum.ENABLED);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: disablingETags
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -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.model.dstu2.resource.OperationOutcome;
|
||||||
|
import ca.uhn.fhir.model.dstu2.valueset.IssueSeverityEnum;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
|
||||||
|
public abstract class ServerExceptionsExample implements IResourceProvider {
|
||||||
|
|
||||||
|
private boolean databaseIsDown;
|
||||||
|
|
||||||
|
//START SNIPPET: returnOO
|
||||||
|
@Read
|
||||||
|
public Patient read(@IdParam IdType theId) {
|
||||||
|
if (databaseIsDown) {
|
||||||
|
OperationOutcome oo = new OperationOutcome();
|
||||||
|
oo.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("Database is down");
|
||||||
|
throw new InternalErrorException("Database is down", oo);
|
||||||
|
}
|
||||||
|
|
||||||
|
Patient patient = new Patient(); // populate this
|
||||||
|
return patient;
|
||||||
|
}
|
||||||
|
//END SNIPPET: returnOO
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
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.valueset.IdentifierUseEnum;
|
||||||
|
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 ServerInterceptors {
|
||||||
|
|
||||||
|
@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(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
|
||||||
|
HumanNameDt name = patient.addName();
|
||||||
|
name.addFamily().setValue("Shmoe");
|
||||||
|
StringDt given = name.addGiven();
|
||||||
|
given.setValue("Joe");
|
||||||
|
ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#moreext", new StringDt("Hello"));
|
||||||
|
given.addUndeclaredExtension(ext2);
|
||||||
|
//END SNIPPET: resourceStringExtension
|
||||||
|
|
||||||
|
String output = FhirContext.forDstu2().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();
|
||||||
|
|
||||||
|
ExtensionDt parent = new ExtensionDt(false, "http://example.com#parent");
|
||||||
|
patient.addUndeclaredExtension(parent);
|
||||||
|
|
||||||
|
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,63 @@
|
||||||
|
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.api.ResourceMetadataKeyEnum;
|
||||||
|
import ca.uhn.fhir.model.api.Tag;
|
||||||
|
import ca.uhn.fhir.model.api.TagList;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import org.hl7.fhir.r4.model.InstantType;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ServerMetadataExamples {
|
||||||
|
|
||||||
|
// START SNIPPET: serverMethod
|
||||||
|
@Search
|
||||||
|
public List<Patient> getAllPatients() {
|
||||||
|
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||||
|
|
||||||
|
// Create a patient to return
|
||||||
|
Patient patient = new Patient();
|
||||||
|
retVal.add(patient);
|
||||||
|
patient.setId("Patient/123");
|
||||||
|
patient.addName().setFamily("Smith").addGiven("John");
|
||||||
|
|
||||||
|
// Add tags to the resource
|
||||||
|
patient.getMeta().addTag()
|
||||||
|
.setSystem("http://example.com/tags")
|
||||||
|
.setCode("tag1")
|
||||||
|
.setDisplay("Some tag");
|
||||||
|
patient.getMeta().addTag()
|
||||||
|
.setSystem("http://example.com/tags")
|
||||||
|
.setCode("tag2")
|
||||||
|
.setDisplay("Another tag");
|
||||||
|
|
||||||
|
// Set the lastUpdate date
|
||||||
|
patient.getMeta().setLastUpdatedElement(new InstantType("2014-07-12T11:22:27Z"));
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
// END SNIPPET: serverMethod
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
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.DateDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
|
import ca.uhn.fhir.rest.param.*;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.dstu3.model.Parameters;
|
||||||
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.ConceptMap;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
public class ServerOperations {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(ServerOperations.class);
|
||||||
|
|
||||||
|
|
||||||
|
//START SNIPPET: manualInputAndOutput
|
||||||
|
@Operation(name="$manualInputAndOutput", manualResponse=true, manualRequest=true)
|
||||||
|
public void manualInputAndOutput(HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws IOException {
|
||||||
|
String contentType = theServletRequest.getContentType();
|
||||||
|
byte[] bytes = IOUtils.toByteArray(theServletRequest.getInputStream());
|
||||||
|
|
||||||
|
ourLog.info("Received call with content type {} and {} bytes", contentType, bytes.length);
|
||||||
|
|
||||||
|
theServletResponse.setContentType(contentType);
|
||||||
|
theServletResponse.getOutputStream().write(bytes);
|
||||||
|
theServletResponse.getOutputStream().close();
|
||||||
|
}
|
||||||
|
//END SNIPPET: manualInputAndOutput
|
||||||
|
|
||||||
|
|
||||||
|
//START SNIPPET: searchParamBasic
|
||||||
|
@Operation(name="$find-matches", idempotent=true)
|
||||||
|
public Parameters findMatchesBasic(
|
||||||
|
@OperationParam(name="date") DateParam theDate,
|
||||||
|
@OperationParam(name="code") TokenParam theCode) {
|
||||||
|
|
||||||
|
Parameters retVal = new Parameters();
|
||||||
|
// Populate bundle with matching resources
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: searchParamBasic
|
||||||
|
|
||||||
|
//START SNIPPET: searchParamAdvanced
|
||||||
|
@Operation(name="$find-matches", idempotent=true)
|
||||||
|
public Parameters findMatchesAdvanced(
|
||||||
|
@OperationParam(name="dateRange") DateRangeParam theDate,
|
||||||
|
@OperationParam(name="name") List<StringParam> theName,
|
||||||
|
@OperationParam(name="code") TokenAndListParam theEnd) {
|
||||||
|
|
||||||
|
Parameters retVal = new Parameters();
|
||||||
|
// Populate bundle with matching resources
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: searchParamAdvanced
|
||||||
|
|
||||||
|
//START SNIPPET: patientTypeOperation
|
||||||
|
@Operation(name="$everything", idempotent=true)
|
||||||
|
public Bundle patientTypeOperation(
|
||||||
|
@OperationParam(name="start") DateDt theStart,
|
||||||
|
@OperationParam(name="end") DateDt theEnd) {
|
||||||
|
|
||||||
|
Bundle retVal = new Bundle();
|
||||||
|
// Populate bundle with matching resources
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: patientTypeOperation
|
||||||
|
|
||||||
|
//START SNIPPET: patientInstanceOperation
|
||||||
|
@Operation(name="$everything", idempotent=true)
|
||||||
|
public Bundle patientInstanceOperation(
|
||||||
|
@IdParam IdType thePatientId,
|
||||||
|
@OperationParam(name="start") DateDt theStart,
|
||||||
|
@OperationParam(name="end") DateDt theEnd) {
|
||||||
|
|
||||||
|
Bundle retVal = new Bundle();
|
||||||
|
// Populate bundle with matching resources
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: patientInstanceOperation
|
||||||
|
|
||||||
|
//START SNIPPET: serverOperation
|
||||||
|
@Operation(name="$closure")
|
||||||
|
public ConceptMap closureOperation(
|
||||||
|
@OperationParam(name="name") StringDt theStart,
|
||||||
|
@OperationParam(name="concept") List<Coding> theEnd,
|
||||||
|
@OperationParam(name="version") IdType theVersion) {
|
||||||
|
|
||||||
|
ConceptMap retVal = new ConceptMap();
|
||||||
|
// Populate bundle with matching resources
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
//END SNIPPET: serverOperation
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
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.RestfulServer;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.*;
|
||||||
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
|
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
|
||||||
|
import org.springframework.web.cors.CorsConfiguration;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.annotation.WebServlet;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class ServletExamples {
|
||||||
|
|
||||||
|
// START SNIPPET: loggingInterceptor
|
||||||
|
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
|
||||||
|
public class RestfulServerWithLogging extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
|
||||||
|
// ... define your resource providers here ...
|
||||||
|
|
||||||
|
// Now register the logging interceptor
|
||||||
|
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
|
||||||
|
registerInterceptor(loggingInterceptor);
|
||||||
|
|
||||||
|
// The SLF4j logger "test.accesslog" will receive the logging events
|
||||||
|
loggingInterceptor.setLoggerName("test.accesslog");
|
||||||
|
|
||||||
|
// This is the format for each line. A number of substitution variables may
|
||||||
|
// be used here. See the JavaDoc for LoggingInterceptor for information on
|
||||||
|
// what is available.
|
||||||
|
loggingInterceptor.setMessageFormat("Source[${remoteAddr}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: loggingInterceptor
|
||||||
|
|
||||||
|
// START SNIPPET: validatingInterceptor
|
||||||
|
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
|
||||||
|
public class ValidatingServerWithLogging extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
|
||||||
|
// ... define your resource providers here ...
|
||||||
|
|
||||||
|
// Create an interceptor to validate incoming requests
|
||||||
|
RequestValidatingInterceptor requestInterceptor = new RequestValidatingInterceptor();
|
||||||
|
|
||||||
|
// Register a validator module (you could also use SchemaBaseValidator and/or SchematronBaseValidator)
|
||||||
|
requestInterceptor.addValidatorModule(new FhirInstanceValidator());
|
||||||
|
|
||||||
|
requestInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||||
|
requestInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||||
|
requestInterceptor.setResponseHeaderValue("Validation on ${line}: ${message} ${severity}");
|
||||||
|
requestInterceptor.setResponseHeaderValueNoIssues("No issues detected");
|
||||||
|
|
||||||
|
// Now register the validating interceptor
|
||||||
|
registerInterceptor(requestInterceptor);
|
||||||
|
|
||||||
|
// Create an interceptor to validate responses
|
||||||
|
// This is configured in the same way as above
|
||||||
|
ResponseValidatingInterceptor responseInterceptor = new ResponseValidatingInterceptor();
|
||||||
|
responseInterceptor.addValidatorModule(new FhirInstanceValidator());
|
||||||
|
responseInterceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||||
|
responseInterceptor.setAddResponseHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||||
|
responseInterceptor.setResponseHeaderValue("Validation on ${line}: ${message} ${severity}");
|
||||||
|
responseInterceptor.setResponseHeaderValueNoIssues("No issues detected");
|
||||||
|
registerInterceptor(responseInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: validatingInterceptor
|
||||||
|
|
||||||
|
// START SNIPPET: exceptionInterceptor
|
||||||
|
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
|
||||||
|
public class RestfulServerWithExceptionHandling extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
|
||||||
|
// ... define your resource providers here ...
|
||||||
|
|
||||||
|
// Now register the interceptor
|
||||||
|
ExceptionHandlingInterceptor interceptor = new ExceptionHandlingInterceptor();
|
||||||
|
registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
// Return the stack trace to the client for the following exception types
|
||||||
|
interceptor.setReturnStackTracesForExceptionTypes(InternalErrorException.class, NullPointerException.class);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: exceptionInterceptor
|
||||||
|
|
||||||
|
// START SNIPPET: responseHighlighterInterceptor
|
||||||
|
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
|
||||||
|
public class RestfulServerWithResponseHighlighter extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
|
||||||
|
// ... define your resource providers here ...
|
||||||
|
|
||||||
|
// Now register the interceptor
|
||||||
|
ResponseHighlighterInterceptor interceptor = new ResponseHighlighterInterceptor();
|
||||||
|
registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: responseHighlighterInterceptor
|
||||||
|
|
||||||
|
// START SNIPPET: corsInterceptor
|
||||||
|
@WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server")
|
||||||
|
public class RestfulServerWithCors extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
|
||||||
|
// ... define your resource providers here ...
|
||||||
|
|
||||||
|
// Define your CORS configuration. This is an example
|
||||||
|
// showing a typical setup. You should customize this
|
||||||
|
// to your specific needs
|
||||||
|
CorsConfiguration config = new CorsConfiguration();
|
||||||
|
config.addAllowedHeader("x-fhir-starter");
|
||||||
|
config.addAllowedHeader("Origin");
|
||||||
|
config.addAllowedHeader("Accept");
|
||||||
|
config.addAllowedHeader("X-Requested-With");
|
||||||
|
config.addAllowedHeader("Content-Type");
|
||||||
|
|
||||||
|
config.addAllowedOrigin("*");
|
||||||
|
|
||||||
|
config.addExposedHeader("Location");
|
||||||
|
config.addExposedHeader("Content-Location");
|
||||||
|
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
|
||||||
|
|
||||||
|
// Create the interceptor and register it
|
||||||
|
CorsInterceptor interceptor = new CorsInterceptor(config);
|
||||||
|
registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: corsInterceptor
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
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.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TagsExamples {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new TagsExamples().getResourceTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void getResourceTags() {
|
||||||
|
// START SNIPPET: getResourceTags
|
||||||
|
IGenericClient client = FhirContext.forDstu2().newRestfulGenericClient("http://fhir.healthintersections.com.au/open");
|
||||||
|
Patient p = client.read(Patient.class, "1");
|
||||||
|
|
||||||
|
// Retrieve the list of tags from the resource metadata
|
||||||
|
List<Coding> tags = p.getMeta().getTag();
|
||||||
|
|
||||||
|
// tags may be empty if no tags were read in
|
||||||
|
if (tags.isEmpty()) {
|
||||||
|
System.out.println("No tags!");
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// You may iterate over all the tags
|
||||||
|
for (Coding next : tags) {
|
||||||
|
System.out.println(next.getSystem() + " - " + next.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// You may also get a specific tag (by system and code)
|
||||||
|
Coding tag = p.getMeta().getTag("http://hl7.org/fhir/tag", "http://foo");
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: getResourceTags
|
||||||
|
}
|
||||||
|
|
||||||
|
// START SNIPPET: serverMethod
|
||||||
|
@Search
|
||||||
|
public List<Patient> getAllPatients() {
|
||||||
|
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||||
|
|
||||||
|
// Create a patient to return
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("Patient/123");
|
||||||
|
patient.addName().setFamily("Smith").addGiven("John");
|
||||||
|
|
||||||
|
// Add some tags to the patient
|
||||||
|
patient.getMeta().addTag("http://example.com/tags", "tag2", "Some tag");
|
||||||
|
patient.getMeta().addTag("http://example.com/tags", "tag1", "Another tag");
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
// END SNIPPET: serverMethod
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,124 @@
|
||||||
|
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.validation.FhirValidator;
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.PrePopulatedValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
|
||||||
|
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
public class ValidateDirectory {
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateDirectory.class);
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// Load all profiles in this directory
|
||||||
|
File profileDirectory = new File("/tmp/directory/with/profiles");
|
||||||
|
|
||||||
|
// Validate resources in this directory
|
||||||
|
File resourceDirectory = new File("/tmp/directory/with/resources/to/validate");
|
||||||
|
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
IParser xmlParser = ctx.newXmlParser();
|
||||||
|
IParser jsonParser = ctx.newJsonParser();
|
||||||
|
|
||||||
|
Map<String, StructureDefinition> structureDefinitions = new HashMap<String, StructureDefinition>();
|
||||||
|
Map<String, CodeSystem> codeSystems = new HashMap<String, CodeSystem>();
|
||||||
|
Map<String, ValueSet> valueSets = new HashMap<String, ValueSet>();
|
||||||
|
|
||||||
|
// Load all profile files
|
||||||
|
for (File nextFile : profileDirectory.listFiles()) {
|
||||||
|
|
||||||
|
IBaseResource parsedRes = null;
|
||||||
|
if (nextFile.getAbsolutePath().toLowerCase().endsWith(".xml")) {
|
||||||
|
parsedRes = xmlParser.parseResource(new FileReader(nextFile));
|
||||||
|
} else if (nextFile.getAbsolutePath().toLowerCase().endsWith(".json")) {
|
||||||
|
parsedRes = jsonParser.parseResource(new FileReader(nextFile));
|
||||||
|
} else {
|
||||||
|
ourLog.info("Ignoring file: {}", nextFile.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedRes instanceof StructureDefinition) {
|
||||||
|
StructureDefinition res = (StructureDefinition) parsedRes;
|
||||||
|
if (isNotBlank(res.getUrl())) {
|
||||||
|
structureDefinitions.put(res.getUrl(), res);
|
||||||
|
}
|
||||||
|
} else if (parsedRes instanceof ValueSet) {
|
||||||
|
ValueSet res = (ValueSet) parsedRes;
|
||||||
|
if (isNotBlank(res.getUrl())) {
|
||||||
|
valueSets.put(res.getUrl(), res);
|
||||||
|
}
|
||||||
|
} else if (parsedRes instanceof CodeSystem) {
|
||||||
|
CodeSystem res = (CodeSystem) parsedRes;
|
||||||
|
if (isNotBlank(res.getUrl())) {
|
||||||
|
codeSystems.put(res.getUrl(), res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FhirInstanceValidator instanceValidator = new FhirInstanceValidator();
|
||||||
|
|
||||||
|
ValidationSupportChain validationSupportChain = new ValidationSupportChain();
|
||||||
|
validationSupportChain.addValidationSupport(new DefaultProfileValidationSupport());
|
||||||
|
validationSupportChain.addValidationSupport(new PrePopulatedValidationSupport(structureDefinitions, valueSets, codeSystems));
|
||||||
|
|
||||||
|
instanceValidator.setValidationSupport(validationSupportChain);
|
||||||
|
|
||||||
|
FhirValidator val = ctx.newValidator();
|
||||||
|
val.registerValidatorModule(instanceValidator);
|
||||||
|
|
||||||
|
// Loop through the files in the validation directory and validate each one
|
||||||
|
for (File nextFile : resourceDirectory.listFiles()) {
|
||||||
|
|
||||||
|
if (nextFile.getAbsolutePath().toLowerCase().endsWith(".xml")) {
|
||||||
|
ourLog.info("Going to validate: {}", nextFile.getName());
|
||||||
|
} else if (nextFile.getAbsolutePath().toLowerCase().endsWith(".json")) {
|
||||||
|
ourLog.info("Going to validate: {}", nextFile.getName());
|
||||||
|
} else {
|
||||||
|
ourLog.info("Ignoring file: {}", nextFile.getName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
String input = IOUtils.toString(new FileReader(nextFile));
|
||||||
|
ValidationResult result = val.validateWithResult(input);
|
||||||
|
IBaseOperationOutcome oo = result.toOperationOutcome();
|
||||||
|
ourLog.info("Result:\n{}", xmlParser.setPrettyPrint(true).encodeResourceToString(oo));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,351 @@
|
||||||
|
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.parser.StrictErrorHandler;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import ca.uhn.fhir.validation.*;
|
||||||
|
import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.io.filefilter.WildcardFileFilter;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
|
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||||
|
import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain;
|
||||||
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class ValidatorExamples {
|
||||||
|
|
||||||
|
public void validationIntro() {
|
||||||
|
// START SNIPPET: validationIntro
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
// Ask the context for a validator
|
||||||
|
FhirValidator validator = ctx.newValidator();
|
||||||
|
|
||||||
|
// Create some modules and register them
|
||||||
|
IValidatorModule module1 = new SchemaBaseValidator(ctx);
|
||||||
|
validator.registerValidatorModule(module1);
|
||||||
|
IValidatorModule module2 = new SchematronBaseValidator(ctx);
|
||||||
|
validator.registerValidatorModule(module2);
|
||||||
|
|
||||||
|
// Pass a resource in to be validated. The resource can
|
||||||
|
// be an IBaseResource instance, or can be a raw String
|
||||||
|
// containing a serialized resource as text.
|
||||||
|
Patient resource = new Patient();
|
||||||
|
ValidationResult result = validator.validateWithResult(resource);
|
||||||
|
String resourceText = "<Patient.....>";
|
||||||
|
ValidationResult result2 = validator.validateWithResult(resourceText);
|
||||||
|
|
||||||
|
// The result object now contains the validation results
|
||||||
|
for (SingleValidationMessage next : result.getMessages()) {
|
||||||
|
System.out.println(next.getLocationString() + " " + next.getMessage());
|
||||||
|
}
|
||||||
|
// END SNIPPET: validationIntro
|
||||||
|
}
|
||||||
|
|
||||||
|
// START SNIPPET: serverValidation
|
||||||
|
public class MyRestfulServer extends RestfulServer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() throws ServletException {
|
||||||
|
// ...Configure resource providers, etc...
|
||||||
|
|
||||||
|
// Create a context, set the error handler and instruct
|
||||||
|
// the server to use it
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
ctx.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
setFhirContext(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: serverValidation
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public void enableValidation() {
|
||||||
|
// START SNIPPET: clientValidation
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
ctx.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
|
||||||
|
// This client will have strict parser validation enabled
|
||||||
|
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu3");
|
||||||
|
// END SNIPPET: clientValidation
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void parserValidation() {
|
||||||
|
// START SNIPPET: parserValidation
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
// Create a parser and configure it to use the strict error handler
|
||||||
|
IParser parser = ctx.newXmlParser();
|
||||||
|
parser.setParserErrorHandler(new StrictErrorHandler());
|
||||||
|
|
||||||
|
// This example resource is invalid, as Patient.active can not repeat
|
||||||
|
String input = "<Patient><active value=\"true\"/><active value=\"false\"/></Patient>";
|
||||||
|
|
||||||
|
// The following will throw a DataFormatException because of the StrictErrorHandler
|
||||||
|
parser.parseResource(Patient.class, input);
|
||||||
|
// END SNIPPET: parserValidation
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateResource() {
|
||||||
|
// START SNIPPET: basicValidation
|
||||||
|
// As always, you need a context
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
// Create and populate a new patient object
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().setFamily("Smith").addGiven("John").addGiven("Q");
|
||||||
|
p.addIdentifier().setSystem("urn:foo:identifiers").setValue("12345");
|
||||||
|
p.addTelecom().setSystem(ContactPoint.ContactPointSystem.PHONE).setValue("416 123-4567");
|
||||||
|
|
||||||
|
// Request a validator and apply it
|
||||||
|
FhirValidator val = ctx.newValidator();
|
||||||
|
|
||||||
|
// Create the Schema/Schematron modules and register them. Note that
|
||||||
|
// you might want to consider keeping these modules around as long-term
|
||||||
|
// objects: they parse and then store schemas, which can be an expensive
|
||||||
|
// operation.
|
||||||
|
IValidatorModule module1 = new SchemaBaseValidator(ctx);
|
||||||
|
IValidatorModule module2 = new SchematronBaseValidator(ctx);
|
||||||
|
val.registerValidatorModule(module1);
|
||||||
|
val.registerValidatorModule(module2);
|
||||||
|
|
||||||
|
ValidationResult result = val.validateWithResult(p);
|
||||||
|
if (result.isSuccessful()) {
|
||||||
|
|
||||||
|
System.out.println("Validation passed");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// We failed validation!
|
||||||
|
System.out.println("Validation failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The result contains a list of "messages"
|
||||||
|
List<SingleValidationMessage> messages = result.getMessages();
|
||||||
|
for (SingleValidationMessage next : messages) {
|
||||||
|
System.out.println("Message:");
|
||||||
|
System.out.println(" * Location: " + next.getLocationString());
|
||||||
|
System.out.println(" * Severity: " + next.getSeverity());
|
||||||
|
System.out.println(" * Message : " + next.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can also convert the results into an OperationOutcome resource
|
||||||
|
OperationOutcome oo = (OperationOutcome) result.toOperationOutcome();
|
||||||
|
String results = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(oo);
|
||||||
|
System.out.println(results);
|
||||||
|
// END SNIPPET: basicValidation
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
instanceValidator();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void instanceValidator() throws Exception {
|
||||||
|
// START SNIPPET: instanceValidator
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
// Create a FhirInstanceValidator and register it to a validator
|
||||||
|
FhirValidator validator = ctx.newValidator();
|
||||||
|
FhirInstanceValidator instanceValidator = new FhirInstanceValidator();
|
||||||
|
validator.registerValidatorModule(instanceValidator);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you want, you can configure settings on the validator to adjust
|
||||||
|
* its behaviour during validation
|
||||||
|
*/
|
||||||
|
instanceValidator.setAnyExtensionsAllowed(true);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Let's create a resource to validate. This Observation has some fields
|
||||||
|
* populated, but it is missing Observation.status, which is mandatory.
|
||||||
|
*/
|
||||||
|
Observation obs = new Observation();
|
||||||
|
obs.getCode().addCoding().setSystem("http://loinc.org").setCode("12345-6");
|
||||||
|
obs.setValue(new StringType("This is a value"));
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
ValidationResult result = validator.validateWithResult(obs);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: You can also explicitly declare a profile to validate against
|
||||||
|
* using the block below.
|
||||||
|
*/
|
||||||
|
// ValidationResult result = validator.validateWithResult(obs, new ValidationOptions().addProfile("http://myprofile.com"));
|
||||||
|
|
||||||
|
// Do we have any errors or fatal errors?
|
||||||
|
System.out.println(result.isSuccessful()); // false
|
||||||
|
|
||||||
|
// Show the issues
|
||||||
|
for (SingleValidationMessage next : result.getMessages()) {
|
||||||
|
System.out.println(" Next issue " + next.getSeverity() + " - " + next.getLocationString() + " - " + next.getMessage());
|
||||||
|
}
|
||||||
|
// Prints:
|
||||||
|
// Next issue ERROR - /f:Observation - Element '/f:Observation.status': minimum required = 1, but only found 0
|
||||||
|
// Next issue WARNING - /f:Observation/f:code - Unable to validate code "12345-6" in code system "http://loinc.org"
|
||||||
|
|
||||||
|
// You can also convert the result into an operation outcome if you
|
||||||
|
// need to return one from a server
|
||||||
|
OperationOutcome oo = (OperationOutcome) result.toOperationOutcome();
|
||||||
|
// END SNIPPET: instanceValidator
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void instanceValidatorCustom() throws Exception {
|
||||||
|
// START SNIPPET: instanceValidatorCustom
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
|
||||||
|
// Create a FhirInstanceValidator and register it to a validator
|
||||||
|
FhirValidator validator = ctx.newValidator();
|
||||||
|
FhirInstanceValidator instanceValidator = new FhirInstanceValidator();
|
||||||
|
validator.registerValidatorModule(instanceValidator);
|
||||||
|
|
||||||
|
IValidationSupport valSupport = new IValidationSupport() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ValueSet.ConceptSetComponent theInclude) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LookupCodeResult lookupCode(FhirContext theContext, String theSystem, String theCode) {
|
||||||
|
// TODO: implement (or return null if your implementation does not support this function)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ValidationSupportChain strings multiple instances of IValidationSupport together. The
|
||||||
|
* code below is useful because it means that when the validator wants to load a
|
||||||
|
* StructureDefinition or a ValueSet, it will first use DefaultProfileValidationSupport,
|
||||||
|
* which loads the default HL7 versions. Any StructureDefinitions which are not found in
|
||||||
|
* the built-in set are delegated to your custom implementation.
|
||||||
|
*/
|
||||||
|
ValidationSupportChain support = new ValidationSupportChain(new DefaultProfileValidationSupport(), valSupport);
|
||||||
|
instanceValidator.setValidationSupport(support);
|
||||||
|
|
||||||
|
// END SNIPPET: instanceValidatorCustom
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static void validateFiles() throws Exception {
|
||||||
|
// START SNIPPET: validateFiles
|
||||||
|
FhirContext ctx = FhirContext.forR4();
|
||||||
|
|
||||||
|
// Create a validator and configure it
|
||||||
|
FhirValidator validator = ctx.newValidator();
|
||||||
|
validator.setValidateAgainstStandardSchema(true);
|
||||||
|
validator.setValidateAgainstStandardSchematron(true);
|
||||||
|
|
||||||
|
// Get a list of files in a given directory
|
||||||
|
String[] fileList = new File("/home/some/dir").list(new WildcardFileFilter("*.txt"));
|
||||||
|
for (String nextFile : fileList) {
|
||||||
|
|
||||||
|
// For each file, load the contents into a string
|
||||||
|
String nextFileContents = IOUtils.toString(new FileReader(nextFile));
|
||||||
|
|
||||||
|
// Parse that string (this example assumes JSON encoding)
|
||||||
|
IBaseResource resource = ctx.newJsonParser().parseResource(nextFileContents);
|
||||||
|
|
||||||
|
// Apply the validation. This will throw an exception on the first
|
||||||
|
// validation failure
|
||||||
|
ValidationResult result = validator.validateWithResult(resource);
|
||||||
|
if (result.isSuccessful() == false) {
|
||||||
|
throw new Exception("We failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// END SNIPPET: validateFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
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.validation.FhirValidator;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
|
||||||
|
|
||||||
|
public class ValidatorExamplesDstu3 {
|
||||||
|
|
||||||
|
public void validateProfileDstu3() {
|
||||||
|
// START SNIPPET: validateFiles
|
||||||
|
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
FhirValidator validator = ctx.newValidator();
|
||||||
|
|
||||||
|
// Typically if you are doing profile validation, you want to disable
|
||||||
|
// the schema/schematron validation since the profile will specify
|
||||||
|
// all the same rules (and more)
|
||||||
|
validator.setValidateAgainstStandardSchema(false);
|
||||||
|
validator.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
|
// FhirInstanceValidator is the validation module that handles
|
||||||
|
// profile validation. So, create an InstanceValidator module
|
||||||
|
// and register it to the validator.
|
||||||
|
FhirInstanceValidator instanceVal = new FhirInstanceValidator();
|
||||||
|
validator.registerValidatorModule(instanceVal);
|
||||||
|
|
||||||
|
// FhirInstanceValidator requires an instance of "IValidationSupport" in
|
||||||
|
// order to function. This module is used by the validator to actually obtain
|
||||||
|
// all of the resources it needs in order to perform validation. Specifically,
|
||||||
|
// the validator uses it to fetch StructureDefinitions, ValueSets, CodeSystems,
|
||||||
|
// etc, as well as to perform terminology validation.
|
||||||
|
//
|
||||||
|
// The implementation used here (ValidationSupportChain) is allows for
|
||||||
|
// multiple implementations to be used in a chain, where if a specific resource
|
||||||
|
// is needed the whole chain is tried and the first module which is actually
|
||||||
|
// able to answer is used. The first entry in the chain that we register is
|
||||||
|
// the DefaultProfileValidationSupport, which supplies the "built-in" FHIR
|
||||||
|
// StructureDefinitions and ValueSets
|
||||||
|
ValidationSupportChain validationSupportChain = new ValidationSupportChain();
|
||||||
|
validationSupportChain.addValidationSupport(new DefaultProfileValidationSupport());
|
||||||
|
instanceVal.setValidationSupport(validationSupportChain);
|
||||||
|
|
||||||
|
// END SNIPPET: validateFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package ca.uhn.hapi.fhir.docs.customtype;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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.api.annotation.Block;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
|
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.dstu3.model.BackboneElement;
|
||||||
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
|
||||||
|
//START SNIPPET: resource
|
||||||
|
@ResourceDef(name = "Patient")
|
||||||
|
public class CustomCompositeExtension extends Patient {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A custom extension
|
||||||
|
*/
|
||||||
|
@Child(name = "foo")
|
||||||
|
@Extension(url="http://acme.org/fooParent", definedLocally = false, isModifier = false)
|
||||||
|
protected FooParentExtension fooParentExtension;
|
||||||
|
|
||||||
|
public FooParentExtension getFooParentExtension() {
|
||||||
|
return fooParentExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return super.isEmpty() && ElementUtil.isEmpty(fooParentExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFooParentExtension(FooParentExtension theFooParentExtension) {
|
||||||
|
fooParentExtension = theFooParentExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Block
|
||||||
|
public static class FooParentExtension extends BackboneElement {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 4522090347756045145L;
|
||||||
|
|
||||||
|
@Child(name = "childA")
|
||||||
|
@Extension(url = "http://acme.org/fooChildA", definedLocally = false, isModifier = false)
|
||||||
|
private StringType myChildA;
|
||||||
|
|
||||||
|
@Child(name = "childB")
|
||||||
|
@Extension(url = "http://acme.org/fooChildB", definedLocally = false, isModifier = false)
|
||||||
|
private StringType myChildB;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FooParentExtension copy() {
|
||||||
|
FooParentExtension copy = new FooParentExtension();
|
||||||
|
copy.myChildA = myChildA;
|
||||||
|
copy.myChildB = myChildB;
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return super.isEmpty() && ElementUtil.isEmpty(myChildA, myChildB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringType getChildA() {
|
||||||
|
return myChildA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringType getChildB() {
|
||||||
|
return myChildB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildA(StringType theChildA) {
|
||||||
|
myChildA = theChildA;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildB(StringType theChildB) {
|
||||||
|
myChildB = theChildB;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//END SNIPPET: resource
|
|
@ -0,0 +1,83 @@
|
||||||
|
package ca.uhn.hapi.fhir.docs.customtype;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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: datatype
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||||
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateTimeType;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Type;
|
||||||
|
import org.hl7.fhir.instance.model.api.ICompositeType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an example of a custom datatype.
|
||||||
|
*
|
||||||
|
* This is an STU3 example so it extends Type and implements ICompositeType. For
|
||||||
|
* DSTU2 it would extend BaseIdentifiableElement and implement ICompositeDatatype.
|
||||||
|
*/
|
||||||
|
@DatatypeDef(name="CustomDatatype")
|
||||||
|
public class CustomDatatype extends Type implements ICompositeType {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Child(name = "date", order = 0, min = 1, max = 1)
|
||||||
|
private DateTimeType myDate;
|
||||||
|
|
||||||
|
@Child(name = "kittens", order = 1, min = 1, max = 1)
|
||||||
|
private StringType myKittens;
|
||||||
|
|
||||||
|
public DateTimeType getDate() {
|
||||||
|
if (myDate == null)
|
||||||
|
myDate = new DateTimeType();
|
||||||
|
return myDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringType getKittens() {
|
||||||
|
return myKittens;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return ElementUtil.isEmpty(myDate, myKittens);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomDatatype setDate(DateTimeType theValue) {
|
||||||
|
myDate = theValue;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CustomDatatype setKittens(StringType theKittens) {
|
||||||
|
myKittens = theKittens;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected CustomDatatype typedCopy() {
|
||||||
|
CustomDatatype retVal = new CustomDatatype();
|
||||||
|
super.copyValues(retVal);
|
||||||
|
retVal.myDate = myDate;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//END SNIPPET: datatype
|
|
@ -0,0 +1,106 @@
|
||||||
|
package ca.uhn.hapi.fhir.docs.customtype;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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: resource
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.Child;
|
||||||
|
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||||
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
|
import org.hl7.fhir.dstu3.model.DomainResource;
|
||||||
|
import org.hl7.fhir.dstu3.model.ResourceType;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
import org.hl7.fhir.dstu3.model.Type;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an example of a custom resource that also uses a custom
|
||||||
|
* datatype.
|
||||||
|
*
|
||||||
|
* Note that we are extensing DomainResource for an STU3
|
||||||
|
* resource. For DSTU2 it would be BaseResource.
|
||||||
|
*/
|
||||||
|
@ResourceDef(name = "CustomResource", profile = "http://hl7.org/fhir/profiles/custom-resource")
|
||||||
|
public class CustomResource extends DomainResource {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We give the resource a field with name "television". This field has no
|
||||||
|
* specific type, so it's a choice[x] field for any type.
|
||||||
|
*/
|
||||||
|
@Child(name="television", min=1, max=Child.MAX_UNLIMITED, order=0)
|
||||||
|
private List<Type> myTelevision;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We'll give it one more field called "dogs"
|
||||||
|
*/
|
||||||
|
@Child(name = "dogs", min=0, max=1, order=1)
|
||||||
|
private StringType myDogs;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CustomResource copy() {
|
||||||
|
CustomResource retVal = new CustomResource();
|
||||||
|
super.copyValues(retVal);
|
||||||
|
retVal.myTelevision = myTelevision;
|
||||||
|
retVal.myDogs = myDogs;
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Type> getTelevision() {
|
||||||
|
if (myTelevision == null) {
|
||||||
|
myTelevision = new ArrayList<Type>();
|
||||||
|
}
|
||||||
|
return myTelevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringType getDogs() {
|
||||||
|
return myDogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceType getResourceType() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FhirVersionEnum getStructureFhirVersionEnum() {
|
||||||
|
return FhirVersionEnum.DSTU3;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return ElementUtil.isEmpty(myTelevision, myDogs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTelevision(List<Type> theValue) {
|
||||||
|
this.myTelevision = theValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDogs(StringType theDogs) {
|
||||||
|
myDogs = theDogs;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// END SNIPPET: resource
|
|
@ -0,0 +1,63 @@
|
||||||
|
package ca.uhn.hapi.fhir.docs.customtype;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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.dstu3.model.DateTimeType;
|
||||||
|
import org.hl7.fhir.dstu3.model.DateType;
|
||||||
|
import org.hl7.fhir.dstu3.model.StringType;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public class CustomUsage {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
// START SNIPPET: usage
|
||||||
|
// Create a context. Note that we declare the custom types we'll be using
|
||||||
|
// on the context before actually using them
|
||||||
|
FhirContext ctx = FhirContext.forDstu3();
|
||||||
|
ctx.registerCustomType(CustomResource.class);
|
||||||
|
ctx.registerCustomType(CustomDatatype.class);
|
||||||
|
|
||||||
|
// Now let's create an instance of our custom resource type
|
||||||
|
// and populate it with some data
|
||||||
|
CustomResource res = new CustomResource();
|
||||||
|
|
||||||
|
// Add some values, including our custom datatype
|
||||||
|
DateType value0 = new DateType("2015-01-01");
|
||||||
|
res.getTelevision().add(value0);
|
||||||
|
|
||||||
|
CustomDatatype value1 = new CustomDatatype();
|
||||||
|
value1.setDate(new DateTimeType(new Date()));
|
||||||
|
value1.setKittens(new StringType("FOO"));
|
||||||
|
res.getTelevision().add(value1);
|
||||||
|
|
||||||
|
res.setDogs(new StringType("Some Dogs"));
|
||||||
|
|
||||||
|
// Now let's serialize our instance
|
||||||
|
String output = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res);
|
||||||
|
System.out.println(output);
|
||||||
|
// END SNIPPET: usage
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package ca.uhn.hapi.fhir.docs.interceptor;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%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.jpa.subscription.module.CanonicalSubscription;
|
||||||
|
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interceptor class
|
||||||
|
*/
|
||||||
|
@Interceptor
|
||||||
|
public class MyTestInterceptor {
|
||||||
|
|
||||||
|
@Hook(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY)
|
||||||
|
public boolean beforeRestHookDelivery(ResourceDeliveryMessage theDeliveryMessage, CanonicalSubscription theSubscription) {
|
||||||
|
|
||||||
|
String header = "Authorization: Bearer 1234567";
|
||||||
|
|
||||||
|
theSubscription.addHeader(header);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
type: add
|
||||||
|
title: feature
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Android Client
|
||||||
|
|
||||||
|
HAPI now has a specially built module for use on Android. Android developers may use this JAR to take advantage of the FHIR model classes, and the FHIR client (running a FHIR server on Android is not yet supported. Get in touch if this is something you are interested in working on!)
|
||||||
|
|
||||||
|
As of HAPI FHIR 3.1.0, the <code>hapi-fhir-android</code> module has been streamlined in order to reduce its footprint. Previous versions of the library included both an XML and a JSON parser but this has been streamlined to only include JSON support in order to reduce the number of libraries required in an Android build.
|
||||||
|
|
||||||
|
When using the HAPI FHIR Android client, the client will request only JSON responses (via the HTTP <code>Accept</code> header) and will not be able to communicate with FHIR servers that support only XML encoding (few, if any, servers actually exist with this limitation that we are aware of).
|
||||||
|
|
||||||
|
The Android client also uses the <code>hapi-fhir-client-okhttp</code> module, which is an HTTP client based on the OkHttp library. This library has proven to be more powerful and less likely to cause issues on Android than the Apache HttpClient implementation which is bundled by default.
|
||||||
|
|
||||||
|
Note that the Android JAR is still new and hasn't received as much testing as other parts of the library. We would greatly appreciate feedback, testing, etc. Also note that because mobile apps run on less powerful hardware compared to desktop and server applications, it is all the more important to keep a single instance of the `FhirContext` around for good performance, since this object is expensive to create. We are hoping to improve performance of the creation of this object in a future release. If you are an Android developer and would like to help with this, please get in touch!
|
||||||
|
|
||||||
|
## Get the Android JAR
|
||||||
|
|
||||||
|
To add the HAPI library via Gradle, you should add the [hapi-fhir-android](https://search.maven.org/search?q=g:ca.uhn.hapi.fhir%20AND%20a:hapi-fhir-android&core=gav) library to your Gradle file, as well as a structures library for the appropriate version of FHIR that you want to support, e.g. [hapi-fhir-structures-r4](https://search.maven.org/search?q=g:ca.uhn.hapi.fhir%20AND%20a:hapi-fhir-structures-r4&core=gav).
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
dependencies {
|
||||||
|
compile "ca.uhn.hapi.fhir:hapi-fhir-android:3.1.0-SNAPSHOT"
|
||||||
|
compile "ca.uhn.hapi.fhir:hapi-fhir-structures-dstu2:3.1.0-SNAPSHOT"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You will also need to manually exclude the Woodstox StAX library from inclusion, as this library uses namespaces which are prohibited on Android. You should also exclude:
|
||||||
|
|
||||||
|
```groovy
|
||||||
|
configurations {
|
||||||
|
all*.exclude group: 'org.codehaus.woodstox'
|
||||||
|
all*.exclude group: 'org.apache.httpcomponents'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To see a sample Gradle file for a working Android project using HAPI FHIR, see the [Android Integration Test](https://github.com/hapifhir/hapi-fhir-android-integration-test) project.
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
|
||||||
|
On mobile devices, performance problems are particularly noticeable. This is made worse by the fact that some economy Android devices have much slower performance than modern desktop computers. See the [Client Configuration Performance](/docs/client/rest_client_http_config.html#performance) page for some tips on how to improve client performance.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
The following is intended to be a selection of publicly available open source Android applications which use HAPI FHIR and might be useful as a reference.
|
||||||
|
|
||||||
|
If you know of others, please let us know!
|
||||||
|
|
||||||
|
* [https://github.com/hapifhir/hapi-fhir-android-integration-test](https://github.com/hapifhir/hapi-fhir-android-integration-test) - hapi-fhir-android Integration Test and Reference Application is our test platform for validating new releases. Created by Thomas Andersen.
|
||||||
|
* [https://github.com/SynappzMA/FHIR-Android](https://github.com/SynappzMA/FHIR-Android) - Nice FHIR DSTU2 search app
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Changelog
|
||||||
|
|
||||||
|
<th:block th:each="version : ${changelog.versions}">
|
||||||
|
|
||||||
|
# Smile CDR <th:block th:text="${version}"/> <th:block th:if="${changelog.changes.get(version).codename} != null" th:text="' (' + ${changelog.changes.get(version).codename} + ')'"/>
|
||||||
|
|
||||||
|
## Release Information
|
||||||
|
|
||||||
|
<th:block th:if="${changelog.changes.get(version).releaseDate} != null">
|
||||||
|
**Released:** <th:block th:text="${changelog.changes.get(version).releaseDate.getValueAsString()}"/>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:if="${changelog.changes.get(version).codename} != null">
|
||||||
|
**Codename:** <th:block th:text="'(' + ${changelog.changes.get(version).codename} + ')'"/>
|
||||||
|
</th:block>
|
||||||
|
|
||||||
|
<th:block th:if="${changelog.changes.get(version).upgrade} != null">
|
||||||
|
## Upgrade Instructions
|
||||||
|
|
||||||
|
[(${changelog.changes.get(version).upgrade})]
|
||||||
|
</th:block>
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<tr th:each="change : ${changelog.changes.get(version)}">
|
||||||
|
<td>
|
||||||
|
<a th:name="'change' + ${version} + '-' + ${change.id}"></a>
|
||||||
|
<span style="color: #129c49; font-size: 1.1em;" th:if="${change.type} == 'add'">
|
||||||
|
<i class="fa fa-plus"></i>
|
||||||
|
</span>
|
||||||
|
<span style="color: #129c49; font-size: 1.1em;" th:if="${change.type} == 'change'">
|
||||||
|
<i class="fa fa-cogs"></i>
|
||||||
|
</span>
|
||||||
|
<span style="color: #ee2324; font-size: 1.1em;" th:if="${change.type} == 'fix'">
|
||||||
|
<i class="fa fa-bug"></i>
|
||||||
|
</span>
|
||||||
|
<span style="color: #64c2d1; font-size: 1.1em;" th:if="${change.type} == 'perf'">
|
||||||
|
<i class="fa fa-rocket"></i>
|
||||||
|
</span>
|
||||||
|
<span style="color: #ee2324; font-size: 1.1em;" th:if="${change.type} == 'security'">
|
||||||
|
<i class="fa fa-shield-alt"></i>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<th:block th:utext="${change.title}"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</th:block>
|
|
@ -0,0 +1,21 @@
|
||||||
|
|
||||||
|
section.introduction.title=Welcome to HAPI FHIR
|
||||||
|
page.introduction.table_of_contents=Table of Contents
|
||||||
|
page.introduction.introduction=Introduction
|
||||||
|
|
||||||
|
section.model.title=Working With The FHIR Model
|
||||||
|
page.model.profiles_and_extensions=Profiles and Extensions
|
||||||
|
page.model.converter=Version Converters
|
||||||
|
page.model.custom_structures=Custom Structures
|
||||||
|
|
||||||
|
section.server.title=Server
|
||||||
|
page.server.cors=CORS
|
||||||
|
|
||||||
|
section.android.title=Android Support
|
||||||
|
page.android.client=Android Client
|
||||||
|
|
||||||
|
section.tools.title=Tools
|
||||||
|
page.tools.hapi_fhir_cli=Command Line Interface (CLI) Tool
|
||||||
|
|
||||||
|
section.appendix.title=Appendix
|
||||||
|
page.appendix.changelog=Changelog
|
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 73 KiB |
After Width: | Height: | Size: 9.5 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 2.0 KiB |
|
@ -0,0 +1,113 @@
|
||||||
|
|
||||||
|
# Introduction to HAPI FHIR
|
||||||
|
|
||||||
|
The HAPI FHIR library is an implementation of the [HL7 FHIR specification](http://hl7.org/fhir/) for Java. Explaining what FHIR is would be beyond the scope of this documentation, so if you have not previously worked with FHIR, the specification is a good place to start. This is often not actually the case when discussing messaging protocols, but in this case it is so: The FHIR specification is designed to be readable and implementable, and is filled with good information.
|
||||||
|
|
||||||
|
Part of the key to why FHIR is a good specification is the fact that its design is based on the design of other successful APIs (in particular, the FHIR designers often reference the Highrise API as a key influence in the design of the spec.)
|
||||||
|
|
||||||
|
HAPI FHIR is based on the same principle, but applied to the Java implementation: We have based the design of this API on the JAXB and JAX-WS APIs, which we consider to be very well thought-out, and very usable APIs. This does <b>not</b> mean that HAPI-FHIR actually uses these two APIs however, or that HAPI-FHIR is in any way compliant with JAXB ([JSR222](https://jcp.org/en/jsr/detail?id=222)) or JAX-WS ([JSR224](https://jcp.org/en/jsr/detail?id=222)), only that we have tried to emulate the easy-to-use, but flexible design of these specifications.
|
||||||
|
|
||||||
|
# Getting Started
|
||||||
|
|
||||||
|
To get started with HAPI FHIR, first download a copy and add it to your project. See the [Download Page](./download.html) for instructions.
|
||||||
|
|
||||||
|
## A Note on FHIR Versions
|
||||||
|
|
||||||
|
Before discussing HAPI itself, a quick word about FHIR versions. FHIR is not yet a finalized "1.0" standard. It is currently in the DSTU phase, which means that it is changing in subtle and non-subtle ways between releases. Before trying to use FHIR, you will need to determine which version of FHIR you want to support in your application. Typically this would be the latest version, but if you are looking to interact with an application which already exists, you will probably want to implement the same version implemented by that application.
|
||||||
|
|
||||||
|
See the [note on DSTU2 support](doc_dstu2.html) for more information on supporting multiple versions of FHIR.
|
||||||
|
|
||||||
|
## Introducing the FHIR Context
|
||||||
|
|
||||||
|
HAPI defines model classes for every resource type and datatype defined by the FHIR specification. For example, here is the [Patient](../apidocs/hapi-fhir-structures-r4/ca/uhn/fhir/model/r4/resource/Patient.html) resource specification. If you browse the JavaDoc you will see getters and setters for the various properties that make up a Patient resource.
|
||||||
|
|
||||||
|
We will come back to how to interact with these objects in a moment, but first we need to create a [FhirContext](../apidocs/hapi-fhir-base/ca/uhn/fhir/context/FhirContext.html). FhirContext is the starting point to using HAPI, and acts as a factory for most other parts of the API as well as a runtime cache of information that HAPI needs to operate. Users of the JAXB API may find this class to be similar in purpose to the [JAXBContext](http://docs.oracle.com/javaee/5/api/javax/xml/bind/JAXBContext.html) class from that API.
|
||||||
|
|
||||||
|
Creating a FhirContext is as simple as instantiating one. A FhirContext instance is specific to a given version of the FHIR specification, so it is recommended that you use one of the factory methods indicating the FHIR version you wish to support in your application, as shown in the following snippet:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/FhirContextIntro.java|creatingContext}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Parsing a resource from a String
|
||||||
|
|
||||||
|
This [Parser instance](../apidocs/hapi-fhir-base/ca/uhn/fhir/parser/IParser.html) can then be used to parse messages. Note that you may use the context to create as many parsers are you want.
|
||||||
|
|
||||||
|
**Performance tip:** The FhirContext is an expensive object to create, so you should try to create it once and keep it around during the life of your application. Parsers, on the other hand, are very lightweight and do not need to be reused.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/FhirContextIntro.java|parseMsg}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encoding a Resource to a String
|
||||||
|
|
||||||
|
The parser can also be used to encode a resource (which you can populate with your own values) just as easily.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/FhirContextIntro.java|encodeMsg}}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!--/* ****** The section below on fluent references the snippet above ***** */-->
|
||||||
|
<!--/* ****** so be careful about any reordering! ***** */-->
|
||||||
|
|
||||||
|
This code gives the following output:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Patient xmlns="http://hl7.org/fhir">
|
||||||
|
<identifier>
|
||||||
|
<system value="http://example.com/fictitious-mrns"/>
|
||||||
|
<value value="MRN001"/>
|
||||||
|
</identifier>
|
||||||
|
<name>
|
||||||
|
<use value="official"/>
|
||||||
|
<family value="Tester"/>
|
||||||
|
<given value="John"/>
|
||||||
|
<given value="Q"/>
|
||||||
|
</name>
|
||||||
|
</Patient>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fluent Programming
|
||||||
|
|
||||||
|
Much of the HAPI FHIR API is designed using a fluent style, where method calls can be chained in a natural way. This leads to tighter and easier-to-read code.
|
||||||
|
|
||||||
|
|
||||||
|
The following snippet is functionally identical to the example above:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/FhirContextIntro.java|encodeMsgFluent}}
|
||||||
|
```
|
||||||
|
|
||||||
|
# JSON Encoding
|
||||||
|
|
||||||
|
JSON parsing/encoding is also supported.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/FhirContextIntro.java|encodeMsgJson}}
|
||||||
|
```
|
||||||
|
|
||||||
|
This code gives the following output:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"resourceType":"Patient",
|
||||||
|
"identifier":[
|
||||||
|
{
|
||||||
|
"system":"http://example.com/fictitious-mrns",
|
||||||
|
"value":"MRN001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name":[
|
||||||
|
{
|
||||||
|
"use":"official",
|
||||||
|
"family":[
|
||||||
|
"Tester"
|
||||||
|
],
|
||||||
|
"given":[
|
||||||
|
"John",
|
||||||
|
"Q"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,26 @@
|
||||||
|
# Table of Contents
|
||||||
|
|
||||||
|
Welcome to HAPI FHIR!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<table class="helpTocTable">
|
||||||
|
<th:block th:each="chapter : ${chapters}">
|
||||||
|
<tr class="helpTocChapter">
|
||||||
|
<td th:text="${chapter.sectionNumber} + '.0.0'" class="helpTocChapter"></td>
|
||||||
|
<td th:text="${chapter.title}" class="helpTocChapter"></td>
|
||||||
|
</tr>
|
||||||
|
<th:block th:each="page : ${chapter.pages}">
|
||||||
|
<tr>
|
||||||
|
<td th:text="${page.sectionNumber} + '.0'"></td>
|
||||||
|
<td class="helpTocPage"><a th:href="${page.link}" th:text="${page.title}"></a></td>
|
||||||
|
</tr>
|
||||||
|
<th:block th:each="section : ${page.sections}">
|
||||||
|
<tr>
|
||||||
|
<td th:text="${section.sectionNumber}"></td>
|
||||||
|
<td class="helpTocSection"><a th:href="${page.link} + ${section.anchor}" th:text="${section.title}"></a></td>
|
||||||
|
</tr>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
|
</table>
|
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
# HL7 FHIR Converter
|
||||||
|
|
||||||
|
Beginning in HAPI FHIR 2.3, a new module called `hapi-fhir-converter` has been added to the project. This is an <b>experimental feature</b> so use it with caution!
|
||||||
|
|
||||||
|
This feature allows automated conversion from earlier versions of the FHIR structures to a later version.
|
||||||
|
|
||||||
|
The following page shows some basic examples. Please get in touch if you are able to contribute better examples!
|
||||||
|
|
||||||
|
## Importing the Module
|
||||||
|
|
||||||
|
To use the `hapi-fhir-converter` module, import the following dependency into your project pom.xml (or equivalent)
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-converter</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Converting from DSTU2 to DSTU3
|
||||||
|
|
||||||
|
The following example shows a conversion from a `hapi-fhir-structures-hl7org-dstu2` structure to a `hapi-fhir-structures-dstu3` structure.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ConverterExamples.java|1020}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Converting from DSTU2.1 to DSTU3
|
||||||
|
|
||||||
|
The following example shows a conversion from a `hapi-fhir-structures-dstu2.1` structure to a `hapi-fhir-structures-dstu3` structure.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ConverterExamples.java|1420}}
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Custom Structures
|
||||||
|
|
||||||
|
Typically, when working with FHIR the right way to provide your own extensions is to work with existing resource types and simply add your own extensions and/or constrain out fields you don't need.
|
||||||
|
|
||||||
|
This process is described on the [Profiles & Extensions](./profiles_and_extensions.html) page.
|
||||||
|
|
||||||
|
There are situations however when you might want to create an entirely custom resource type. This feature should be used only if there is no other option, since it means you are creating a resource type that will not be interoperable with other FHIR implementations.
|
||||||
|
|
||||||
|
<p class="doc_info_bubble">
|
||||||
|
This is an advanced features and isn't needed for most uses of HAPI-FHIR. Feel free to skip this page.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
# Custom Resource Structure
|
||||||
|
|
||||||
|
The following example shows a custom resource structure class:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/customtype/CustomResource.java|resource}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Datatype Structure
|
||||||
|
|
||||||
|
The following example shows a custom datatype structure class:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/customtype/CustomDatatype.java|datatype}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using the Custom Structure
|
||||||
|
|
||||||
|
And now let's try the custom structure out:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/customtype/CustomUsage.java|usage}}
|
||||||
|
```
|
||||||
|
|
||||||
|
This produces the following output (some spacing has been added for readability):
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<CustomResource xmlns="http://hl7.org/fhir">
|
||||||
|
<meta>
|
||||||
|
<profile value="http://hl7.org/fhir/profiles/custom-resource"/>
|
||||||
|
</meta>
|
||||||
|
|
||||||
|
<televisionDate value="2015-01-01"/>
|
||||||
|
<televisionCustomDatatype>
|
||||||
|
<date value="2016-05-22T08:30:36-04:00"/>
|
||||||
|
<kittens value="FOO"/>
|
||||||
|
</televisionCustomDatatype>
|
||||||
|
|
||||||
|
<dogs value="Some Dogs"/>
|
||||||
|
|
||||||
|
</CustomResource>
|
||||||
|
```
|
|
@ -0,0 +1,174 @@
|
||||||
|
# Profiles and Extensions
|
||||||
|
|
||||||
|
This page describes how to extend and constrain the FHIR data model for your own purposes.
|
||||||
|
|
||||||
|
# Extensions
|
||||||
|
|
||||||
|
<p class="doc_info_bubble">
|
||||||
|
Note on FHIR Versions: Because of the differences in the way the structures work between DSTU2 and DSTU3, we have provided two versions of many of the examples on this page. See the <a href="/hapi-fhir/download.html">download page</a> for more information on FHIR versions.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Extensions are a key part of the FHIR specification, providing a standardized way of placing additional data in a resource.
|
||||||
|
|
||||||
|
The simplest way to interact with extensions (i.e. to add them to resources you are creating, or to read them from resources you are consuming) is to treat them as "undeclared extensions". Undeclared extensions can be added to any of the built in FHIR resource types that come with HAPI-FHIR.
|
||||||
|
|
||||||
|
### DSTU2
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu2.java|resourceExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DSTU3 and Later
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|resourceExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Undeclared extensions can also be added to datatypes (composite or primitive).
|
||||||
|
|
||||||
|
### DSTU2
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu2.java|resourceStringExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DSTU3 and Later
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|resourceStringExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sub-Extensions
|
||||||
|
|
||||||
|
Extensions may also have child extensions as their content, instead of a datatype. This is done by adding a child undeclared extension to the parent extension.
|
||||||
|
|
||||||
|
### DSTU2
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu2.java|subExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DSTU3 and Later
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|subExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Retrieving Extension Values
|
||||||
|
|
||||||
|
HAPI provides a few ways of accessing extension values in resources which are received from other sources (i.e. downloaded by a client).
|
||||||
|
|
||||||
|
### DSTU2
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu2.java|parseExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DSTU3 and Later
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|parseExtension}}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Custom Resource Types
|
||||||
|
|
||||||
|
The most elegant way of adding extensions to a resource is through the use of custom fields. The following example shows a custom type which extends the FHIR Patient resource definition through two extensions.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/MyPatient.java|patientDef}}
|
||||||
|
```
|
||||||
|
|
||||||
|
Using this custom type is as simple as instantiating the type and working with the new fields.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/MyPatientUse.java|patientUse}}
|
||||||
|
```
|
||||||
|
|
||||||
|
This example produces the following output:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Patient xmlns="http://hl7.org/fhir">
|
||||||
|
<modifierExtension url="http://example.com/dontuse#importantDates">
|
||||||
|
<valueDateTime value="2010-01-02"/>
|
||||||
|
</modifierExtension>
|
||||||
|
<modifierExtension url="http://example.com/dontuse#importantDates">
|
||||||
|
<valueDateTime value="2014-01-26T11:11:11"/>
|
||||||
|
</modifierExtension>
|
||||||
|
<extension url="http://example.com/dontuse#petname">
|
||||||
|
<valueString value="Fido"/>
|
||||||
|
</extension>
|
||||||
|
<name>
|
||||||
|
<family value="Smith"/>
|
||||||
|
<given value="John"/>
|
||||||
|
<given value="Quincy"/>
|
||||||
|
<suffix value="Jr"/>
|
||||||
|
</name>
|
||||||
|
</Patient>
|
||||||
|
```
|
||||||
|
|
||||||
|
Parsing messages using your new custom type is equally simple. These types can also be used as method return types in clients and servers.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/MyPatientUse.java|patientParse}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Custom Types in a Client
|
||||||
|
|
||||||
|
If you are using a client and wish to use a specific custom structure, you may simply use the custom structure as you would a build in HAPI type.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|customTypeClientSimple}}
|
||||||
|
```
|
||||||
|
|
||||||
|
You may also explicitly use custom types in searches and other operations which return resources.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|customTypeClientSearch}}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also explicitly declare a preferred response resource custom type. This is useful for some operations that do not otherwise declare their resource types in the method signature.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|customTypeClientSearch2}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using Multiple Custom Types in a Client
|
||||||
|
|
||||||
|
Sometimes you may not know in advance exactly which type you will be receiving. For example, there are Patient resources which conform to several different profiles on a server and you aren't sure which profile you will get back for a specific read, you can declare the "primary" type for a given profile.
|
||||||
|
|
||||||
|
This is declared at the FhirContext level, and will apply to any clients created from this context (including clients created before the default was set).
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|customTypeClientDeclared}}
|
||||||
|
```
|
||||||
|
## Using Custom Types in a Server
|
||||||
|
|
||||||
|
If you are using a client and wish to use a specific custom structure, you may simply use the custom structure as you would a build in HAPI type.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExtensionsDstu3.java|customTypeClientSimple}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Custom Type Examples: Composite Extensions
|
||||||
|
|
||||||
|
The following example shows a resource containing a composite extension.
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/customtype/CustomCompositeExtension.java|resource}}
|
||||||
|
```
|
||||||
|
|
||||||
|
This could be used to create a resource such as the following:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<Patient xmlns="http://hl7.org/fhir">
|
||||||
|
<id value="123"/>
|
||||||
|
<extension url="http://acme.org/fooParent">
|
||||||
|
<extension url="http://acme.org/fooChildA">
|
||||||
|
<valueString value="ValueA"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="http://acme.org/fooChildB">
|
||||||
|
<valueString value="ValueB"/>
|
||||||
|
</extension>
|
||||||
|
</extension>
|
||||||
|
</Patient>
|
||||||
|
```
|
|
@ -0,0 +1,94 @@
|
||||||
|
# CORS
|
||||||
|
|
||||||
|
<p class="doc_info_bubble">
|
||||||
|
Note that in previous revisions of this document we recommended using the <a href="https://github.com/ebay/cors-filter">eBay CORS Filter</a>, but as of 2016 the eBay filter is no longer being maintained and contains known bugs. We now recommend against using this filter.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
If you are intending to support JavaScript clients in your server application, you will generally need to enable Cross Origin Resource Sharing (CORS). There are a number of ways of supporting this, so two are shown here:
|
||||||
|
|
||||||
|
* An approach using a HAPI FHIR Server Interceptor (Requires SpringFramework)
|
||||||
|
* An approach using a servlet Filter (Container Specific)
|
||||||
|
|
||||||
|
## HAPI FHIR Server Interceptor
|
||||||
|
|
||||||
|
The HAPI FHIR server framework includes an interceptor that can be used to provide CORS functionality on your server. This mechanism is nice because it relies purely on Java configuration (no messing around with web.xml files). HAPI's interceptor is a thin wrapper around Spring Framework's CorsProcessor class, so it requires Spring to be present on your classpath.
|
||||||
|
|
||||||
|
Spring is generally unlikely to conflict with other libraries so it is usually safe to add it to your classpath, but it is a fairly large library so if size is a concern you might opt to use a filter instead.
|
||||||
|
|
||||||
|
The following steps outline how to enable HAPI's CorsInterceptor:
|
||||||
|
|
||||||
|
Add the following dependency to your POM. Note the exclusion of commons-logging, as we are using SLF4j without commons-logging in most of our examples. If your application uses commons-logging you don't need to exclude that dependency.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-web</artifactId>
|
||||||
|
<version>${spring_version}</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
In your server's initialization method, create and register a CorsInterceptor:
|
||||||
|
|
||||||
|
```java
|
||||||
|
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ServletExamples.java|corsInterceptor}}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add the Dependency
|
||||||
|
|
||||||
|
The following examples show how to use the Apache Tomcat CorsFilter to enable CORS support. The filter being used (`org.apache.catalina.filters.CorsFilter`) is bundled with Apache Tomcat so if you are deploying to that server you can use the filter.
|
||||||
|
|
||||||
|
Other containers have similar filters you can use, so consult the documentation for the given container you are using for more information. (If you have an example for how to configure a different CORS filter, please send it our way! Examples are always useful!)
|
||||||
|
|
||||||
|
In your web.xml file (within the WEB-INF directory in your WAR file), the following filter definition adds the CORS filter, including support for the X-FHIR-Starter header defined by SMART Platforms.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<filter>
|
||||||
|
<filter-name>CORS Filter</filter-name>
|
||||||
|
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
|
||||||
|
<param-name>cors.allowed.origins</param-name>
|
||||||
|
<param-value>*</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
|
||||||
|
<param-name>cors.allowed.methods</param-name>
|
||||||
|
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of allowed headers when making a non simple CORS request.</description>
|
||||||
|
<param-name>cors.allowed.headers</param-name>
|
||||||
|
<param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
|
||||||
|
<param-name>cors.exposed.headers</param-name>
|
||||||
|
<param-value>Location,Content-Location</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A flag that suggests if CORS is supported with cookies</description>
|
||||||
|
<param-name>cors.support.credentials</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A flag to control logging</description>
|
||||||
|
<param-name>cors.logging.enabled</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
|
||||||
|
<param-name>cors.preflight.maxage</param-name>
|
||||||
|
<param-value>300</param-value>
|
||||||
|
</init-param>
|
||||||
|
</filter>
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>CORS Filter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>]]></source>
|
||||||
|
```
|
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
# Command Line Tool for HAPI FHIR
|
||||||
|
|
||||||
|
**hapi-fhir-cli** is the HAPI FHIR Command Line tool. It features a number of HAPI's built-in features as easy to use command line options.
|
||||||
|
|
||||||
|
## Download and Installation
|
||||||
|
|
||||||
|
You can get the tool by downloading it from our [GitHub Releases](https://github.com/jamesagnew/hapi-fhir/releases) page (look for the archive named `hapi-fhir-[version]-cli.tar.bz2` on OSX/Linux or `hapi-fhir-[version]-cli.zip` on Windows).
|
||||||
|
|
||||||
|
When you have downloaded the archive (either ZIP or tar.bz2), expand it into a directory where you will keep it, and add this directory to your path.
|
||||||
|
|
||||||
|
You can now try the tool out by executing the following command: `hapi-fhir-cli`
|
||||||
|
|
||||||
|
This command should show a help screen, as shown in the screeenshot below.
|
||||||
|
|
||||||
|
<img src="/hapi-fhir/docs/images/hapi-fhir-cli.png" alt="Basic screen shot" style="margin-left: 40px;"/>
|
||||||
|
|
||||||
|
## Download and Installation - Mac/OSX
|
||||||
|
|
||||||
|
hapi-fhir-cli is available as a <a href="https://brew.sh/">Homebrew</a> package for Mac. It can be installed using the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
brew install hapi-fhir-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
The tool should work correctly on any system that has Java 8 (or newer) installed. If it is not working correctly, first try the following command to test if Java is installed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
java -version
|
||||||
|
```
|
||||||
|
|
||||||
|
If this command does not produce output similar to the following, you should install/reinstall Java.
|
||||||
|
|
||||||
|
```
|
||||||
|
java version "1.8.0_60"
|
||||||
|
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
|
||||||
|
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
|
||||||
|
```
|
||||||
|
If this does not help, please post a question on our [Google Group](https://groups.google.com/d/forum/hapi-fhir).
|
||||||
|
|
||||||
|
# Server (run-server)
|
||||||
|
|
||||||
|
The CLI tool can be used to start a local, fully functional FHIR server which you can use for testing. To start this server, simply issue the command <code>hapi-fhir-cli run-server</code> as shown in the example below:
|
||||||
|
|
||||||
|
<img src="/hapi-fhir/docs/images/hapi-fhir-cli-run-server.png" alt="Run Server" style="margin-left: 40px;"/>
|
||||||
|
|
||||||
|
Once the server has started, you can access the testing webpage by pointing your browser at <a href="http://localhost:8080/">http://localhost:8080/</a>. The FHIR server base URL will be <a href="http://localhost:8080/baseDstu2/">http://localhost:8080/baseDstu2/</a>.
|
||||||
|
|
||||||
|
Note that by default this server will not be populated with any resources at all. You can easily populate it with the FHIR example resources by <b>leaving it running</b> and opening a second terminal window, then using the <code>hapi-fhir-cli upload-examples</code> command (see the section below).
|
||||||
|
|
||||||
|
The server uses a local Derby database instance for storage. You may want to execute this command in an empty directory, which you can clear if you want to reset the server.
|
||||||
|
|
||||||
|
# Upload Example Resources (upload-examples)
|
||||||
|
|
||||||
|
The <b>upload-examples</b> command downloads the complete set of FHIR example resources from the HL7 website, and uploads them to a server of your choice. This can be useful to populate a server with test data.
|
||||||
|
|
||||||
|
To execute this command, uploading test resources to a local CLI server, issue the following: `hapi-fhir-cli upload-examples -t http://localhost:8080/baseDstu2`
|
||||||
|
|
||||||
|
Note that this command may take a surprisingly long time to complete because of the large number of examples.
|
||||||
|
|
||||||
|
# Upload Terminology
|
||||||
|
|
||||||
|
The HAPI FHIR JPA server has a terminology server, and has the ability to be populated with "external" code systems. These code systems are systems that contain large numbers of codes, so the codes are not stored directly inside the resource body.
|
||||||
|
|
||||||
|
HAPI has methods for uploading several popular code systems into its tables using the distribution files produced by the respective code systems. This is done using the <code>upload-terminology</code> command. The following examples show how to do this for several popular code systems.
|
||||||
|
|
||||||
|
Note that the path and exact filename of the terminology files will likely need to be adjusted for your local disk structure.
|
||||||
|
|
||||||
|
### SNOMED CT
|
||||||
|
|
||||||
|
```
|
||||||
|
./hapi-fhir-cli upload-terminology -d Downloads/SnomedCT_RF2Release_INT_20160131.zip -f dstu3 -t http://localhost:8080/baseDstu3 -u http://snomed.info/sct
|
||||||
|
```
|
||||||
|
|
||||||
|
### LOINC
|
||||||
|
|
||||||
|
```
|
||||||
|
./hapi-fhir-cli upload-terminology -d Downloads/LOINC_2.54_MULTI-AXIAL_HIERARCHY.zip -d Downloads/LOINC_2.54_Text.zip -f dstu3 -t http://localhost:8080/baseDstu3 -u http://loinc.org
|
||||||
|
```
|
||||||
|
|
||||||
|
# Migrate Database
|
||||||
|
|
||||||
|
The `migrate-database` command may be used to Migrate a database schema when upgrading a <a href="./doc_jpa.html">HAPI FHIR JPA</a> project from one version of HAPI FHIR to another version.
|
||||||
|
|
||||||
|
See <a href="./doc_jpa.html#upgrading">Upgrading HAPI FHIR JPA</a> for information on how to use this command.
|
|
@ -50,26 +50,31 @@
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -33,7 +33,21 @@
|
||||||
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu2</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>
|
<dependency>
|
||||||
<groupId>javax.ws.rs</groupId>
|
<groupId>javax.ws.rs</groupId>
|
||||||
<artifactId>javax.ws.rs-api</artifactId>
|
<artifactId>javax.ws.rs-api</artifactId>
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.migrate.tasks.api.BaseMigrationTasks;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.util.VersionEnum;
|
import ca.uhn.fhir.util.VersionEnum;
|
||||||
|
|
||||||
|
import javax.persistence.Index;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -60,7 +61,46 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
protected void init410() {
|
protected void init410() {
|
||||||
Builder version = forVersion(VersionEnum.V4_1_0);
|
Builder version = forVersion(VersionEnum.V4_1_0);
|
||||||
|
|
||||||
version.startSectionWithMessage("Processing table: HFJ_RES_VER_PROV");
|
// HFJ_SEARCH
|
||||||
|
version.onTable("HFJ_SEARCH").addColumn("EXPIRY_OR_NULL").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
|
||||||
|
|
||||||
|
// HFJ_BLK_EXPORT_JOB
|
||||||
|
version.addIdGenerator("SEQ_BLKEXJOB_PID");
|
||||||
|
Builder.BuilderAddTableByColumns bulkExportJob = version.addTableByColumns("HFJ_BLK_EXPORT_JOB", "PID");
|
||||||
|
bulkExportJob.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
bulkExportJob.addColumn("JOB_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 36);
|
||||||
|
bulkExportJob.addColumn("JOB_STATUS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 10);
|
||||||
|
bulkExportJob.addColumn("CREATED_TIME").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
|
||||||
|
bulkExportJob.addColumn("STATUS_TIME").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
|
||||||
|
bulkExportJob.addColumn("EXP_TIME").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
|
||||||
|
bulkExportJob.addColumn("REQUEST").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 500);
|
||||||
|
bulkExportJob.addColumn("OPTLOCK").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
|
||||||
|
bulkExportJob.addColumn("EXP_SINCE").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP);
|
||||||
|
bulkExportJob.addColumn("STATUS_MESSAGE").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 500);
|
||||||
|
bulkExportJob.addIndex("IDX_BLKEX_EXPTIME").unique(false).withColumns("EXP_TIME");
|
||||||
|
bulkExportJob.addIndex("IDX_BLKEX_JOB_ID").unique(true).withColumns("JOB_ID");
|
||||||
|
|
||||||
|
|
||||||
|
// HFJ_BLK_EXPORT_COLLECTION
|
||||||
|
version.addIdGenerator("SEQ_BLKEXCOL_PID");
|
||||||
|
Builder.BuilderAddTableByColumns bulkExportCollection = version.addTableByColumns("HFJ_BLK_EXPORT_COLLECTION", "PID");
|
||||||
|
bulkExportCollection.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
bulkExportCollection.addColumn("JOB_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
bulkExportCollection.addForeignKey("FK_BLKEXCOL_JOB").toColumn("JOB_PID").references("HFJ_BLK_EXPORT_JOB", "PID");
|
||||||
|
bulkExportCollection.addColumn("RES_TYPE").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 35);
|
||||||
|
bulkExportCollection.addColumn("TYPE_FILTER").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 1000);
|
||||||
|
bulkExportCollection.addColumn("OPTLOCK").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
|
||||||
|
|
||||||
|
// HFJ_BLK_EXPORT_COLFILE
|
||||||
|
version.addIdGenerator("SEQ_BLKEXCOLFILE_PID");
|
||||||
|
Builder.BuilderAddTableByColumns bulkExportCollectionFile = version.addTableByColumns("HFJ_BLK_EXPORT_COLFILE", "PID");
|
||||||
|
bulkExportCollectionFile.addColumn("PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
bulkExportCollectionFile.addColumn("COLLECTION_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
bulkExportCollectionFile.addColumn("RES_ID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 100);
|
||||||
|
bulkExportCollectionFile.addForeignKey("FK_BLKEXCOLFILE_COLLECT").toColumn("COLLECTION_PID").references("HFJ_BLK_EXPORT_COLLECTION", "PID");
|
||||||
|
|
||||||
|
|
||||||
|
version.startSectionWithMessage("Processing bulkExportCollectionFile: HFJ_RES_VER_PROV");
|
||||||
Builder.BuilderAddTableByColumns resVerProv = version.addTableByColumns("HFJ_RES_VER_PROV", "RES_VER_PID");
|
Builder.BuilderAddTableByColumns resVerProv = version.addTableByColumns("HFJ_RES_VER_PROV", "RES_VER_PID");
|
||||||
resVerProv.addColumn("RES_VER_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
resVerProv.addColumn("RES_VER_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
resVerProv
|
resVerProv
|
||||||
|
@ -78,7 +118,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
resVerProv.addIndex("IDX_RESVERPROV_REQUESTID").unique(false).withColumns("REQUEST_ID");
|
resVerProv.addIndex("IDX_RESVERPROV_REQUESTID").unique(false).withColumns("REQUEST_ID");
|
||||||
|
|
||||||
// TermValueSetConceptDesignation
|
// TermValueSetConceptDesignation
|
||||||
version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION");
|
version.startSectionWithMessage("Processing bulkExportCollectionFile: TRM_VALUESET_C_DESIGNATION");
|
||||||
Builder.BuilderWithTableName termValueSetConceptDesignationTable = version.onTable("TRM_VALUESET_C_DESIGNATION");
|
Builder.BuilderWithTableName termValueSetConceptDesignationTable = version.onTable("TRM_VALUESET_C_DESIGNATION");
|
||||||
termValueSetConceptDesignationTable.addColumn("VALUESET_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
termValueSetConceptDesignationTable.addColumn("VALUESET_PID").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
termValueSetConceptDesignationTable
|
termValueSetConceptDesignationTable
|
||||||
|
@ -91,7 +131,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
version.onTable("HFJ_SEARCH_RESULT").dropForeignKey("FK_SEARCHRES_SEARCH", "HFJ_SEARCH");
|
version.onTable("HFJ_SEARCH_RESULT").dropForeignKey("FK_SEARCHRES_SEARCH", "HFJ_SEARCH");
|
||||||
|
|
||||||
// TermValueSet
|
// TermValueSet
|
||||||
version.startSectionWithMessage("Processing table: TRM_VALUESET");
|
version.startSectionWithMessage("Processing bulkExportCollectionFile: TRM_VALUESET");
|
||||||
Builder.BuilderWithTableName termValueSetTable = version.onTable("TRM_VALUESET");
|
Builder.BuilderWithTableName termValueSetTable = version.onTable("TRM_VALUESET");
|
||||||
termValueSetTable.addColumn("TOTAL_CONCEPTS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
termValueSetTable.addColumn("TOTAL_CONCEPTS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
termValueSetTable.addColumn("TOTAL_CONCEPT_DESIGNATIONS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
termValueSetTable.addColumn("TOTAL_CONCEPT_DESIGNATIONS").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||||
|
@ -101,7 +141,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
version.dropIdGenerator("SEQ_SEARCHPARM_ID");
|
version.dropIdGenerator("SEQ_SEARCHPARM_ID");
|
||||||
|
|
||||||
// TermValueSetConcept
|
// TermValueSetConcept
|
||||||
version.startSectionWithMessage("Processing table: TRM_VALUESET_CONCEPT");
|
version.startSectionWithMessage("Processing bulkExportCollectionFile: TRM_VALUESET_CONCEPT");
|
||||||
Builder.BuilderWithTableName termValueSetConceptTable = version.onTable("TRM_VALUESET_CONCEPT");
|
Builder.BuilderWithTableName termValueSetConceptTable = version.onTable("TRM_VALUESET_CONCEPT");
|
||||||
termValueSetConceptTable.addColumn("VALUESET_ORDER").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
|
termValueSetConceptTable.addColumn("VALUESET_ORDER").nonNullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.INT);
|
||||||
termValueSetConceptTable
|
termValueSetConceptTable
|
||||||
|
|
|
@ -41,6 +41,11 @@
|
||||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<!-- Optional -->
|
<!-- Optional -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
|
|
@ -82,6 +82,16 @@
|
||||||
<skipUpdateLicense>true</skipUpdateLicense>
|
<skipUpdateLicense>true</skipUpdateLicense>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<includeDependencySources>true</includeDependencySources>
|
||||||
|
<dependencySourceIncludes>
|
||||||
|
<include>ca.uhn.hapi.fhir:org.hl7.fhir.dstu3</include>
|
||||||
|
</dependencySourceIncludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
@ -160,6 +170,13 @@
|
||||||
<artifactId>xpp3</artifactId>
|
<artifactId>xpp3</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.antlr</groupId>
|
||||||
|
<artifactId>ST4</artifactId>
|
||||||
|
<version>4.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>xpp3</groupId>
|
<groupId>xpp3</groupId>
|
||||||
|
|
|
@ -94,6 +94,30 @@
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Optional dependencies used by org.hl7.fhir.r4
|
||||||
|
We include these here to get the aggregate JavaDoc to work
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>ooxml-schemas</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xmlunit</groupId>
|
<groupId>org.xmlunit</groupId>
|
||||||
|
@ -329,6 +353,16 @@
|
||||||
</instructions>
|
</instructions>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<includeDependencySources>true</includeDependencySources>
|
||||||
|
<dependencySourceIncludes>
|
||||||
|
<include>ca.uhn.hapi.fhir:org.hl7.fhir.r4</include>
|
||||||
|
</dependencySourceIncludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,29 @@
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Optional dependencies used by org.hl7.fhir.r4
|
||||||
|
We include these here to get the aggregate JavaDoc to work
|
||||||
|
-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>poi-ooxml</artifactId>
|
||||||
|
<version>4.0.1</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.poi</groupId>
|
||||||
|
<artifactId>ooxml-schemas</artifactId>
|
||||||
|
<version>1.4</version>
|
||||||
|
<optional>true</optional>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Testing -->
|
<!-- Testing -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xmlunit</groupId>
|
<groupId>org.xmlunit</groupId>
|
||||||
|
@ -323,6 +346,16 @@
|
||||||
</instructions>
|
</instructions>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<includeDependencySources>true</includeDependencySources>
|
||||||
|
<dependencySourceIncludes>
|
||||||
|
<include>ca.uhn.hapi.fhir:org.hl7.fhir.r5</include>
|
||||||
|
</dependencySourceIncludes>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|