Merge branch 'master' into loinc_loader_update
This commit is contained in:
commit
53c2d8a38d
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
This example sets up a FHIR server that can ship out Server-sent events using standard Jersey 2.x components. Start up the server and eg. issue the following curl request 'curl -v -X GET http://localhost:8080/Patient/listen'. The will block curl and once any events are shipped to the server, they will automatically be sent to the curl client.
|
||||
|
||||
Changes can be sent to the server on localhost:8080/Patient which accepts any kind of patients that has at least one identifier.
|
||||
|
||||
Voila
|
|
@ -0,0 +1,91 @@
|
|||
<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-fhir</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>hapi-fhir-jaxrs-sse</artifactId>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ebaysf.web</groupId>
|
||||
<artifactId>cors-filter</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.media</groupId>
|
||||
<artifactId>jersey-media-sse</artifactId>
|
||||
<version>${jersey_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jersey.containers</groupId>
|
||||
<artifactId>jersey-container-servlet</artifactId>
|
||||
<version>${jersey_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>jul-to-slf4j</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.21</version>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/org.glassfish.hk2/hk2-locator -->
|
||||
<dependency>
|
||||
<groupId>org.glassfish.hk2</groupId>
|
||||
<artifactId>hk2-locator</artifactId>
|
||||
<version>2.4.0-b34</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.glassfish.hk2</groupId>
|
||||
<artifactId>guice-bridge</artifactId>
|
||||
<version>2.4.0-b34</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>21.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,129 @@
|
|||
package embedded.example;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.glassfish.jersey.media.sse.EventOutput;
|
||||
import org.glassfish.jersey.media.sse.OutboundEvent;
|
||||
import org.glassfish.jersey.media.sse.SseBroadcaster;
|
||||
import org.glassfish.jersey.media.sse.SseFeature;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
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 ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import jersey.repackaged.com.google.common.collect.Maps;
|
||||
|
||||
@Singleton
|
||||
@Path("Patient")
|
||||
@Produces({ MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML })
|
||||
public class JaxRsPatientProvider extends AbstractJaxRsResourceProvider<Patient> {
|
||||
|
||||
private final Map<String, Patient> patients = Maps.newConcurrentMap();
|
||||
private final SseBroadcaster broadcaster = new SseBroadcaster();
|
||||
|
||||
@Inject
|
||||
public JaxRsPatientProvider() {
|
||||
super(FhirContext.forDstu3(), JaxRsPatientProvider.class);
|
||||
}
|
||||
|
||||
@Search
|
||||
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
|
||||
final List<Patient> result = new LinkedList<Patient>();
|
||||
for (final Patient patient : patients.values()) {
|
||||
Patient single = null;
|
||||
if (name == null
|
||||
|| patient.getName().get(0).getFamilyElement().getValueNotNull().equals(name.getValueNotNull())) {
|
||||
single = patient;
|
||||
}
|
||||
if (single != null) {
|
||||
result.add(single);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam final String theConditional)
|
||||
throws Exception {
|
||||
|
||||
storePatient(patient);
|
||||
|
||||
final MethodOutcome result = new MethodOutcome().setCreated(true);
|
||||
result.setResource(patient);
|
||||
result.setId(new IdType(patient.getId()));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Conceptual wrapper for storing in a db
|
||||
private void storePatient(final Patient patient) {
|
||||
|
||||
try {
|
||||
patients.put(patient.getIdentifierFirstRep().getValue(), patient);
|
||||
// if storing is successful the notify the listeners that listens on
|
||||
// any patient => patient/*
|
||||
|
||||
final String bundleToString = currentPatientsAsJsonString();
|
||||
|
||||
broadcaster
|
||||
.broadcast(new OutboundEvent.Builder().name("patients").data(String.class, bundleToString).build());
|
||||
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String currentPatientsAsJsonString() {
|
||||
final IParser jsonParser = this.getFhirContext().newJsonParser().setPrettyPrint(true);
|
||||
final org.hl7.fhir.dstu3.model.Bundle bundle = new org.hl7.fhir.dstu3.model.Bundle();
|
||||
for (final Patient p : patients.values())
|
||||
bundle.addEntry(new BundleEntryComponent().setResource(p));
|
||||
final String bundleToString = jsonParser.encodeResourceToString(bundle);
|
||||
return bundleToString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ETagSupportEnum getETagSupport() {
|
||||
return ETagSupportEnum.DISABLED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("listen")
|
||||
@Produces(SseFeature.SERVER_SENT_EVENTS)
|
||||
public EventOutput listenToBroadcast() throws IOException {
|
||||
final EventOutput eventOutput = new EventOutput();
|
||||
|
||||
final String bundleToString = currentPatientsAsJsonString();
|
||||
|
||||
eventOutput.write(
|
||||
new OutboundEvent.Builder().name("patients").data(String.class, bundleToString).build());
|
||||
this.broadcaster.add(eventOutput);
|
||||
return eventOutput;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package embedded.example.jerseyguice;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.glassfish.hk2.api.ServiceLocator;
|
||||
import org.glassfish.jersey.server.ResourceConfig;
|
||||
import org.glassfish.jersey.server.spi.Container;
|
||||
import org.glassfish.jersey.server.spi.ContainerLifecycleListener;
|
||||
import org.glassfish.jersey.servlet.ServletContainer;
|
||||
import org.jvnet.hk2.guice.bridge.api.GuiceBridge;
|
||||
import org.jvnet.hk2.guice.bridge.api.GuiceIntoHK2Bridge;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Scopes;
|
||||
import com.google.inject.servlet.ServletModule;
|
||||
|
||||
public abstract class GuiceHk2Helper extends ServletModule {
|
||||
private static final Logger log = LoggerFactory.getLogger(GuiceHk2Helper.class);
|
||||
|
||||
@Override
|
||||
abstract protected void configureServlets();
|
||||
|
||||
public interface RestKeyBindingBuilder {
|
||||
void packages(String... packages);
|
||||
|
||||
void packages(Package... packages);
|
||||
|
||||
void packages(Class<?>... clazz);
|
||||
}
|
||||
|
||||
protected RestKeyBindingBuilder rest(final String... urlPatterns) {
|
||||
return new RestKeyBindingBuilderImpl(Arrays.asList(urlPatterns));
|
||||
}
|
||||
|
||||
private class RestKeyBindingBuilderImpl implements RestKeyBindingBuilder {
|
||||
List<String> paths;
|
||||
|
||||
public RestKeyBindingBuilderImpl(final List<String> paths) {
|
||||
this.paths = paths;
|
||||
}
|
||||
|
||||
private boolean checkIfPackageExistsAndLog(final String packge) {
|
||||
boolean exists = false;
|
||||
final String resourcePath = packge.replace(".", "/");
|
||||
final URL resource = getClass().getClassLoader().getResource(resourcePath);
|
||||
if (resource != null) {
|
||||
exists = true;
|
||||
log.info("rest(" + paths + ").packages(" + packge + ")");
|
||||
} else {
|
||||
log.info("No Beans in '" + packge + "' found. Requests " + paths + " will fail.");
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packages(final String... packages) {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (final String pkg : packages) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(',');
|
||||
}
|
||||
checkIfPackageExistsAndLog(pkg);
|
||||
sb.append(pkg);
|
||||
}
|
||||
final Map<String, String> params = new HashMap<>();
|
||||
params.put("javax.ws.rs.Application", GuiceResourceConfig.class.getCanonicalName());
|
||||
if (sb.length() > 0) {
|
||||
params.put("jersey.config.server.provider.packages", sb.toString());
|
||||
}
|
||||
bind(ServletContainer.class).in(Scopes.SINGLETON);
|
||||
for (final String path : paths) {
|
||||
serve(path).with(ServletContainer.class, params);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packages(final Package... packages) {
|
||||
packages(FluentIterable.from(packages).transform(new Function<Package, String>() {
|
||||
|
||||
@Override
|
||||
public String apply(final Package arg0) {
|
||||
return arg0.getName();
|
||||
}
|
||||
}).toArray(String.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void packages(final Class<?>... clazz) {
|
||||
packages(FluentIterable.from(clazz).transform(new Function<Class<?>, String>() {
|
||||
|
||||
@Override
|
||||
public String apply(final Class<?> arg0) {
|
||||
return arg0.getPackage().getName();
|
||||
}
|
||||
}).toArray(String.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GuiceResourceConfig extends ResourceConfig {
|
||||
public GuiceResourceConfig() {
|
||||
register(new ContainerLifecycleListener() {
|
||||
@Override
|
||||
public void onStartup(final Container container) {
|
||||
final ServletContainer servletContainer = (ServletContainer) container;
|
||||
final ServiceLocator serviceLocator = container.getApplicationHandler().getServiceLocator();
|
||||
GuiceBridge.getGuiceBridge().initializeGuiceBridge(serviceLocator);
|
||||
final GuiceIntoHK2Bridge guiceBridge = serviceLocator.getService(GuiceIntoHK2Bridge.class);
|
||||
final Injector injector = (Injector) servletContainer.getServletContext()
|
||||
.getAttribute(Injector.class.getName());
|
||||
guiceBridge.bridgeGuiceInjector(injector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(final Container container) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShutdown(final Container container) {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Aberger Software GmbH. All Rights Reserved.
|
||||
* http://www.aberger.at
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package embedded.example.jerseyguice;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.net.URI;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.Module;
|
||||
import com.google.inject.Stage;
|
||||
import com.google.inject.servlet.GuiceFilter;
|
||||
import com.google.inject.servlet.GuiceServletContextListener;
|
||||
|
||||
import embedded.example.JaxRsPatientProvider;
|
||||
|
||||
public class GuiceJersey2ServletContextListener extends GuiceServletContextListener {
|
||||
|
||||
@Override
|
||||
protected Injector getInjector() {
|
||||
|
||||
final List<Module> modules = Lists.newArrayList();
|
||||
|
||||
|
||||
modules.add(new GuiceHk2Helper() {
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
// bind(JaxRsPatientProvider.class).in(Scopes.SINGLETON);
|
||||
rest("/*").packages(JaxRsPatientProvider.class);
|
||||
}
|
||||
});
|
||||
return Guice.createInjector(Stage.PRODUCTION, modules);
|
||||
}
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
|
||||
SLF4JBridgeHandler.removeHandlersForRootLogger();
|
||||
SLF4JBridgeHandler.install();
|
||||
|
||||
final Server server = new Server(8080);
|
||||
|
||||
final ServletContextHandler sch = new ServletContextHandler(server, "/");
|
||||
sch.addEventListener(new GuiceJersey2ServletContextListener());
|
||||
sch.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
server.start();
|
||||
|
||||
Desktop.getDesktop().browse(new URI("http://localhost:8080/Patient"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0"?>
|
||||
<web-app>
|
||||
<filter>
|
||||
<filter-name>Guice Filter</filter-name>
|
||||
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>Guice Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
<listener>
|
||||
<listener-class>embedded.example.ContextListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<!-- <context-param> <param-name>username</param-name> <param-value>username</param-value>
|
||||
</context-param> <context-param> <param-name>password</param-name> <param-value>password</param-value>
|
||||
</context-param> -->
|
||||
<context-param>
|
||||
<param-name>serverAddress</param-name>
|
||||
<param-value>http://fhirtest.uhn.ca/baseDstu2</param-value>
|
||||
</context-param>
|
||||
</web-app>
|
|
@ -0,0 +1,14 @@
|
|||
package test;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
public class WarTester {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
final Server server = new Server(8080);
|
||||
server.setHandler(new WebAppContext("target/fhirtester.war", "/"));
|
||||
server.start();
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -224,13 +224,17 @@
|
|||
</pluginManagement>
|
||||
|
||||
<plugins>
|
||||
<!-- Tell Maven which Java source version you want to use -->
|
||||
|
||||
<!--
|
||||
The CQF-Ruler project has some OWASP dependency security failures which we don't want
|
||||
to cause the whole build to fail. TODO: investigate these
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<groupId>org.owasp</groupId>
|
||||
<artifactId>dependency-check-maven</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
<failBuildOnCVSS>99</failBuildOnCVSS>
|
||||
<failOnError>false</failOnError>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
|
|
@ -0,0 +1,713 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Strict//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<title>/Users/anoushmouradian/Documents/projects/chip-hapi-fhir-new/hapi-fhir-jpaserver-dynamic/.README.md.html</title>
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
color: #333;
|
||||
font: 13px/1.4 "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
background: transparent;
|
||||
color: #4183c4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0 none;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
sub, sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
img {
|
||||
border: 0 none;
|
||||
}
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
hr {
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace,monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
font: 12px Consolas,"Liberation Mono",Menlo,Courier,monospace;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.markdown-body {
|
||||
padding: 30px;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.markdown-body>*:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body>*:last-child {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.markdown-body .absent {
|
||||
color: #c00;
|
||||
}
|
||||
|
||||
.markdown-body .anchor {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: block;
|
||||
padding-right: 6px;
|
||||
padding-left: 30px;
|
||||
margin-left: -30px;
|
||||
}
|
||||
|
||||
.markdown-body .anchor:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.markdown-body h1,
|
||||
.markdown-body h2,
|
||||
.markdown-body h3,
|
||||
.markdown-body h4,
|
||||
.markdown-body h5,
|
||||
.markdown-body h6 {
|
||||
position: relative;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.markdown-body h1 .octicon-link,
|
||||
.markdown-body h2 .octicon-link,
|
||||
.markdown-body h3 .octicon-link,
|
||||
.markdown-body h4 .octicon-link,
|
||||
.markdown-body h5 .octicon-link,
|
||||
.markdown-body h6 .octicon-link {
|
||||
display: none;
|
||||
color: #000;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.markdown-body h1:hover .anchor,
|
||||
.markdown-body h2:hover .anchor,
|
||||
.markdown-body h3:hover .anchor,
|
||||
.markdown-body h4:hover .anchor,
|
||||
.markdown-body h5:hover .anchor,
|
||||
.markdown-body h6:hover .anchor {
|
||||
padding-left: 8px;
|
||||
margin-left: -30px;
|
||||
line-height: 1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.markdown-body h1:hover .anchor .octicon-link,
|
||||
.markdown-body h2:hover .anchor .octicon-link,
|
||||
.markdown-body h3:hover .anchor .octicon-link,
|
||||
.markdown-body h4:hover .anchor .octicon-link,
|
||||
.markdown-body h5:hover .anchor .octicon-link,
|
||||
.markdown-body h6:hover .anchor .octicon-link {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.markdown-body h1 tt,
|
||||
.markdown-body h1 code,
|
||||
.markdown-body h2 tt,
|
||||
.markdown-body h2 code,
|
||||
.markdown-body h3 tt,
|
||||
.markdown-body h3 code,
|
||||
.markdown-body h4 tt,
|
||||
.markdown-body h4 code,
|
||||
.markdown-body h5 tt,
|
||||
.markdown-body h5 code,
|
||||
.markdown-body h6 tt,
|
||||
.markdown-body h6 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
.markdown-body h1 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 2.25em;
|
||||
line-height: 1.2;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.markdown-body h2 {
|
||||
padding-bottom: 0.3em;
|
||||
font-size: 1.75em;
|
||||
line-height: 1.225;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.markdown-body h3 {
|
||||
font-size: 1.5em;
|
||||
line-height: 1.43;
|
||||
}
|
||||
|
||||
.markdown-body h4 {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.markdown-body h5 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.markdown-body h6 {
|
||||
font-size: 1em;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.markdown-body p,.markdown-body blockquote,
|
||||
.markdown-body ul,.markdown-body ol,
|
||||
.markdown-body dl,.markdown-body table,
|
||||
.markdown-body pre {
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body hr {
|
||||
height: 4px;
|
||||
padding: 0;
|
||||
margin: 16px 0;
|
||||
background-color: #e7e7e7;
|
||||
border: 0 none;
|
||||
}
|
||||
|
||||
.markdown-body ul,
|
||||
.markdown-body ol {
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.markdown-body ul.no-list,
|
||||
.markdown-body ol.no-list {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
.markdown-body ul ul,
|
||||
.markdown-body ul ol,
|
||||
.markdown-body ol ol,
|
||||
.markdown-body ol ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body li>p {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.markdown-body dl {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.markdown-body dl dt {
|
||||
padding: 0;
|
||||
margin-top: 16px;
|
||||
font-size: 1em;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body dl dd {
|
||||
padding: 0 16px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body blockquote {
|
||||
padding: 0 15px;
|
||||
color: #777;
|
||||
border-left: 4px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body blockquote>:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.markdown-body blockquote>:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.markdown-body table {
|
||||
display: block;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
word-break: normal;
|
||||
word-break: keep-all;
|
||||
}
|
||||
|
||||
.markdown-body table th {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.markdown-body table th,
|
||||
.markdown-body table td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body table tr {
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.markdown-body table tr:nth-child(2n) {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.markdown-body img {
|
||||
max-width: 100%;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.markdown-body span.frame {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown-body span.frame>span {
|
||||
display: block;
|
||||
float: left;
|
||||
width: auto;
|
||||
padding: 7px;
|
||||
margin: 13px 0 0;
|
||||
overflow: hidden;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.markdown-body span.frame span img {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.markdown-body span.frame span span {
|
||||
display: block;
|
||||
padding: 5px 0 0;
|
||||
clear: both;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.markdown-body span.align-center {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown-body span.align-center>span {
|
||||
display: block;
|
||||
margin: 13px auto 0;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.markdown-body span.align-center span img {
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.markdown-body span.align-right {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.markdown-body span.align-right>span {
|
||||
display: block;
|
||||
margin: 13px 0 0;
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.markdown-body span.align-right span img {
|
||||
margin: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.markdown-body span.float-left {
|
||||
display: block;
|
||||
float: left;
|
||||
margin-right: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown-body span.float-left span {
|
||||
margin: 13px 0 0;
|
||||
}
|
||||
|
||||
.markdown-body span.float-right {
|
||||
display: block;
|
||||
float: right;
|
||||
margin-left: 13px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.markdown-body span.float-right>span {
|
||||
display: block;
|
||||
margin: 13px auto 0;
|
||||
overflow: hidden;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.markdown-body code,.markdown-body tt {
|
||||
padding: 0;
|
||||
padding-top: 0.2em;
|
||||
padding-bottom: 0.2em;
|
||||
margin: 0;
|
||||
font-size: 85%;
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown-body code:before,
|
||||
.markdown-body code:after,
|
||||
.markdown-body tt:before,
|
||||
.markdown-body tt:after {
|
||||
letter-spacing: -0.2em;
|
||||
content: "\00a0";
|
||||
}
|
||||
|
||||
.markdown-body code br,
|
||||
.markdown-body tt br {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.markdown-body del code {
|
||||
text-decoration: inherit;
|
||||
}
|
||||
|
||||
.markdown-body pre>code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 100%;
|
||||
word-break: normal;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body .highlight {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.markdown-body .highlight pre,
|
||||
.markdown-body pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f7f7f7;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.markdown-body .highlight pre {
|
||||
margin-bottom: 0;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.markdown-body pre {
|
||||
word-wrap: normal;
|
||||
}
|
||||
|
||||
.markdown-body pre code,
|
||||
.markdown-body pre tt {
|
||||
display: inline;
|
||||
max-width: initial;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: initial;
|
||||
line-height: inherit;
|
||||
word-wrap: normal;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.markdown-body pre code:before,
|
||||
.markdown-body pre code:after,
|
||||
.markdown-body pre tt:before,
|
||||
.markdown-body pre tt:after {
|
||||
content: normal;
|
||||
}
|
||||
|
||||
.highlight .pl-coc,
|
||||
.highlight .pl-entl,
|
||||
.highlight .pl-entm,
|
||||
.highlight .pl-eoa,
|
||||
.highlight .pl-mai .pl-sf,
|
||||
.highlight .pl-mm,
|
||||
.highlight .pl-pdv,
|
||||
.highlight .pl-sc,
|
||||
.highlight .pl-som,
|
||||
.highlight .pl-sr,
|
||||
.highlight .pl-v,
|
||||
.highlight .pl-vpf {
|
||||
color: #0086b3;
|
||||
}
|
||||
.highlight .pl-eoac,
|
||||
.highlight .pl-mdht,
|
||||
.highlight .pl-mi1,
|
||||
.highlight .pl-mri,
|
||||
.highlight .pl-va,
|
||||
.highlight .pl-vpu {
|
||||
color: #008080;
|
||||
}
|
||||
.highlight .pl-c,
|
||||
.highlight .pl-pdc {
|
||||
color: #b4b7b4;
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .pl-k,
|
||||
.highlight .pl-ko,
|
||||
.highlight .pl-kolp,
|
||||
.highlight .pl-mc,
|
||||
.highlight .pl-mr,
|
||||
.highlight .pl-ms,
|
||||
.highlight .pl-s,
|
||||
.highlight .pl-sok,
|
||||
.highlight .pl-st {
|
||||
color: #6e5494;
|
||||
}
|
||||
.highlight .pl-ef,
|
||||
.highlight .pl-enf,
|
||||
.highlight .pl-enm,
|
||||
.highlight .pl-entc,
|
||||
.highlight .pl-eoi,
|
||||
.highlight .pl-sf,
|
||||
.highlight .pl-smc {
|
||||
color: #d12089;
|
||||
}
|
||||
.highlight .pl-ens,
|
||||
.highlight .pl-eoai,
|
||||
.highlight .pl-kos,
|
||||
.highlight .pl-mh .pl-pdh,
|
||||
.highlight .pl-mp,
|
||||
.highlight .pl-pde,
|
||||
.highlight .pl-stp {
|
||||
color: #458;
|
||||
}
|
||||
.highlight .pl-enti {
|
||||
color: #d12089;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .pl-cce,
|
||||
.highlight .pl-enc,
|
||||
.highlight .pl-kou,
|
||||
.highlight .pl-mq {
|
||||
color: #f93;
|
||||
}
|
||||
.highlight .pl-mp1 .pl-sf {
|
||||
color: #458;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .pl-cos,
|
||||
.highlight .pl-ent,
|
||||
.highlight .pl-md,
|
||||
.highlight .pl-mdhf,
|
||||
.highlight .pl-ml,
|
||||
.highlight .pl-pdc1,
|
||||
.highlight .pl-pds,
|
||||
.highlight .pl-s1,
|
||||
.highlight .pl-scp,
|
||||
.highlight .pl-sol {
|
||||
color: #df5000;
|
||||
}
|
||||
.highlight .pl-c1,
|
||||
.highlight .pl-cn,
|
||||
.highlight .pl-pse,
|
||||
.highlight .pl-pse .pl-s2,
|
||||
.highlight .pl-vi {
|
||||
color: #a31515;
|
||||
}
|
||||
.highlight .pl-mb,
|
||||
.highlight .pl-pdb {
|
||||
color: #df5000;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .pl-mi,
|
||||
.highlight .pl-pdi {
|
||||
color: #6e5494;
|
||||
font-style: italic;
|
||||
}
|
||||
.highlight .pl-ms1 {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.highlight .pl-mdh,
|
||||
.highlight .pl-mdi {
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .pl-mdr {
|
||||
color: #0086b3;
|
||||
font-weight: bold;
|
||||
}
|
||||
.highlight .pl-s2 {
|
||||
color: #333;
|
||||
}
|
||||
.highlight .pl-ii {
|
||||
background-color: #df5000;
|
||||
color: #fff;
|
||||
}
|
||||
.highlight .pl-ib {
|
||||
background-color: #f93;
|
||||
}
|
||||
.highlight .pl-id {
|
||||
background-color: #a31515;
|
||||
color: #fff;
|
||||
}
|
||||
.highlight .pl-iu {
|
||||
background-color: #b4b7b4;
|
||||
}
|
||||
.highlight .pl-mo {
|
||||
color: #969896;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function getDocumentScrollTop()
|
||||
{
|
||||
var res = document.body.scrollTop || document.documentElement.scrollTop || window.pageYOffset || 0;
|
||||
// alert(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
function setDocumentScrollTop(ypos)
|
||||
{
|
||||
window.scrollTo(0, ypos);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
</head>
|
||||
<body class="markdown-body">
|
||||
<h2> <a id="description" class="anchor" href="#description" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Description</h2>
|
||||
<p>This project has been built with hapi-fhir-jpaserver-example as a base. It has been made more dynamic by replacing <code>web.xml</code> with <code>ca.uhn.fhir.jpa.demo.WebInitializer</code> class which extends Spring <code>org.springframework.web.WebApplicationInitializer</code> class and loads application contexts in a dynamic manner, so that based on environment and/or property variables it can be started either as dstu2 or dstu3 version of HAPI-FHIR JPA Server. Some of the classes have been also refactored to make them more generic.</p>
|
||||
<h4> <a id="environment-variables" class="anchor" href="#environment-variables" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Environment variables</h4>
|
||||
<p>There are number of environment variables that will control the behavior of the application at run time (such as start as dstu2 or dstu3 version, whether database schema gets recreated or no, database url, etc..). They can also be defined in Property files, see section below. These are environment variables that can be set before application starts:</p>
|
||||
<ul>
|
||||
<li> <p><code>DB_URL</code> - database url in a standard jdbc url format, specific to a database of your choosing. For example for Postgres it will be: <code>jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password></code>. So far support has been added for MySQL, derby and Postgres databases.</p> </li>
|
||||
<li> <p><code>DATABASE_URL</code> - if you deploy your server to HEROKU and create a Postgres database, its URL will be exposed through <code>DATABASE_URL</code> environment variable set by HEROKU. If <code>DATABASE_URL</code> is present it will overwrite <code>DB_URL</code> and its value will be used as jdbc url. This implementations assumes that Heroku will be setup with Postgres database, so current implementation handles postgres <code>DATABASE_URL</code> that gets set in this format: <code>postgres://<username>:<password>@<hostname>:5432/<databaseName></code>. We convert it into standard jdbc format: <code>jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password></code></p> </li>
|
||||
<li> <p><code>SCHEMA_NAME</code> - used only if <code>DATABASE_URL</code> is set, which is expected to be Postgres database url set by HEROKU. If it's set <code>currentSchema</code> parameter will be added to the jdbc url, e.g.:<br /> <code>jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>&currentScema=<schemaName></code>. Note that schema has to be created beforehand and user should have the right permissions to create tables.</p> </li>
|
||||
<li> <p><code>STU_VERSION</code> - can be set to <code>dstu2</code> or <code>dstu3</code>. If not set by default <code>dstu3</code> will be used. Corresponding classes will get dynamically loaded at a server startup.</p> </li>
|
||||
<li> <p><code>ENV</code> - environment this server will run in, and based on which corresponding property files will be loaded.</p> <p>It can be one of those values: <code>local, dev, stg, prod</code>. Based on the value one of the property files will be loaded: <code>resources/config/<STU_VERSION>/app_<ENV>.properties</code>.</p> <p>So for example if <code>ENV=local</code> and <code>STU_VERSION=dstu3</code> this file will be loaded:</p> <p><code>resources/config/dstu3/app_local.properties</code></p> </li>
|
||||
<li> <p><code>HIBERNATE_CREATE</code> - can be set to <code>true</code> or <code>false</code>. If set to <code>true</code> database schema will be dropped and recreated again upon application startup. If set to <code>false</code> hibernate will run with <code>validate</code> as a schema setting.</p> </li>
|
||||
</ul>
|
||||
<h4> <a id="property-files" class="anchor" href="#property-files" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Property files</h4>
|
||||
<p>There are number of property files created for different environments: <code>local, dev, stg, prod</code>. So if <code>ENV</code> environment variable is set to one of those values corresponding property file will be loaded at a run time, by default <code>local</code> files will be loaded. Property files are located at: <code>src/main/resources/config/dstu2</code> and <code>src/main/resources/config/dstu3s</code> directories. These are the files:</p>
|
||||
<pre><code> app_local.properties
|
||||
app_dev.properties
|
||||
app_stg.properties
|
||||
app_prod.properties
|
||||
immutable.properties - DO NOT modify any of the properties defined in that file.
|
||||
</code></pre>
|
||||
<p>Any of the Environment variables can be defined in one of the <code>app_<ENV>.properties</code> property files. If a property is also defined as Environment variable it will overwrite value defined in property file. Properties defined in <code>immutable.properties</code> should not be changed, those are servlet/Spring mappings and names of classes that will be loaded at a run time and are specific to dstu version being used.</p>
|
||||
<h2> <a id="running-hapi-fhir-jpaserver-dynamic-with-a-webapp-runner" class="anchor" href="#running-hapi-fhir-jpaserver-dynamic-with-a-webapp-runner" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Running hapi-fhir-jpaserver-dynamic with a webapp-runner</h2>
|
||||
<p>You can run the web application with webapp-runner and pass environment variables to it.</p>
|
||||
<p>Here is a sample command to run the webapp runner which will start dynamic HAPI-FHIR server with version dstu3, postgres database and hibernate schema being dropped and re-created.</p>
|
||||
<p>Note optional command to unset DATABASE_URL, so that only DB_URL is used locally. Also make sure to replace placeholder parameters <code><databasename></code>, <code><username></code> and <code><password></code> with actual values.</p>
|
||||
<pre><code>mvn clean install
|
||||
|
||||
unset DATABASE_URL
|
||||
|
||||
java $JAVA_OPTS -DSTU_VERSION=dstu3 -DHIBERNATE_CREATE=true -DDB_URL='jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>' -DENV=local -jar target/dependency/webapp-runner.jar target/*.war
|
||||
</code></pre>
|
||||
<p>You should be able to access HAPI_FHIR server at: <a href="http://localhost:8080/" rel="nofollow">http://localhost:8080/</a> .</p>
|
||||
<p>If you'd like to open a debugging port run this command and attach remote debugger in IDE of your choice to port 5000. Again make sure to replace placeholder parameters with actual values before you run the command.</p>
|
||||
<pre><code>java $JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=5000,suspend=n -DSTU_VERSION=dstu3 -DHIBERNATE_CREATE=false -DDB_URL='jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>' -DENV=local -jar target/dependency/webapp-runner.jar target/*.war
|
||||
</code></pre>
|
||||
<h2> <a id="running-hapi-fhir-jpaserver-dynamic-in-tomcat-from-intellij" class="anchor" href="#running-hapi-fhir-jpaserver-dynamic-in-tomcat-from-intellij" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Running hapi-fhir-jpaserver-dynamic in Tomcat from IntelliJ</h2>
|
||||
<p>Install Tomcat.</p>
|
||||
<p>Make sure you have Tomcat set up in IntelliJ.</p>
|
||||
<ul>
|
||||
<li>File->Settings->Build, Execution, Deployment->Application Servers</li>
|
||||
<li>Click +</li>
|
||||
<li>Select "Tomcat Server"</li>
|
||||
<li>Enter the path to your tomcat deployment for both Tomcat Home (IntelliJ will fill in base directory for you)</li>
|
||||
</ul>
|
||||
<p>Add a Run Configuration for running hapi-fhir-jpaserver-dynamic under Tomcat</p>
|
||||
<ul>
|
||||
<li>Run->Edit Configurations</li>
|
||||
<li>Click the green +</li>
|
||||
<li>Select Tomcat Server, Local</li>
|
||||
<li>Change the name to whatever you wish</li>
|
||||
<li>Uncheck the "After launch" checkbox</li>
|
||||
<li>On the "Deployment" tab, click the green +</li>
|
||||
<li>Select "Artifact"</li>
|
||||
<li>Select "hapi-fhir-jpaserver-dynamic:war"</li>
|
||||
<li>In "Application context" type /hapi</li>
|
||||
</ul>
|
||||
<p>Run the configuration.</p>
|
||||
<ul>
|
||||
<li>You should now have an "Application Servers" in the list of windows at the bottom.</li>
|
||||
<li>Click it.</li>
|
||||
<li>Select your server, and click the green triangle (or the bug if you want to debug)</li>
|
||||
<li>Wait for the console output to stop</li>
|
||||
</ul>
|
||||
<p>Point your browser (or fiddler, or what have you) to <code>http://localhost:8080/fhir/base/Patient</code></p>
|
||||
<p>You should get an empty bundle back.</p>
|
||||
<h2> <a id="running-hapi-fhir-jpaserver-dynamic-in-a-docker-container" class="anchor" href="#running-hapi-fhir-jpaserver-dynamic-in-a-docker-container" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>Running hapi-fhir-jpaserver-dynamic in a Docker container</h2>
|
||||
<p>Execute the <code>build-docker-image.sh</code> script to build the docker image.</p>
|
||||
<p>Use this command to start the container: <code>docker run -d --name hapi-fhir-jpaserver-dynamic -p 8080:8080 hapi-fhir/hapi-fhir-jpaserver-dynamic</code></p>
|
||||
<p>Note: with this command data is persisted across container restarts, but not after removal of the container. Use a docker volume mapping on /var/lib/jetty/target to achieve this.</p>
|
||||
<p>There is also Dockerfile.tomcat which contains docker commands to run hapi-fhir-jpaserver-dynamic within tomcat. Rename Dockerfile.tomcat to Dockerfile if you would rather use tomcat as your application container.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,129 @@
|
|||
/target
|
||||
/jpaserver_derby_files
|
||||
*.log
|
||||
ca.uhn.fhir.jpa.entity.ResourceTable/
|
||||
|
||||
# Created by https://www.gitignore.io
|
||||
|
||||
### Java ###
|
||||
*.class
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
|
||||
|
||||
### Maven ###
|
||||
target/
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
|
||||
|
||||
### Vim ###
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
*.un~
|
||||
Session.vim
|
||||
.netrwhist
|
||||
*~
|
||||
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
|
||||
|
||||
|
||||
### Eclipse ###
|
||||
*.pydevproject
|
||||
.metadata
|
||||
.gradle
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.loadpath
|
||||
|
||||
# Eclipse Core
|
||||
.project
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
# sbteclipse plugin
|
||||
.target
|
||||
|
||||
# TeXlipse plugin
|
||||
.texlipse
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
FROM jetty:9-jre8-alpine
|
||||
USER jetty:jetty
|
||||
ADD ./target/hapi-fhir-jpaserver-dynamic.war /var/lib/jetty/webapps/root.war
|
||||
EXPOSE 8080
|
|
@ -0,0 +1,4 @@
|
|||
FROM tomcat:8
|
||||
COPY ["./hapi-fhir-jpaserver-dynamic.war","/usr/local/tomcat/webapps/"]
|
||||
CMD ["catalina.sh","run"]
|
||||
EXPOSE 8080
|
|
@ -0,0 +1,107 @@
|
|||
## Description
|
||||
This project has been built with hapi-fhir-jpaserver-example as a base. It has been made more dynamic by replacing `web.xml` with `ca.uhn.fhir.jpa.demo.WebInitializer` class which extends
|
||||
Spring `org.springframework.web.WebApplicationInitializer` class and loads application contexts in a dynamic manner, so that based on environment and/or property variables it can be started either as dstu2 or dstu3 version of HAPI-FHIR JPA Server. Some of the classes have been also refactored to make them more generic.
|
||||
|
||||
#### Environment variables
|
||||
There are number of environment variables that will control the behavior of the application at run time (such as start as dstu2 or dstu3 version, whether
|
||||
database schema gets recreated or no, database url, etc..). They can also be defined in Property files, see section below. These are environment variables that can be set before application starts:
|
||||
* `DB_URL` - database url in a standard jdbc url format, specific to a database of your choosing. For example for Postgres it will be: `jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>`. So far support has been added for MySQL, derby and Postgres databases.
|
||||
* `DATABASE_URL` - if you deploy your server to HEROKU and create a Postgres database, its URL will be exposed through `DATABASE_URL` environment variable set by HEROKU.
|
||||
If `DATABASE_URL` is present it will overwrite `DB_URL` and its value will be used as jdbc url. This implementations assumes that Heroku will be setup with Postgres database, so current implementation handles postgres `DATABASE_URL` that gets set in this format: `postgres://<username>:<password>@<hostname>:5432/<databaseName>`. We convert it into standard jdbc format: `jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>`
|
||||
* `SCHEMA_NAME` - used only if `DATABASE_URL` is set, which is expected to be Postgres database url set by HEROKU. If it's set
|
||||
`currentSchema` parameter will be added to the jdbc url, e.g.:
|
||||
```jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>¤tScema=<schemaName>```.
|
||||
Note that schema has to be created beforehand and user should have the right permissions to create tables.
|
||||
* `STU_VERSION` - can be set to `dstu2` or `dstu3`. If not set by default `dstu3` will be used. Corresponding classes will get dynamically loaded at a server startup.
|
||||
* `ENV` - environment this server will run in, and based on which corresponding property files will be loaded.
|
||||
|
||||
It can be one of those values: `local, dev, stg, prod`. Based on the value one of the property files will be loaded:
|
||||
```resources/config/<STU_VERSION>/app_<ENV>.properties```.
|
||||
|
||||
So for example if `ENV=local` and `STU_VERSION=dstu3` this file will be loaded:
|
||||
|
||||
```resources/config/dstu3/app_local.properties```
|
||||
* `HIBERNATE_CREATE` - can be set to `true` or `false`. If set to `true` database schema will be dropped and recreated again upon application startup. If set
|
||||
to `false` hibernate will run with `validate` as a schema setting.
|
||||
|
||||
#### Property files
|
||||
There are number of property files created for different environments: `local, dev, stg, prod`. So if `ENV` environment variable is set
|
||||
to one of those values corresponding property file will be loaded at a run time, by default `local` files will be loaded. Property files are located at:
|
||||
`src/main/resources/config/dstu2` and `src/main/resources/config/dstu3s` directories. These are the files:
|
||||
```
|
||||
app_local.properties
|
||||
app_dev.properties
|
||||
app_stg.properties
|
||||
app_prod.properties
|
||||
immutable.properties - DO NOT modify any of the properties defined in that file.
|
||||
```
|
||||
Any of the Environment variables can be defined in one of the `app_<ENV>.properties` property files. If a property is also defined as Environment variable it will overwrite value defined in property file. Properties defined in `immutable.properties` should not be changed, those are servlet/Spring mappings and names of classes that will be loaded at a run time and are specific to dstu version being used.
|
||||
|
||||
## Running hapi-fhir-jpaserver-dynamic with a webapp-runner
|
||||
You can run the web application with webapp-runner and pass environment variables to it.
|
||||
|
||||
Here is a sample command to run the webapp runner which will start
|
||||
dynamic HAPI-FHIR server with version dstu3, postgres database and hibernate schema being dropped and re-created.
|
||||
|
||||
Note optional command to unset DATABASE_URL, so that only DB_URL is used locally. Also make sure to replace placeholder parameters `<databasename>`, `<username>` and `<password>` with actual values.
|
||||
|
||||
```
|
||||
mvn clean install
|
||||
|
||||
unset DATABASE_URL
|
||||
|
||||
java $JAVA_OPTS -DSTU_VERSION=dstu3 -DHIBERNATE_CREATE=true -DDB_URL='jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>' -DENV=local -jar target/dependency/webapp-runner.jar target/*.war
|
||||
```
|
||||
You should be able to access HAPI_FHIR server at: http://localhost:8080/ .
|
||||
|
||||
If you'd like to open a debugging port run this command and attach remote debugger in IDE of your choice to port 5000. Again make sure to replace placeholder parameters with actual values before you run the command.
|
||||
|
||||
```
|
||||
java $JAVA_OPTS -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=5000,suspend=n -DSTU_VERSION=dstu3 -DHIBERNATE_CREATE=false -DDB_URL='jdbc:postgresql://localhost:5432/<databaseName>?user=<username>&password=<password>' -DENV=local -jar target/dependency/webapp-runner.jar target/*.war
|
||||
```
|
||||
|
||||
## Running hapi-fhir-jpaserver-dynamic in Tomcat from IntelliJ
|
||||
|
||||
Install Tomcat.
|
||||
|
||||
Make sure you have Tomcat set up in IntelliJ.
|
||||
|
||||
- File->Settings->Build, Execution, Deployment->Application Servers
|
||||
- Click +
|
||||
- Select "Tomcat Server"
|
||||
- Enter the path to your tomcat deployment for both Tomcat Home (IntelliJ will fill in base directory for you)
|
||||
|
||||
Add a Run Configuration for running hapi-fhir-jpaserver-dynamic under Tomcat
|
||||
|
||||
- Run->Edit Configurations
|
||||
- Click the green +
|
||||
- Select Tomcat Server, Local
|
||||
- Change the name to whatever you wish
|
||||
- Uncheck the "After launch" checkbox
|
||||
- On the "Deployment" tab, click the green +
|
||||
- Select "Artifact"
|
||||
- Select "hapi-fhir-jpaserver-dynamic:war"
|
||||
- In "Application context" type /hapi
|
||||
|
||||
Run the configuration.
|
||||
|
||||
- You should now have an "Application Servers" in the list of windows at the bottom.
|
||||
- Click it.
|
||||
- Select your server, and click the green triangle (or the bug if you want to debug)
|
||||
- Wait for the console output to stop
|
||||
|
||||
Point your browser (or fiddler, or what have you) to `http://localhost:8080/fhir/base/Patient`
|
||||
|
||||
You should get an empty bundle back.
|
||||
|
||||
|
||||
## Running hapi-fhir-jpaserver-dynamic in a Docker container
|
||||
|
||||
Execute the `build-docker-image.sh` script to build the docker image.
|
||||
|
||||
Use this command to start the container:
|
||||
`docker run -d --name hapi-fhir-jpaserver-dynamic -p 8080:8080 hapi-fhir/hapi-fhir-jpaserver-dynamic`
|
||||
|
||||
Note: with this command data is persisted across container restarts, but not after removal of the container. Use a docker volume mapping on /var/lib/jetty/target to achieve this.
|
||||
|
||||
There is also Dockerfile.tomcat which contains docker commands to run hapi-fhir-jpaserver-dynamic within tomcat. Rename Dockerfile.tomcat to Dockerfile if you would rather use tomcat as your application container.
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
mvn package && \
|
||||
docker build -t hapi-fhir/hapi-fhir-jpaserver-dynamic .
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!--
|
||||
Note: HAPI projects use the "hapi-fhir" POM as their base to provide easy management.
|
||||
You do not need to use this in your own projects, so the "parent" tag and it's
|
||||
contents below may be removed
|
||||
if you are using this file as a basis for your own project.
|
||||
-->
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-jpaserver-dynamic</artifactId>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<name>HAPI FHIR JPA Server - Example for CHIP</name>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>oss-snapshots</id>
|
||||
<snapshots>
|
||||
<enabled>true</enabled>
|
||||
</snapshots>
|
||||
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
<!-- <repository>
|
||||
<id>jpa_base_lib</id>
|
||||
<url>file://${basedir}/lib</url>
|
||||
</repository> -->
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-api</artifactId>
|
||||
<version>${jetty_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-client</artifactId>
|
||||
<version>${jetty_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<!-- <version>6.0.5</version>-->
|
||||
<version>5.1.40</version>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<version>1.8.9</version>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- This dependency includes the core HAPI-FHIR classes -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- At least one "structures" JAR must also be included -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- This dependency includes the JPA server itself, which is packaged separately from the rest of HAPI FHIR -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>war</type>
|
||||
<scope>runtime</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>classes</classifier>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- HAPI-FHIR uses Logback for logging support. The logback library is included automatically by Maven as a part of the hapi-fhir-base dependency, but you also need to include a logging library. Logback
|
||||
is used here, but log4j would also be fine. -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Needed for JEE/Servlet support -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- If you are using HAPI narrative generation, you will need to include Thymeleaf as well. Otherwise the following can be omitted. -->
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf</groupId>
|
||||
<artifactId>thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Used for CORS support -->
|
||||
<dependency>
|
||||
<groupId>org.ebaysf.web</groupId>
|
||||
<artifactId>cors-filter</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<groupId>javax.servlet</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Web is used to deploy the server to a web container. -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- You may not need this if you are deploying to an application server which provides database connection pools itself. -->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-dbcp2</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- This example uses Derby embedded database. If you are using another database such as Mysql or Oracle, you may omit the following dependencies and replace them with an appropriate database client
|
||||
dependency for your database platform. -->
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derby</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbynet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.derby</groupId>
|
||||
<artifactId>derbyclient</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.phloc</groupId>
|
||||
<artifactId>phloc-schematron</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>Saxon-HE</artifactId>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
For some reason JavaDoc crashed during site generation unless we have this dependency
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>javax.interceptor</groupId>
|
||||
<artifactId>javax.interceptor-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
<version>42.1.4</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver-dynamic.war -->
|
||||
<finalName>hapi-fhir-jpaserver-dynamic</finalName>
|
||||
|
||||
<!-- The following is not required for the application to build, but allows you to test it by issuing "mvn jetty:run" from the command line. -->
|
||||
<!-- <pluginManagement>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<webApp>
|
||||
<contextPath>/hapi-fhir-jpaserver-dynamic</contextPath>
|
||||
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
|
||||
</webApp>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement> -->
|
||||
|
||||
<plugins>
|
||||
<!-- Tell Maven which Java source version you want to use -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- The configuration here tells the WAR plugin to include the FHIR Tester overlay. You can omit it if you are not using that feature. -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Build-Time>${maven.build.timestamp}</Build-Time>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<overlays>
|
||||
<overlay>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
|
||||
</overlay>
|
||||
</overlays>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
|
||||
<!-- <webXml>src/main/webapp/WEB-INF/web.xml</webXml> -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- This plugin is just a part of the HAPI internal build process, you do not need to incude it in your own projects -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- This is to run the integration tests -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<configuration>
|
||||
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>integration-test</goal>
|
||||
<goal>verify</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- for Heroku deployment -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals><goal>copy</goal></goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>com.github.jsimone</groupId>
|
||||
<artifactId>webapp-runner-main</artifactId>
|
||||
<version>8.5.23.1</version>
|
||||
<destFileName>webapp-runner.jar</destFileName>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!--<plugin>
|
||||
<groupId>com.heroku.sdk</groupId>
|
||||
<artifactId>heroku-maven-plugin</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</plugin>-->
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,106 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.PropertySources;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
/**
|
||||
* This is the primary configuration file for the dynamic jpa server running with dstu3 version.
|
||||
* It will load 2 property files: <br>
|
||||
* <i>config/dstu3/immutable.properties</i> and <i>config/dstu3/app_${ENV}.properties</i> <br>
|
||||
* where <b>${ENV}</b> is an environment variable named <b>ENV</b> which should be set to one of the strings:
|
||||
* <i>local, dev, stg or prod</i>.
|
||||
*
|
||||
* By default it will be set to <i>local</i>, so <b>config/dstu3/app_local.properties</b> file will be loaded.
|
||||
* It expects properties to be exposed either as as environment variables or through property files. Note that environment variable take precedence over
|
||||
* property files.
|
||||
* <ul>
|
||||
* <li><b>ENV</b> - default value set to <i>"local"</i>. Can be set to <i>"local"</i>, <i>"dev"</i>, <i>"stg"</i> or <i>"prod"</i>.</li>
|
||||
* <li><b>DB_URL</b> - database url, can be exposed either as environment variable or in environment specific property file, e.g. app_local.properties</li>
|
||||
* <li><b>DATABASE_URL</b> - this url will be set by Heroku as a db url, if it's set, it'll overwrite db settings set with
|
||||
* <b>DB_URL</b></li>
|
||||
* <li><b>HIBERNATE_CREATE</b> - if set to <b>true</b>, hibernate will drop and recreate schema, if set to <b>false</b>,
|
||||
* will validate the schema
|
||||
* <li><b>SCHEMA_NAME</b> - if set, schema name will be used in the database url, used only when <b>DATABASE_URL</b> is set.
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
@PropertySources({
|
||||
@PropertySource("classpath:config/dstu3/immutable.properties"),
|
||||
@PropertySource("classpath:config/dstu3/app_${ENV:local}.properties") })
|
||||
public class FhirServerConfig extends BaseJavaConfigDstu3 {
|
||||
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FhirServerConfig.class);
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
/**
|
||||
* Configure FHIR properties around the the JPA server via this bean
|
||||
*/
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
return FhirServerConfigCommon.getDaoConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
|
||||
* directory called "jpaserver_derby_files".
|
||||
*
|
||||
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
|
||||
*/
|
||||
@Bean(destroyMethod = "close")
|
||||
public DataSource dataSource() {
|
||||
return FhirServerConfigCommon.getDataSource(env);
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
return FhirServerConfigCommon.getEntityManagerFactory(env, dataSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||
*/
|
||||
public IServerInterceptor loggingInterceptor() {
|
||||
return FhirServerConfigCommon.loggingInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
|
||||
*/
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IServerInterceptor responseHighlighterInterceptor() {
|
||||
return FhirServerConfigCommon.getResponseHighlighterInterceptor();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IServerInterceptor subscriptionSecurityInterceptor() {
|
||||
String stuVersion = (env.getProperty(Utils.STU_VERSION) == null)?Utils.DSTU3:env.getProperty(Utils.STU_VERSION) ;
|
||||
logger.info("-------STU_VERSION: " + stuVersion);
|
||||
SubscriptionsRequireManualActivationInterceptorDstu3 interceptor = new SubscriptionsRequireManualActivationInterceptorDstu3();
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
return FhirServerConfigCommon.getTransactionManager(entityManagerFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
|
||||
|
||||
/**
|
||||
* Common code for dstu2 and dstu3 classes moved into static methods so that they can be called from version specific class.
|
||||
*
|
||||
* @author anoushmouradian
|
||||
*
|
||||
*/
|
||||
public class FhirServerConfigCommon {
|
||||
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class);
|
||||
|
||||
/**
|
||||
* Configure FHIR properties around the the JPA server via this bean
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static DaoConfig getDaoConfig() {
|
||||
DaoConfig daoConfig = new DaoConfig();
|
||||
daoConfig.setSubscriptionEnabled(true);
|
||||
daoConfig.setSubscriptionPollDelay(5000);
|
||||
daoConfig.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
|
||||
daoConfig.setAllowMultipleDelete(true);
|
||||
return daoConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
|
||||
* directory called "jpaserver_derby_files".
|
||||
*
|
||||
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
|
||||
*/
|
||||
public static DataSource getDataSource(Environment env) {
|
||||
String dbUrl = (env.getProperty(Utils.DB_URL) != null)?env.getProperty(Utils.DB_URL).toLowerCase():"";
|
||||
String herokuDbUrl = env.getProperty(Utils.HEROKU_DATABASE_URL);
|
||||
|
||||
if(herokuDbUrl != null) {
|
||||
// url will come as: postgres://user:pass@host:5432/dbname
|
||||
String fromUserName = herokuDbUrl.substring(herokuDbUrl.indexOf("//") + 2);
|
||||
String userName = fromUserName.substring(0, fromUserName.indexOf(":"));
|
||||
String pass = fromUserName.substring(fromUserName.indexOf(":") +1, fromUserName.indexOf("@"));
|
||||
String fromHost = fromUserName.substring(fromUserName.indexOf("@")+1);
|
||||
String schemaName = env.getProperty(Utils.SCHEMA_NAME);
|
||||
|
||||
//build this url: jdbc:postgresql://host:5432/dbName?user=username&password=pass¤tSchema='
|
||||
dbUrl = "jdbc:postgresql://" + fromHost + "?user=" + userName + "&password=" + pass + "&sslmode=require";
|
||||
if(schemaName != null) {
|
||||
dbUrl += "¤tSchema=" + schemaName;
|
||||
}
|
||||
logger.info("------DB Url: " + dbUrl);
|
||||
}
|
||||
BasicDataSource dataSource = new BasicDataSource();
|
||||
try {
|
||||
if(dbUrl.indexOf("mysql") > -1 ) {
|
||||
dataSource.setDriver(new com.mysql.jdbc.Driver());
|
||||
} else if(dbUrl.indexOf("postgres") > -1) {
|
||||
dataSource.setDriver(new org.postgresql.Driver());
|
||||
} else if(dbUrl.indexOf("derby") > -1) {
|
||||
dataSource.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
logger.error("----FhiServerConfigCommon: getDataSource: setting driver error: " + e.getMessage());
|
||||
}
|
||||
dataSource.setUrl(dbUrl);
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
public static LocalContainerEntityManagerFactoryBean getEntityManagerFactory(Environment env, DataSource dataSource) {
|
||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
||||
retVal.setPersistenceUnitName("HAPI_PU");
|
||||
retVal.setDataSource(dataSource);
|
||||
|
||||
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
|
||||
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
|
||||
retVal.setJpaProperties(jpaProperties(env));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||
*/
|
||||
public static IServerInterceptor loggingInterceptor() {
|
||||
LoggingInterceptor retVal = new LoggingInterceptor();
|
||||
retVal.setLoggerName("fhirtest.access");
|
||||
retVal.setMessageFormat(
|
||||
"Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
|
||||
retVal.setLogExceptions(true);
|
||||
retVal.setErrorMessageFormat("ERROR - ${requestVerb} ${requestUrl}");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
|
||||
*/
|
||||
public static IServerInterceptor getResponseHighlighterInterceptor() {
|
||||
ResponseHighlighterInterceptor retVal = new ResponseHighlighterInterceptor();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static JpaTransactionManager getTransactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private static Properties jpaProperties(Environment env) {
|
||||
Properties extraProperties = new Properties();
|
||||
String dbUrl = (env.getProperty(Utils.HEROKU_DATABASE_URL) == null)?env.getProperty(Utils.DB_URL):env.getProperty(Utils.HEROKU_DATABASE_URL);
|
||||
if(dbUrl != null && dbUrl.indexOf("mysql") > -1) {
|
||||
extraProperties.put("hibernate.dialect", org.hibernate.dialect.MySQL5Dialect.class.getName());
|
||||
extraProperties.put("hibernate.dialect.storage_engine","innodb");
|
||||
}
|
||||
else if(dbUrl != null && dbUrl.indexOf("postgres") > -1) {
|
||||
extraProperties.put("hibernate.dialect", org.hibernate.dialect.PostgreSQL9Dialect.class.getName());
|
||||
}
|
||||
else if(dbUrl != null && dbUrl.indexOf("derby") > -1) {
|
||||
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
|
||||
}
|
||||
boolean hibernateCreate = new Boolean(env.getProperty(Utils.HIBERNATE_CREATE));
|
||||
logger.info("------DB hibernateCreate: " + hibernateCreate);
|
||||
if(hibernateCreate){
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "create");
|
||||
} else {
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "validate");
|
||||
}
|
||||
extraProperties.put("hibernate.format_sql", "true");
|
||||
extraProperties.put("hibernate.show_sql", "false");
|
||||
|
||||
extraProperties.put("hibernate.jdbc.batch_size", "20");
|
||||
extraProperties.put("hibernate.cache.use_query_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.autoregister_listeners", "false");
|
||||
extraProperties.put("hibernate.search.default.indexBase", "./target/lucenefiles");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
extraProperties.put("hibernate.search.indexing_strategy", "manual");
|
||||
extraProperties.put("hibernate.search.default.worker.execution", "async");
|
||||
|
||||
return extraProperties;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.PropertySources;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
|
||||
/**
|
||||
* This is the primary configuration file for the dynamic jpa server running with dstu2 version.
|
||||
* It will load 2 property files: <br>
|
||||
* <i>config/dstu2/immutable.properties</i> and <i>config/dstu2/app_${ENV}.properties</i> <br>
|
||||
* where <b>${ENV}</b> is an environment variable named <b>ENV</b> which should be set to one of the strings:
|
||||
* <i>local, dev, stg or prod</i>.
|
||||
*
|
||||
* By default it will be set to <i>local</i>, so <b>config/dstu2/app_local.properties</b> file will be loaded.
|
||||
* It expects properties to be exposed either as as environment variables or through property files. Note that environment variable take precedence over
|
||||
* property files.
|
||||
* <ul>
|
||||
* <li><b>ENV</b> - default value set to <i>"local"</i>. Can be set to <i>"local"</i>, <i>"dev"</i>, <i>"stg"</i> or <i>"prod"</i>.</li>
|
||||
* <li><b>DB_URL</b> - database url, can be exposed either as environment variable or in environment specific property file, e.g. app_local.properties</li>
|
||||
* <li><b>DATABASE_URL</b> - this url will be set by Heroku as a db url, if it's set, it'll overwrite db settings set with
|
||||
* <b>DB_URL</b></li>
|
||||
* <li><b>HIBERNATE_CREATE</b> - if set to <b>true</b>, hibernate will drop and recreate schema, if set to <b>false</b>,
|
||||
* will validate the schema
|
||||
* <li><b>SCHEMA_NAME</b> - if set, schema name will be used in the database url, used only when <b>DATABASE_URL</b> is set.
|
||||
* </ul>
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
@PropertySources({
|
||||
@PropertySource("classpath:config/dstu2/immutable.properties"),
|
||||
@PropertySource("classpath:config/dstu2/app_${ENV:local}.properties") })
|
||||
public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FhirServerConfigDstu2.class);
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
/**
|
||||
* Configure FHIR properties around the the JPA server via this bean
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
return FhirServerConfigCommon.getDaoConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
|
||||
* directory called "jpaserver_derby_files".
|
||||
*
|
||||
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
|
||||
*/
|
||||
@Bean(destroyMethod = "close")
|
||||
public DataSource dataSource() {
|
||||
return FhirServerConfigCommon.getDataSource(env);
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
return FhirServerConfigCommon.getEntityManagerFactory(env, dataSource());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||
*/
|
||||
public IServerInterceptor loggingInterceptor() {
|
||||
return FhirServerConfigCommon.loggingInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
|
||||
*/
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IServerInterceptor responseHighlighterInterceptor() {
|
||||
return FhirServerConfigCommon.getResponseHighlighterInterceptor();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IServerInterceptor subscriptionSecurityInterceptor() {
|
||||
String stuVersion = (env.getProperty(Utils.STU_VERSION) == null)?Utils.DSTU2:env.getProperty(Utils.STU_VERSION) ;
|
||||
logger.info("-------STU_VERSION: " + stuVersion);
|
||||
SubscriptionsRequireManualActivationInterceptorDstu2 interceptor = new SubscriptionsRequireManualActivationInterceptorDstu2();
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
return FhirServerConfigCommon.getTransactionManager(entityManagerFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.PropertySources;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.to.FhirTesterMvcConfig;
|
||||
import ca.uhn.fhir.to.TesterConfig;
|
||||
|
||||
//@formatter:off
|
||||
/**
|
||||
* This spring config file configures the web testing module. It serves two
|
||||
* purposes:
|
||||
* 1. It imports FhirTesterMvcConfig, which is the spring config for the
|
||||
* tester itself
|
||||
* 2. It tells the tester which server(s) to talk to, via the testerConfig()
|
||||
* method below.<br>
|
||||
* It will also load properties defined in <b>config/dstu3/immutable.properties</b> file.
|
||||
*/
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource("classpath:config/dstu3/immutable.properties") })
|
||||
@Import(FhirTesterMvcConfig.class)
|
||||
public class FhirTesterConfig {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
/**
|
||||
* This bean tells the testing webpage which servers it should configure itself
|
||||
* to communicate with. In this example we configure it to talk to the local
|
||||
* server, as well as one public server. If you are creating a project to
|
||||
* deploy somewhere else, you might choose to only put your own server's
|
||||
* address here.
|
||||
*
|
||||
* Note the use of the ${serverBase} variable below. This will be replaced with
|
||||
* the base URL as reported by the server itself. Often for a simple Tomcat
|
||||
* (or other container) installation, this will end up being something
|
||||
* like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are
|
||||
* deploying your server to a place with a fully qualified domain name,
|
||||
* you might want to use that instead of using the variable.
|
||||
*/
|
||||
@Bean
|
||||
public TesterConfig testerConfig() {
|
||||
TesterConfig retVal = new TesterConfig();
|
||||
String baseFhirMapping = env.getProperty(Utils.BASE_FHIR_MAPPING);
|
||||
baseFhirMapping = (baseFhirMapping == null)?"fhir":baseFhirMapping;
|
||||
retVal
|
||||
.addServer()
|
||||
.withId("home")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU3)
|
||||
.withBaseUrl("${serverBase}/" + baseFhirMapping)
|
||||
.withName("Local Tester")
|
||||
.addServer()
|
||||
.withId("hapi")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU3)
|
||||
.withBaseUrl("http://fhirtest.uhn.ca/" + baseFhirMapping)
|
||||
.withName("Public HAPI Test Server");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
//@formatter:on
|
|
@ -0,0 +1,71 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.to.FhirTesterMvcConfig;
|
||||
import ca.uhn.fhir.to.TesterConfig;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.PropertySources;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
//@formatter:off
|
||||
|
||||
/**
|
||||
* This spring config file configures the web testing module. It serves two
|
||||
* purposes:
|
||||
* 1. It imports FhirTesterMvcConfig, which is the spring config for the
|
||||
* tester itself
|
||||
* 2. It tells the tester which server(s) to talk to, via the testerConfig()
|
||||
* method below<br>
|
||||
* It will also load properties defined in <b>config/dstu2/immutable.properties</b> file.
|
||||
*/
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource("classpath:config/dstu2/immutable.properties") })
|
||||
@Import(FhirTesterMvcConfig.class)
|
||||
public class FhirTesterConfigDstu2 {
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(FhirTesterConfigDstu2.class);
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
/**
|
||||
* This bean tells the testing webpage which servers it should configure itself
|
||||
* to communicate with. In this example we configure it to talk to the local
|
||||
* server, as well as one public server. If you are creating a project to
|
||||
* deploy somewhere else, you might choose to only put your own server's
|
||||
* address here.
|
||||
*
|
||||
* Note the use of the ${serverBase} variable below. This will be replaced with
|
||||
* the base URL as reported by the server itself. Often for a simple Tomcat
|
||||
* (or other container) installation, this will end up being something
|
||||
* like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are
|
||||
* deploying your server to a place with a fully qualified domain name,
|
||||
* you might want to use that instead of using the variable.
|
||||
*/
|
||||
@Bean
|
||||
public TesterConfig testerConfig() {
|
||||
logger.info("-------FhirTesterConfigDstu2:" + "testerConfig");
|
||||
TesterConfig retVal = new TesterConfig();
|
||||
String baseFhirMapping = env.getProperty(Utils.BASE_FHIR_MAPPING);
|
||||
baseFhirMapping = (baseFhirMapping == null)?"fhir":baseFhirMapping;
|
||||
retVal
|
||||
.addServer()
|
||||
.withId("home")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU2)
|
||||
.withBaseUrl("${serverBase}/" + baseFhirMapping)
|
||||
.withName("Local Tester")
|
||||
.addServer()
|
||||
.withId("hapi")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU2)
|
||||
.withBaseUrl("http://fhirtest.uhn.ca/" + baseFhirMapping)
|
||||
.withName("Public HAPI Test Server");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
//@formatter:on
|
|
@ -0,0 +1,64 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
/**
|
||||
* Load immutable properties from /resources/config/<STU_VERSION>/immutable.properties file. STU_VERSION environment variable can be set to dstu2 or dstu3, which will translate to the
|
||||
* file path, e.g.: /resources/config/immutable/dstu3/immutable.properties
|
||||
* By default it'll set path to dstu3.
|
||||
*
|
||||
* @author anoushmouradian
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
@PropertySource("classpath:config/${STU_VERSION:dstu3}/immutable.properties")
|
||||
public class ImmutablePropertiesConfig {
|
||||
|
||||
@Value("${FHIR_VERSION}")
|
||||
private String fhirVersion;
|
||||
@Value("${fhirServerConfigClass}")
|
||||
private String fhirServerConfigClass;
|
||||
@Value("${fhirTesterConfigClass}")
|
||||
private String fhirTesterConfigClass;
|
||||
@Value("${jpaDemoClass}")
|
||||
private String jpaDemoClass;
|
||||
@Value("${jpaDemoMapping}")
|
||||
private String jpaDemoMapping;
|
||||
|
||||
|
||||
public String getFhirVersion() {
|
||||
return fhirVersion;
|
||||
}
|
||||
public void setFhirVersion(String fhirVersion) {
|
||||
this.fhirVersion = fhirVersion;
|
||||
}
|
||||
public String getFhirServerConfigClass() {
|
||||
return fhirServerConfigClass;
|
||||
}
|
||||
public void setFhirServerConfigClass(String fhirServerConfigClass) {
|
||||
this.fhirServerConfigClass = fhirServerConfigClass;
|
||||
}
|
||||
public String getFhirTesterConfigClass() {
|
||||
return fhirTesterConfigClass;
|
||||
}
|
||||
public void setFhirTesterConfigClass(String fhirTesterConfigClass) {
|
||||
this.fhirTesterConfigClass = fhirTesterConfigClass;
|
||||
}
|
||||
public String getJpaDemoClass() {
|
||||
return jpaDemoClass;
|
||||
}
|
||||
public void setJpaDemoClass(String jpaDemoClass) {
|
||||
this.jpaDemoClass = jpaDemoClass;
|
||||
}
|
||||
public String getJpaDemoMapping() {
|
||||
return jpaDemoMapping;
|
||||
}
|
||||
public void setJpaDemoMapping(String jpaDemoMapping) {
|
||||
this.jpaDemoMapping = jpaDemoMapping;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Meta;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
public class JpaServerDemo extends RestfulServer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private WebApplicationContext myAppCtx;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
/*
|
||||
* We want to support FHIR DSTU2 format. This means that the server
|
||||
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
|
||||
*
|
||||
* If you want to use DSTU1 instead, change the following line, and change the 2 occurrences of dstu2 in web.xml to dstu1
|
||||
*/
|
||||
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU3;
|
||||
setFhirContext(new FhirContext(fhirVersion));
|
||||
|
||||
// Get the spring context from the web container (it's declared in web.xml)
|
||||
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
||||
|
||||
/*
|
||||
* The BaseJavaConfigDstu2.java class is a spring configuration
|
||||
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
|
||||
* contains bean definitions for a resource provider for each resource type
|
||||
*/
|
||||
String resourceProviderBeanName;
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu2";
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu3";
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
|
||||
setResourceProviders(beans);
|
||||
|
||||
/*
|
||||
* The system provider implements non-resource-type methods, such as
|
||||
* transaction, and global history.
|
||||
*/
|
||||
Object systemProvider;
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
setPlainProviders(systemProvider);
|
||||
|
||||
/*
|
||||
* The conformance provider exports the supported resources, search parameters, etc for
|
||||
* this server. The JPA version adds resource counts to the exported statement, so it
|
||||
* is a nice addition.
|
||||
*/
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao,
|
||||
myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao,
|
||||
myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable ETag Support (this is already the default)
|
||||
*/
|
||||
setETagSupport(ETagSupportEnum.ENABLED);
|
||||
|
||||
/*
|
||||
* This server tries to dynamically generate narratives
|
||||
*/
|
||||
FhirContext ctx = getFhirContext();
|
||||
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
/*
|
||||
* Default to JSON and pretty printing
|
||||
*/
|
||||
setDefaultPrettyPrint(true);
|
||||
setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
/*
|
||||
* -- New in HAPI FHIR 1.5 --
|
||||
* This configures the server to page search results to and from
|
||||
* the database, instead of only paging them to memory. This may mean
|
||||
* a performance hit when performing searches that return lots of results,
|
||||
* but makes the server much more scalable.
|
||||
*/
|
||||
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
/*
|
||||
* Load interceptors for the server from Spring (these are defined in FhirServerConfig.java)
|
||||
*/
|
||||
Collection<IServerInterceptor> interceptorBeans = myAppCtx.getBeansOfType(IServerInterceptor.class).values();
|
||||
for (IServerInterceptor interceptor : interceptorBeans) {
|
||||
this.registerInterceptor(interceptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* If you are hosting this server at a specific DNS name, the server will try to
|
||||
* figure out the FHIR base URL based on what the web container tells it, but
|
||||
* this doesn't always work. If you are setting links in your search bundles that
|
||||
* just refer to "localhost", you might want to use a server address strategy:
|
||||
*/
|
||||
//setServerAddressStrategy(new HardcodedServerAddressStrategy("http://mydomain.com/fhir/baseDstu2"));
|
||||
|
||||
/*
|
||||
* If you are using DSTU3+, you may want to add a terminology uploader, which allows
|
||||
* uploading of external terminologies such as Snomed CT. Note that this uploader
|
||||
* does not have any security attached (any anonymous user may use it by default)
|
||||
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
||||
* with this feature.
|
||||
*/
|
||||
//if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
// registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Meta;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
public class JpaServerDemoDstu2 extends RestfulServer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private WebApplicationContext myAppCtx;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
/*
|
||||
* We want to support FHIR DSTU2 format. This means that the server
|
||||
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
|
||||
*
|
||||
* If you want to use DSTU1 instead, change the following line, and change the 2 occurrences of dstu2 in web.xml to dstu1
|
||||
*/
|
||||
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU2;
|
||||
setFhirContext(new FhirContext(fhirVersion));
|
||||
|
||||
// Get the spring context from the web container (it's declared in web.xml)
|
||||
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
||||
|
||||
/*
|
||||
* The BaseJavaConfigDstu2.java class is a spring configuration
|
||||
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
|
||||
* contains bean definitions for a resource provider for each resource type
|
||||
*/
|
||||
String resourceProviderBeanName;
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu2";
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu3";
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
|
||||
setResourceProviders(beans);
|
||||
|
||||
/*
|
||||
* The system provider implements non-resource-type methods, such as
|
||||
* transaction, and global history.
|
||||
*/
|
||||
Object systemProvider;
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
setPlainProviders(systemProvider);
|
||||
|
||||
/*
|
||||
* The conformance provider exports the supported resources, search parameters, etc for
|
||||
* this server. The JPA version adds resource counts to the exported statement, so it
|
||||
* is a nice addition.
|
||||
*/
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao,
|
||||
myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao,
|
||||
myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable ETag Support (this is already the default)
|
||||
*/
|
||||
setETagSupport(ETagSupportEnum.ENABLED);
|
||||
|
||||
/*
|
||||
* This server tries to dynamically generate narratives
|
||||
*/
|
||||
FhirContext ctx = getFhirContext();
|
||||
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
/*
|
||||
* Default to JSON and pretty printing
|
||||
*/
|
||||
setDefaultPrettyPrint(true);
|
||||
setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
/*
|
||||
* -- New in HAPI FHIR 1.5 --
|
||||
* This configures the server to page search results to and from
|
||||
* the database, instead of only paging them to memory. This may mean
|
||||
* a performance hit when performing searches that return lots of results,
|
||||
* but makes the server much more scalable.
|
||||
*/
|
||||
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
/*
|
||||
* Load interceptors for the server from Spring (these are defined in FhirServerConfig.java)
|
||||
*/
|
||||
Collection<IServerInterceptor> interceptorBeans = myAppCtx.getBeansOfType(IServerInterceptor.class).values();
|
||||
for (IServerInterceptor interceptor : interceptorBeans) {
|
||||
this.registerInterceptor(interceptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* If you are hosting this server at a specific DNS name, the server will try to
|
||||
* figure out the FHIR base URL based on what the web container tells it, but
|
||||
* this doesn't always work. If you are setting links in your search bundles that
|
||||
* just refer to "localhost", you might want to use a server address strategy:
|
||||
*/
|
||||
//setServerAddressStrategy(new HardcodedServerAddressStrategy("http://mydomain.com/fhir/baseDstu2"));
|
||||
|
||||
/*
|
||||
* If you are using DSTU3+, you may want to add a terminology uploader, which allows
|
||||
* uploading of external terminologies such as Snomed CT. Note that this uploader
|
||||
* does not have any security attached (any anonymous user may use it by default)
|
||||
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
||||
* with this feature.
|
||||
*/
|
||||
//if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
// registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
/**
|
||||
* @author anoushmouradian
|
||||
*
|
||||
*/
|
||||
public class Utils {
|
||||
public static final String HEROKU_DATABASE_URL = "DATABASE_URL";
|
||||
public static final String DB_URL = "DB_URL";
|
||||
public static final String HIBERNATE_CREATE = "HIBERNATE_CREATE";
|
||||
public static final String STU_VERSION = "STU_VERSION";
|
||||
public static final String DSTU2 = "dstu2";
|
||||
public static final String DSTU3 = "dstu3";
|
||||
public static final String SCHEMA_NAME= "SCHEMA_NAME";
|
||||
public static final String BASE_FHIR_MAPPING = "baseFhirMapping";
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.FilterRegistration;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRegistration;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.web.WebApplicationInitializer;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
/**
|
||||
* replace web.xml with Spring web initializer, so that various version specific
|
||||
* classes can be loaded on startup dynamically
|
||||
*
|
||||
* @author anoushmouradian
|
||||
*
|
||||
*/
|
||||
public class WebInitializer implements WebApplicationInitializer {
|
||||
|
||||
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(WebInitializer.class);
|
||||
|
||||
@Override
|
||||
public void onStartup(ServletContext container) throws ServletException {
|
||||
|
||||
ConfigurableApplicationContext propContext = new AnnotationConfigApplicationContext(ImmutablePropertiesConfig.class);
|
||||
ImmutablePropertiesConfig props = propContext.getBean(ImmutablePropertiesConfig.class);
|
||||
logger.info("This is FHIR_VERSION: " + props.getFhirVersion());
|
||||
propContext.close();
|
||||
|
||||
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
|
||||
context.setConfigLocation(props.getFhirServerConfigClass());
|
||||
|
||||
container.addListener(new ContextLoaderListener(context));
|
||||
context.close();
|
||||
|
||||
AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();
|
||||
dispatcherContext.setConfigLocation(props.getFhirTesterConfigClass());
|
||||
ServletRegistration.Dynamic springDispatcher = container.addServlet("spring", new DispatcherServlet(dispatcherContext));
|
||||
springDispatcher.setLoadOnStartup(2);
|
||||
springDispatcher.addMapping("/");
|
||||
dispatcherContext.close();
|
||||
|
||||
ServletRegistration.Dynamic fhirServlet = container.addServlet("fhirServlet", props.getJpaDemoClass());
|
||||
fhirServlet.setInitParameter("ImplementationDescription", "FHIR JPA Server");
|
||||
fhirServlet.setInitParameter("FhirVersion", props.getFhirVersion());
|
||||
fhirServlet.setLoadOnStartup(1);
|
||||
fhirServlet.addMapping(props.getJpaDemoMapping());
|
||||
|
||||
FilterRegistration.Dynamic corsFilter = container.addFilter("CORS Filter", "org.ebaysf.web.cors.CORSFilter");
|
||||
corsFilter.addMappingForUrlPatterns(null, false, "/*");
|
||||
Map<String, String> corsMap = Collections.unmodifiableMap(new HashMap<String, String>() {
|
||||
{
|
||||
put("cors.allowed.origins", "*");
|
||||
put("cors.allowed.methods", "GET,POST,PUT,DELETE,OPTIONS");
|
||||
put("cors.allowed.headers",
|
||||
"X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers");
|
||||
put("cors.exposed.headers", "Location,Content-Location");
|
||||
put("cors.support.credentials", "true");
|
||||
put("cors.logging.enabled", "true");
|
||||
put("cors.preflight.maxage", "300");
|
||||
}
|
||||
});
|
||||
corsFilter.setInitParameters(corsMap);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://<host>:5432/<dbName>?user=<username>&password=<password>&sslmode=require
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://localhost:5432/<dbName>?user=<username>&password=<password>
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://<host>:5432/<dbName>?user=<username>&password=<password>&sslmode=require
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://<host>:5432/<dbName>?user=<username>&password=<password>&sslmode=require
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,6 @@
|
|||
FHIR_VERSION=DSTU2
|
||||
fhirServerConfigClass=ca.uhn.fhir.jpa.demo.FhirServerConfigDstu2
|
||||
fhirTesterConfigClass=ca.uhn.fhir.jpa.demo.FhirTesterConfigDstu2
|
||||
jpaDemoClass=ca.uhn.fhir.jpa.demo.JpaServerDemoDstu2
|
||||
jpaDemoMapping=/fhir/*
|
||||
baseFhirMapping=fhir
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://<host>:5432/<dbName>?user=<username>&password=<password>&sslmode=require
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://localhost:5432/<dbName>?user=<username>&password=<password>
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://<host>:5432/<dbName>?user=<username>&password=<password>&sslmode=require
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,2 @@
|
|||
#DB_URL=jdbc:postgresql://<host>:5432/<dbName>?user=<username>&password=<password>&sslmode=require
|
||||
HIBERNATE_CREATE=false
|
|
@ -0,0 +1,6 @@
|
|||
FHIR_VERSION=DSTU3
|
||||
fhirServerConfigClass=ca.uhn.fhir.jpa.demo.FhirServerConfig
|
||||
fhirTesterConfigClass=ca.uhn.fhir.jpa.demo.FhirTesterConfig
|
||||
jpaDemoClass=ca.uhn.fhir.jpa.demo.JpaServerDemo
|
||||
jpaDemoMapping=/fhir/*
|
||||
baseFhirMapping=fhir
|
|
@ -0,0 +1,16 @@
|
|||
<configuration scan="true" scanPeriod="30 seconds">
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>ERROR</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="ERROR">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,67 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head th:include="tmpl-head :: head">
|
||||
<title>About This Server</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<form action="" method="get" id="outerForm">
|
||||
<div th:replace="tmpl-navbar-top :: top" ></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div th:replace="tmpl-navbar-left :: left" ></div>
|
||||
|
||||
<div class="col-sm-9 col-sm-offset-3 col-md-9 col-md-offset-3 main">
|
||||
|
||||
<div th:replace="tmpl-banner :: banner"></div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">About This Server</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="pull-right">
|
||||
<object data="img/fhirtest-architecture.svg" width="383" height="369" type="image/svg+xml"></object>
|
||||
</div>
|
||||
<p>
|
||||
This server provides a nearly complete implementation of the FHIR Specification
|
||||
using a 100% open source software stack. It is hosted by University Health Network.
|
||||
</p>
|
||||
<p>
|
||||
The architecture in use here is shown in the image on the right. This server is built
|
||||
from a number of modules of the
|
||||
<a href="https://github.com/jamesagnew/hapi-fhir/">HAPI FHIR</a>
|
||||
project, which is a 100% open-source (Apache 2.0 Licensed) Java based
|
||||
implementation of the FHIR specification.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">Data On This Server</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<p>
|
||||
This server is regularly loaded with a standard set of test data sourced
|
||||
from UHN's own testing environment. Do not use this server to store any data
|
||||
that you will need later, as we will be regularly resetting it.
|
||||
</p>
|
||||
<p>
|
||||
This is not a production server and it provides no privacy. Do not store any
|
||||
confidential data here.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div th:replace="tmpl-footer :: footer" ></div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,16 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<div th:fragment="footer">
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-1395874-6', 'auto');
|
||||
ga('require', 'displayfeatures');
|
||||
ga('require', 'linkid', 'linkid.js');
|
||||
ga('send', 'pageview');
|
||||
</script>
|
||||
</div>
|
||||
</html>
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<div th:fragment="banner" class="well">
|
||||
<th:block th:if="${serverId} == 'home'">
|
||||
<p>
|
||||
This is the home for the FHIR test server operated by
|
||||
<a href="http://uhn.ca">University Health Network</a>. This server
|
||||
(and the testing application you are currently using to access it)
|
||||
is entirely built using
|
||||
<a href="https://github.com/jamesagnew/hapi-fhir">HAPI-FHIR</a>,
|
||||
a 100% open-source Java implementation of the
|
||||
<a href="http://hl7.org/implement/standards/fhir/">FHIR specification</a>.
|
||||
</p>
|
||||
<p>
|
||||
Here are some things you might wish to try:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
View a
|
||||
<a href="http://fhirtest.uhn.ca/search?serverId=home&encoding=json&pretty=true&resource=Patient&param.0.type=string&param.0.name=_id&param.0.0=&resource-search-limit=">list of patients</a>
|
||||
on this server.
|
||||
</li>
|
||||
<li>
|
||||
Construct a
|
||||
<a href="http://fhirtest.uhn.ca/resource?serverId=home&encoding=json&pretty=true&resource=Patient">search query</a>
|
||||
on this server.
|
||||
</li>
|
||||
<li>
|
||||
Access a
|
||||
<a href="http://fhirtest.uhn.ca/home?serverId=furore">different server</a>
|
||||
(use the <b>Server</b> menu at the top of the page to see a list of public FHIR servers)
|
||||
</li>
|
||||
</ul>
|
||||
</th:block>
|
||||
<th:block th:if="${serverId} != 'home'">
|
||||
<p>
|
||||
You are accessing the public FHIR server
|
||||
<b th:text="${baseName}"/>. This server is hosted elsewhere on the internet
|
||||
but is being accessed using the HAPI client implementation.
|
||||
</p>
|
||||
</th:block>
|
||||
<p>
|
||||
<b style="color: red;">
|
||||
<span class="glyphicon glyphicon-warning-sign"/>
|
||||
This is not a production server!
|
||||
</b>
|
||||
Do not store any information here that contains personal health information
|
||||
or any other confidential information. This server will be regularly purged
|
||||
and reloaded with fixed test data.
|
||||
</p>
|
||||
</div>
|
||||
</html>
|
|
@ -0,0 +1,106 @@
|
|||
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<context-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>
|
||||
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
</param-value>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfigDstu2
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- Servlets -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfigDstu2</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<servlet-class>ca.uhn.fhir.jpa.demo.JpaServerDemoDstu2</servlet-class>
|
||||
<init-param>
|
||||
<param-name>ImplementationDescription</param-name>
|
||||
<param-value>FHIR JPA Server</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>FhirVersion</param-name>
|
||||
<param-value>DSTU2</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/baseDstu2/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
|
||||
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||
<filter>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<filter-class>org.ebaysf.web.cors.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</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>
|
||||
</web-app>
|
|
@ -0,0 +1,108 @@
|
|||
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<context-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>
|
||||
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
</param-value>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfig
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- Servlets -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfig</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<servlet-class>ca.uhn.fhir.jpa.demo.JpaServerDemo</servlet-class>
|
||||
<init-param>
|
||||
<param-name>ImplementationDescription</param-name>
|
||||
<param-value>FHIR JPA Server</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>FhirVersion</param-name>
|
||||
<param-value>DSTU3</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/baseDstu3/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
|
||||
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||
<filter>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<filter-class>org.ebaysf.web.cors.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</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>
|
||||
|
||||
|
||||
</web-app>
|
|
@ -0,0 +1,106 @@
|
|||
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<context-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>
|
||||
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
|
||||
</param-value>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfigDstu2
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- Servlets -->
|
||||
|
||||
<servlet>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfigDstu2</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<servlet-class>ca.uhn.fhir.jpa.demo.JpaServerDemoDstu2</servlet-class>
|
||||
<init-param>
|
||||
<param-name>ImplementationDescription</param-name>
|
||||
<param-value>FHIR JPA Server</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>FhirVersion</param-name>
|
||||
<param-value>DSTU2</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/baseDstu2/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
|
||||
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||
<filter>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<filter-class>org.ebaysf.web.cors.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</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>
|
||||
</web-app>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,389 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified"
|
||||
version="2.2">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
||||
|
||||
Copyright 2003-2009 Sun Microsystems, Inc. All rights reserved.
|
||||
|
||||
The contents of this file are subject to the terms of either the
|
||||
GNU General Public License Version 2 only ("GPL") or the Common
|
||||
Development and Distribution License("CDDL") (collectively, the
|
||||
"License"). You may not use this file except in compliance with
|
||||
the License. You can obtain a copy of the License at
|
||||
https://glassfish.dev.java.net/public/CDDL+GPL.html or
|
||||
glassfish/bootstrap/legal/LICENSE.txt. See the License for the
|
||||
specific language governing permissions and limitations under the
|
||||
License.
|
||||
|
||||
When distributing the software, include this License Header
|
||||
Notice in each file and include the License file at
|
||||
glassfish/bootstrap/legal/LICENSE.txt. Sun designates this
|
||||
particular file as subject to the "Classpath" exception as
|
||||
provided by Sun in the GPL Version 2 section of the License file
|
||||
that accompanied this code. If applicable, add the following
|
||||
below the License Header, with the fields enclosed by brackets []
|
||||
replaced by your own identifying information:
|
||||
"Portions Copyrighted [year] [name of copyright owner]"
|
||||
|
||||
Contributor(s):
|
||||
|
||||
If you wish your version of this file to be governed by only the
|
||||
CDDL or only the GPL Version 2, indicate your decision by adding
|
||||
"[Contributor] elects to include this software in this
|
||||
distribution under the [CDDL or GPL Version 2] license." If you
|
||||
don't indicate a single choice of license, a recipient has the
|
||||
option to distribute your version of this file under either the
|
||||
CDDL, the GPL Version 2 or to extend the choice of license to its
|
||||
licensees as provided above. However, if you add GPL Version 2
|
||||
code and therefore, elected the GPL Version 2 license, then the
|
||||
option applies only if the new code is made subject to such
|
||||
option by the copyright holder.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
This is the XML Schema for the JSP 2.2 deployment descriptor
|
||||
types. The JSP 2.2 schema contains all the special
|
||||
structures and datatypes that are necessary to use JSP files
|
||||
from a web application.
|
||||
|
||||
The contents of this schema is used by the web-common_3_0.xsd
|
||||
file to define JSP specific content.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The following conventions apply to all Java EE
|
||||
deployment descriptor elements unless indicated otherwise.
|
||||
|
||||
- In elements that specify a pathname to a file within the
|
||||
same JAR file, relative filenames (i.e., those not
|
||||
starting with "/") are considered relative to the root of
|
||||
the JAR file's namespace. Absolute filenames (i.e., those
|
||||
starting with "/") also specify names in the root of the
|
||||
JAR file's namespace. In general, relative names are
|
||||
preferred. The exception is .war files where absolute
|
||||
names are preferred for consistency with the Servlet API.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:include schemaLocation="javaee_6.xsd"/>
|
||||
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:complexType name="jsp-configType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The jsp-configType is used to provide global configuration
|
||||
information for the JSP files in a web application. It has
|
||||
two subelements, taglib and jsp-property-group.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="taglib"
|
||||
type="javaee:taglibType"
|
||||
minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xsd:element name="jsp-property-group"
|
||||
type="javaee:jsp-property-groupType"
|
||||
minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id"
|
||||
type="xsd:ID"/>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:complexType name="jsp-fileType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The jsp-file element contains the full path to a JSP file
|
||||
within the web application beginning with a `/'.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleContent>
|
||||
<xsd:restriction base="javaee:pathType"/>
|
||||
</xsd:simpleContent>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:complexType name="jsp-property-groupType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The jsp-property-groupType is used to group a number of
|
||||
files so they can be given global property information.
|
||||
All files so described are deemed to be JSP files. The
|
||||
following additional properties can be described:
|
||||
|
||||
- Control whether EL is ignored.
|
||||
- Control whether scripting elements are invalid.
|
||||
- Indicate pageEncoding information.
|
||||
- Indicate that a resource is a JSP document (XML).
|
||||
- Prelude and Coda automatic includes.
|
||||
- Control whether the character sequence #{ is allowed
|
||||
when used as a String literal.
|
||||
- Control whether template text containing only
|
||||
whitespaces must be removed from the response output.
|
||||
- Indicate the default contentType information.
|
||||
- Indicate the default buffering model for JspWriter
|
||||
- Control whether error should be raised for the use of
|
||||
undeclared namespaces in a JSP page.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:group ref="javaee:descriptionGroup"/>
|
||||
<xsd:element name="url-pattern"
|
||||
type="javaee:url-patternType"
|
||||
maxOccurs="unbounded"/>
|
||||
<xsd:element name="el-ignored"
|
||||
type="javaee:true-falseType"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
Can be used to easily set the isELIgnored
|
||||
property of a group of JSP pages. By default, the
|
||||
EL evaluation is enabled for Web Applications using
|
||||
a Servlet 2.4 or greater web.xml, and disabled
|
||||
otherwise.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="page-encoding"
|
||||
type="javaee:string"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The valid values of page-encoding are those of the
|
||||
pageEncoding page directive. It is a
|
||||
translation-time error to name different encodings
|
||||
in the pageEncoding attribute of the page directive
|
||||
of a JSP page and in a JSP configuration element
|
||||
matching the page. It is also a translation-time
|
||||
error to name different encodings in the prolog
|
||||
or text declaration of a document in XML syntax and
|
||||
in a JSP configuration element matching the document.
|
||||
It is legal to name the same encoding through
|
||||
mulitple mechanisms.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="scripting-invalid"
|
||||
type="javaee:true-falseType"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
Can be used to easily disable scripting in a
|
||||
group of JSP pages. By default, scripting is
|
||||
enabled.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="is-xml"
|
||||
type="javaee:true-falseType"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
If true, denotes that the group of resources
|
||||
that match the URL pattern are JSP documents,
|
||||
and thus must be interpreted as XML documents.
|
||||
If false, the resources are assumed to not
|
||||
be JSP documents, unless there is another
|
||||
property group that indicates otherwise.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="include-prelude"
|
||||
type="javaee:pathType"
|
||||
minOccurs="0"
|
||||
maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The include-prelude element is a context-relative
|
||||
path that must correspond to an element in the
|
||||
Web Application. When the element is present,
|
||||
the given path will be automatically included (as
|
||||
in an include directive) at the beginning of each
|
||||
JSP page in this jsp-property-group.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="include-coda"
|
||||
type="javaee:pathType"
|
||||
minOccurs="0"
|
||||
maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The include-coda element is a context-relative
|
||||
path that must correspond to an element in the
|
||||
Web Application. When the element is present,
|
||||
the given path will be automatically included (as
|
||||
in an include directive) at the end of each
|
||||
JSP page in this jsp-property-group.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="deferred-syntax-allowed-as-literal"
|
||||
type="javaee:true-falseType"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The character sequence #{ is reserved for EL expressions.
|
||||
Consequently, a translation error occurs if the #{
|
||||
character sequence is used as a String literal, unless
|
||||
this element is enabled (true). Disabled (false) by
|
||||
default.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="trim-directive-whitespaces"
|
||||
type="javaee:true-falseType"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
Indicates that template text containing only whitespaces
|
||||
must be removed from the response output. It has no
|
||||
effect on JSP documents (XML syntax). Disabled (false)
|
||||
by default.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="default-content-type"
|
||||
type="javaee:string"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The valid values of default-content-type are those of the
|
||||
contentType page directive. It specifies the default
|
||||
response contentType if the page directive does not include
|
||||
a contentType attribute.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="buffer"
|
||||
type="javaee:string"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The valid values of buffer are those of the
|
||||
buffer page directive. It specifies if buffering should be
|
||||
used for the output to response, and if so, the size of the
|
||||
buffer to use.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="error-on-undeclared-namespace"
|
||||
type="javaee:true-falseType"
|
||||
minOccurs="0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The default behavior when a tag with unknown namespace is used
|
||||
in a JSP page (regular syntax) is to silently ignore it. If
|
||||
set to true, then an error must be raised during the translation
|
||||
time when an undeclared tag is used in a JSP page. Disabled
|
||||
(false) by default.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id"
|
||||
type="xsd:ID"/>
|
||||
</xsd:complexType>
|
||||
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:complexType name="taglibType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The taglibType defines the syntax for declaring in
|
||||
the deployment descriptor that a tag library is
|
||||
available to the application. This can be done
|
||||
to override implicit map entries from TLD files and
|
||||
from the container.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="taglib-uri"
|
||||
type="javaee:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
A taglib-uri element describes a URI identifying a
|
||||
tag library used in the web application. The body
|
||||
of the taglib-uri element may be either an
|
||||
absolute URI specification, or a relative URI.
|
||||
There should be no entries in web.xml with the
|
||||
same taglib-uri value.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
<xsd:element name="taglib-location"
|
||||
type="javaee:pathType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
the taglib-location element contains the location
|
||||
(as a resource relative to the root of the web
|
||||
application) where to find the Tag Library
|
||||
Description file for the tag library.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id"
|
||||
type="xsd:ID"/>
|
||||
</xsd:complexType>
|
||||
|
||||
</xsd:schema>
|
|
@ -0,0 +1,272 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:javaee="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified"
|
||||
version="3.0">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
||||
|
||||
Copyright 2003-2009 Sun Microsystems, Inc. All rights reserved.
|
||||
|
||||
The contents of this file are subject to the terms of either the
|
||||
GNU General Public License Version 2 only ("GPL") or the Common
|
||||
Development and Distribution License("CDDL") (collectively, the
|
||||
"License"). You may not use this file except in compliance with
|
||||
the License. You can obtain a copy of the License at
|
||||
https://glassfish.dev.java.net/public/CDDL+GPL.html or
|
||||
glassfish/bootstrap/legal/LICENSE.txt. See the License for the
|
||||
specific language governing permissions and limitations under the
|
||||
License.
|
||||
|
||||
When distributing the software, include this License Header
|
||||
Notice in each file and include the License file at
|
||||
glassfish/bootstrap/legal/LICENSE.txt. Sun designates this
|
||||
particular file as subject to the "Classpath" exception as
|
||||
provided by Sun in the GPL Version 2 section of the License file
|
||||
that accompanied this code. If applicable, add the following
|
||||
below the License Header, with the fields enclosed by brackets []
|
||||
replaced by your own identifying information:
|
||||
"Portions Copyrighted [year] [name of copyright owner]"
|
||||
|
||||
Contributor(s):
|
||||
|
||||
If you wish your version of this file to be governed by only the
|
||||
CDDL or only the GPL Version 2, indicate your decision by adding
|
||||
"[Contributor] elects to include this software in this
|
||||
distribution under the [CDDL or GPL Version 2] license." If you
|
||||
don't indicate a single choice of license, a recipient has the
|
||||
option to distribute your version of this file under either the
|
||||
CDDL, the GPL Version 2 or to extend the choice of license to its
|
||||
licensees as provided above. However, if you add GPL Version 2
|
||||
code and therefore, elected the GPL Version 2 license, then the
|
||||
option applies only if the new code is made subject to such
|
||||
option by the copyright holder.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
<![CDATA[[
|
||||
This is the XML Schema for the Servlet 3.0 deployment descriptor.
|
||||
The deployment descriptor must be named "WEB-INF/web.xml" in the
|
||||
web application's war file. All Servlet deployment descriptors
|
||||
must indicate the web application schema by using the Java EE
|
||||
namespace:
|
||||
|
||||
http://java.sun.com/xml/ns/javaee
|
||||
|
||||
and by indicating the version of the schema by
|
||||
using the version element as shown below:
|
||||
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="..."
|
||||
version="3.0">
|
||||
...
|
||||
</web-app>
|
||||
|
||||
The instance documents may indicate the published version of
|
||||
the schema using the xsi:schemaLocation attribute for Java EE
|
||||
namespace with the following location:
|
||||
|
||||
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd
|
||||
|
||||
]]>
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The following conventions apply to all Java EE
|
||||
deployment descriptor elements unless indicated otherwise.
|
||||
|
||||
- In elements that specify a pathname to a file within the
|
||||
same JAR file, relative filenames (i.e., those not
|
||||
starting with "/") are considered relative to the root of
|
||||
the JAR file's namespace. Absolute filenames (i.e., those
|
||||
starting with "/") also specify names in the root of the
|
||||
JAR file's namespace. In general, relative names are
|
||||
preferred. The exception is .war files where absolute
|
||||
names are preferred for consistency with the Servlet API.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<xsd:include schemaLocation="web-common_3_0.xsd"/>
|
||||
|
||||
|
||||
<!-- **************************************************** -->
|
||||
|
||||
<xsd:element name="web-app"
|
||||
type="javaee:web-appType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The web-app element is the root of the deployment
|
||||
descriptor for a web application. Note that the sub-elements
|
||||
of this element can be in the arbitrary order. Because of
|
||||
that, the multiplicity of the elements of distributable,
|
||||
session-config, welcome-file-list, jsp-config, login-config,
|
||||
and locale-encoding-mapping-list was changed from "?" to "*"
|
||||
in this schema. However, the deployment descriptor instance
|
||||
file must not contain multiple elements of session-config,
|
||||
jsp-config, and login-config. When there are multiple elements of
|
||||
welcome-file-list or locale-encoding-mapping-list, the container
|
||||
must concatenate the element contents. The multiple occurence
|
||||
of the element distributable is redundant and the container
|
||||
treats that case exactly in the same way when there is only
|
||||
one distributable.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:unique name="web-common-servlet-name-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The servlet element contains the name of a servlet.
|
||||
The name must be unique within the web application.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:servlet"/>
|
||||
<xsd:field xpath="javaee:servlet-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-filter-name-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The filter element contains the name of a filter.
|
||||
The name must be unique within the web application.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:filter"/>
|
||||
<xsd:field xpath="javaee:filter-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-ejb-local-ref-name-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The ejb-local-ref-name element contains the name of an EJB
|
||||
reference. The EJB reference is an entry in the web
|
||||
application's environment and is relative to the
|
||||
java:comp/env context. The name must be unique within
|
||||
the web application.
|
||||
|
||||
It is recommended that name is prefixed with "ejb/".
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:ejb-local-ref"/>
|
||||
<xsd:field xpath="javaee:ejb-ref-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-ejb-ref-name-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The ejb-ref-name element contains the name of an EJB
|
||||
reference. The EJB reference is an entry in the web
|
||||
application's environment and is relative to the
|
||||
java:comp/env context. The name must be unique within
|
||||
the web application.
|
||||
|
||||
It is recommended that name is prefixed with "ejb/".
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:ejb-ref"/>
|
||||
<xsd:field xpath="javaee:ejb-ref-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-resource-env-ref-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The resource-env-ref-name element specifies the name of
|
||||
a resource environment reference; its value is the
|
||||
environment entry name used in the web application code.
|
||||
The name is a JNDI name relative to the java:comp/env
|
||||
context and must be unique within a web application.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:resource-env-ref"/>
|
||||
<xsd:field xpath="javaee:resource-env-ref-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-message-destination-ref-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The message-destination-ref-name element specifies the name of
|
||||
a message destination reference; its value is the
|
||||
environment entry name used in the web application code.
|
||||
The name is a JNDI name relative to the java:comp/env
|
||||
context and must be unique within a web application.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:message-destination-ref"/>
|
||||
<xsd:field xpath="javaee:message-destination-ref-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-res-ref-name-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The res-ref-name element specifies the name of a
|
||||
resource manager connection factory reference. The name
|
||||
is a JNDI name relative to the java:comp/env context.
|
||||
The name must be unique within a web application.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:resource-ref"/>
|
||||
<xsd:field xpath="javaee:res-ref-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:unique name="web-common-env-entry-name-uniqueness">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The env-entry-name element contains the name of a web
|
||||
application's environment entry. The name is a JNDI
|
||||
name relative to the java:comp/env context. The name
|
||||
must be unique within a web application.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:env-entry"/>
|
||||
<xsd:field xpath="javaee:env-entry-name"/>
|
||||
</xsd:unique>
|
||||
<xsd:key name="web-common-role-name-key">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
A role-name-key is specified to allow the references
|
||||
from the security-role-refs.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:security-role"/>
|
||||
<xsd:field xpath="javaee:role-name"/>
|
||||
</xsd:key>
|
||||
<xsd:keyref name="web-common-role-name-references"
|
||||
refer="javaee:web-common-role-name-key">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
The keyref indicates the references from
|
||||
security-role-ref to a specified role-name.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:selector xpath="javaee:servlet/javaee:security-role-ref"/>
|
||||
<xsd:field xpath="javaee:role-link"/>
|
||||
</xsd:keyref>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,287 @@
|
|||
<?xml version='1.0'?>
|
||||
<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
|
||||
<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns ="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en">
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
<h1>About the XML namespace</h1>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
This schema document describes the XML namespace, in a form
|
||||
suitable for import by other schema documents.
|
||||
</p>
|
||||
<p>
|
||||
See <a href="http://www.w3.org/XML/1998/namespace.html">
|
||||
http://www.w3.org/XML/1998/namespace.html</a> and
|
||||
<a href="http://www.w3.org/TR/REC-xml">
|
||||
http://www.w3.org/TR/REC-xml</a> for information
|
||||
about this namespace.
|
||||
</p>
|
||||
<p>
|
||||
Note that local names in this namespace are intended to be
|
||||
defined only by the World Wide Web Consortium or its subgroups.
|
||||
The names currently defined in this namespace are listed below.
|
||||
They should not be used with conflicting semantics by any Working
|
||||
Group, specification, or document instance.
|
||||
</p>
|
||||
<p>
|
||||
See further below in this document for more information about <a
|
||||
href="#usage">how to refer to this schema document from your own
|
||||
XSD schema documents</a> and about <a href="#nsversioning">the
|
||||
namespace-versioning policy governing this schema document</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:attribute name="lang">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>lang (as an attribute name)</h3>
|
||||
<p>
|
||||
denotes an attribute whose value
|
||||
is a language code for the natural language of the content of
|
||||
any element; its value is inherited. This name is reserved
|
||||
by virtue of its definition in the XML specification.</p>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<h4>Notes</h4>
|
||||
<p>
|
||||
Attempting to install the relevant ISO 2- and 3-letter
|
||||
codes as the enumerated possible values is probably never
|
||||
going to be a realistic possibility.
|
||||
</p>
|
||||
<p>
|
||||
See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
|
||||
http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
|
||||
and the IANA language subtag registry at
|
||||
<a href="http://www.iana.org/assignments/language-subtag-registry">
|
||||
http://www.iana.org/assignments/language-subtag-registry</a>
|
||||
for further information.
|
||||
</p>
|
||||
<p>
|
||||
The union allows for the 'un-declaration' of xml:lang with
|
||||
the empty string.
|
||||
</p>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:union memberTypes="xs:language">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:enumeration value=""/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:union>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="space">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>space (as an attribute name)</h3>
|
||||
<p>
|
||||
denotes an attribute whose
|
||||
value is a keyword indicating what whitespace processing
|
||||
discipline is intended for the content of the element; its
|
||||
value is inherited. This name is reserved by virtue of its
|
||||
definition in the XML specification.</p>
|
||||
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:NCName">
|
||||
<xs:enumeration value="default"/>
|
||||
<xs:enumeration value="preserve"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>base (as an attribute name)</h3>
|
||||
<p>
|
||||
denotes an attribute whose value
|
||||
provides a URI to be used as the base for interpreting any
|
||||
relative URIs in the scope of the element on which it
|
||||
appears; its value is inherited. This name is reserved
|
||||
by virtue of its definition in the XML Base specification.</p>
|
||||
|
||||
<p>
|
||||
See <a
|
||||
href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
|
||||
for information about this attribute.
|
||||
</p>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attribute name="id" type="xs:ID">
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>id (as an attribute name)</h3>
|
||||
<p>
|
||||
denotes an attribute whose value
|
||||
should be interpreted as if declared to be of type ID.
|
||||
This name is reserved by virtue of its definition in the
|
||||
xml:id specification.</p>
|
||||
|
||||
<p>
|
||||
See <a
|
||||
href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
|
||||
for information about this attribute.
|
||||
</p>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
|
||||
<xs:attributeGroup name="specialAttrs">
|
||||
<xs:attribute ref="xml:base"/>
|
||||
<xs:attribute ref="xml:lang"/>
|
||||
<xs:attribute ref="xml:space"/>
|
||||
<xs:attribute ref="xml:id"/>
|
||||
</xs:attributeGroup>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div>
|
||||
|
||||
<h3>Father (in any context at all)</h3>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
denotes Jon Bosak, the chair of
|
||||
the original XML Working Group. This name is reserved by
|
||||
the following decision of the W3C XML Plenary and
|
||||
XML Coordination groups:
|
||||
</p>
|
||||
<blockquote>
|
||||
<p>
|
||||
In appreciation for his vision, leadership and
|
||||
dedication the W3C XML Plenary on this 10th day of
|
||||
February, 2000, reserves for Jon Bosak in perpetuity
|
||||
the XML name "xml:Father".
|
||||
</p>
|
||||
</blockquote>
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div xml:id="usage" id="usage">
|
||||
<h2><a name="usage">About this schema document</a></h2>
|
||||
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
This schema defines attributes and an attribute group suitable
|
||||
for use by schemas wishing to allow <code>xml:base</code>,
|
||||
<code>xml:lang</code>, <code>xml:space</code> or
|
||||
<code>xml:id</code> attributes on elements they define.
|
||||
</p>
|
||||
<p>
|
||||
To enable this, such a schema must import this schema for
|
||||
the XML namespace, e.g. as follows:
|
||||
</p>
|
||||
<pre>
|
||||
<schema . . .>
|
||||
. . .
|
||||
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||
schemaLocation="http://www.w3.org/2001/xml.xsd"/>
|
||||
</pre>
|
||||
<p>
|
||||
or
|
||||
</p>
|
||||
<pre>
|
||||
<import namespace="http://www.w3.org/XML/1998/namespace"
|
||||
schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
|
||||
</pre>
|
||||
<p>
|
||||
Subsequently, qualified reference to any of the attributes or the
|
||||
group defined below will have the desired effect, e.g.
|
||||
</p>
|
||||
<pre>
|
||||
<type . . .>
|
||||
. . .
|
||||
<attributeGroup ref="xml:specialAttrs"/>
|
||||
</pre>
|
||||
<p>
|
||||
will define a type which will schema-validate an instance element
|
||||
with any of those attributes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
<xs:annotation>
|
||||
<xs:documentation>
|
||||
<div id="nsversioning" xml:id="nsversioning">
|
||||
<h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
|
||||
<div class="bodytext">
|
||||
<p>
|
||||
In keeping with the XML Schema WG's standard versioning
|
||||
policy, this schema document will persist at
|
||||
<a href="http://www.w3.org/2009/01/xml.xsd">
|
||||
http://www.w3.org/2009/01/xml.xsd</a>.
|
||||
</p>
|
||||
<p>
|
||||
At the date of issue it can also be found at
|
||||
<a href="http://www.w3.org/2001/xml.xsd">
|
||||
http://www.w3.org/2001/xml.xsd</a>.
|
||||
</p>
|
||||
<p>
|
||||
The schema document at that URI may however change in the future,
|
||||
in order to remain compatible with the latest version of XML
|
||||
Schema itself, or with the XML namespace itself. In other words,
|
||||
if the XML Schema or XML namespaces change, the version of this
|
||||
document at <a href="http://www.w3.org/2001/xml.xsd">
|
||||
http://www.w3.org/2001/xml.xsd
|
||||
</a>
|
||||
will change accordingly; the version at
|
||||
<a href="http://www.w3.org/2009/01/xml.xsd">
|
||||
http://www.w3.org/2009/01/xml.xsd
|
||||
</a>
|
||||
will not change.
|
||||
</p>
|
||||
<p>
|
||||
Previous dated (and unchanging) versions of this schema
|
||||
document are at:
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="http://www.w3.org/2009/01/xml.xsd">
|
||||
http://www.w3.org/2009/01/xml.xsd</a></li>
|
||||
<li><a href="http://www.w3.org/2007/08/xml.xsd">
|
||||
http://www.w3.org/2007/08/xml.xsd</a></li>
|
||||
<li><a href="http://www.w3.org/2004/10/xml.xsd">
|
||||
http://www.w3.org/2004/10/xml.xsd</a></li>
|
||||
<li><a href="http://www.w3.org/2001/03/xml.xsd">
|
||||
http://www.w3.org/2001/03/xml.xsd</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
|
||||
</xs:schema>
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
|
||||
public class ExampleServerIT {
|
||||
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu2();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerIT.class);
|
||||
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
private static String ourServerBase;
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testCreateAndRead() throws IOException {
|
||||
ourLog.info("Base URL is: http://localhost:" + ourPort + "/baseDstu2");
|
||||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
StringDt famName = new StringDt(methodName);
|
||||
List<StringDt> famNames =Arrays.asList(famName);
|
||||
pt.addName().setFamily(famNames);
|
||||
IIdType id = ourClient.create().resource(pt).execute().getId();
|
||||
|
||||
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
||||
assertEquals(famNames, pt2.getName().get(0).getFamily());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
/*
|
||||
* This runs under maven, and I'm not sure how else to figure out the target directory from code..
|
||||
*/
|
||||
String path = ExampleServerIT.class.getClassLoader().getResource(".keep_hapi-fhir-jpaserver-example").getPath();
|
||||
path = new File(path).getParent();
|
||||
path = new File(path).getParent();
|
||||
path = new File(path).getParent();
|
||||
|
||||
ourLog.info("Project base path is: {}", path);
|
||||
|
||||
ourPort = RandomServerPortProvider.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
WebAppContext webAppContext = new WebAppContext();
|
||||
webAppContext.setContextPath("/");
|
||||
//webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
|
||||
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-example");
|
||||
webAppContext.setParentLoaderPriority(true);
|
||||
|
||||
ourServer.setHandler(webAppContext);
|
||||
ourServer.start();
|
||||
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
ourServerBase = "http://localhost:" + ourPort + "/baseDstu2";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides server ports
|
||||
*/
|
||||
public class RandomServerPortProvider {
|
||||
|
||||
private static List<Integer> ourPorts = new ArrayList<Integer>();
|
||||
|
||||
public static int findFreePort() {
|
||||
ServerSocket server;
|
||||
try {
|
||||
server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
ourPorts.add(port);
|
||||
server.close();
|
||||
Thread.sleep(500);
|
||||
return port;
|
||||
} catch (IOException e) {
|
||||
throw new Error(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Integer> list() {
|
||||
return ourPorts;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
nothing
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>hapi-fhir-standalone-overlay-example</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<url>http://jamesagnew.github.io/hapi-fhir/</url>
|
||||
|
||||
|
@ -150,6 +150,21 @@
|
|||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>
|
||||
<!--required when using servers-->
|
||||
ca.uhn.fhir.rest.api.server;resolution:=optional,
|
||||
ca.uhn.fhir.model.api;resolution:=optional,
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.apache.commons.lang3.Validate;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import javassist.Modifier;
|
||||
|
||||
public class ReflectionUtil {
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
* 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.
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,12 +4,12 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>HAPI FHIR - Client Framework</name>
|
||||
|
||||
|
@ -69,6 +69,18 @@
|
|||
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Fragment-Host>
|
||||
ca.uhn.hapi.fhir.hapi-fhir-base
|
||||
</Fragment-Host>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -130,19 +130,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
}
|
||||
|
||||
// public IResource read(UriDt url) {
|
||||
// return read(inferResourceClass(url), url);
|
||||
// }
|
||||
//
|
||||
// @SuppressWarnings("unchecked")
|
||||
// public <T extends IResource> T read(final Class<T> theType, UriDt url) {
|
||||
// return (T) invoke(theType, url, new ResourceResponseHandler<T>(theType));
|
||||
// }
|
||||
//
|
||||
// public Bundle search(UriDt url) {
|
||||
// return search(inferResourceClass(url), url);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public IFetchConformanceUntyped fetchConformance() {
|
||||
return new FetchConformanceInternal();
|
||||
|
@ -169,11 +156,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
return theResource.getIdElement().getIdPart();
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public <T extends IBaseResource> T read(final Class<T> theType, IdDt theId) {
|
||||
// return doReadOrVRead(theType, theId, false, null, null);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public IHistory history() {
|
||||
return new HistoryInternal();
|
||||
|
@ -2105,14 +2087,14 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
@Override
|
||||
public IUpdateTyped resource(IBaseResource theResource) {
|
||||
//Validate.notNull(theResource, "Resource can not be null");
|
||||
Validate.notNull(theResource, "Resource can not be null");
|
||||
myResource = theResource;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IUpdateTyped resource(String theResourceBody) {
|
||||
//Validate.notBlank(theResourceBody, "Body can not be null or blank");
|
||||
Validate.notBlank(theResourceBody, "Body can not be null or blank");
|
||||
myResourceBody = theResourceBody;
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -5,25 +5,25 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Server -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -35,43 +35,43 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
@ -134,5 +134,21 @@
|
|||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>
|
||||
ca.uhn.fhir.rest.server*;resolution:=optional,
|
||||
javax.servlet.http;resolution:=optional,
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -129,7 +129,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
|
||||
HashSet<String> excludeElementsInEncoded = new HashSet<String>();
|
||||
excludeElementsInEncoded.add("id");
|
||||
excludeElementsInEncoded.add("meta");
|
||||
excludeElementsInEncoded.add("*.meta");
|
||||
EXCLUDE_ELEMENTS_IN_ENCODED = Collections.unmodifiableSet(excludeElementsInEncoded);
|
||||
}
|
||||
|
||||
|
|
|
@ -431,7 +431,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
// Perform actual DB update
|
||||
updateEntity(theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||
ResourceTable updatedEntity = updateEntity(theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||
theResource.setId(entity.getIdDt());
|
||||
|
||||
|
||||
|
@ -445,12 +445,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
// Notify JPA interceptors
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourceCreated(theResource);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceCreated(theRequestDetails, theResource);
|
||||
if (!updatedEntity.isUnchangedInCurrentOperation()) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourceCreated(theResource);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceCreated(theRequestDetails, theResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1262,14 +1264,16 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
// Notify interceptors
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource);
|
||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(oldResource, theResource);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource);
|
||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, oldResource, theResource);
|
||||
if (!savedEntity.isUnchangedInCurrentOperation()) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource);
|
||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(oldResource, theResource);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource);
|
||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, oldResource, theResource);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,11 @@ public class DaoConfig {
|
|||
* update setter javadoc if default changes
|
||||
*/
|
||||
private boolean myAllowExternalReferences = false;
|
||||
/**
|
||||
* update setter javadoc if default changes
|
||||
*/
|
||||
private boolean myAllowContainsSearches = true;
|
||||
|
||||
/**
|
||||
* update setter javadoc if default changes
|
||||
*/
|
||||
|
@ -135,6 +140,7 @@ public class DaoConfig {
|
|||
myTreatReferencesAsLogical.add(theTreatReferencesAsLogical);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specifies the highest number that a client is permitted to use in a
|
||||
* <code>Cache-Control: nostore, max-results=NNN</code>
|
||||
|
@ -374,9 +380,9 @@ public class DaoConfig {
|
|||
* of higher importance than raw write performance
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this setting also has an impact on sorting (i.e. using the
|
||||
* <code>_sort</code> parameter on searches): If the server is configured
|
||||
* to not index missing field.
|
||||
* Note that this setting also has an impact on sorting (i.e. using the
|
||||
* <code>_sort</code> parameter on searches): If the server is configured
|
||||
* to not index missing field.
|
||||
* </p>
|
||||
*/
|
||||
public void setIndexMissingFields(IndexEnabledEnum theIndexMissingFields) {
|
||||
|
@ -648,6 +654,26 @@ public class DaoConfig {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If enabled, the server will support the use of :contains searches,
|
||||
* which are helpful but can have adverse effects on performance.
|
||||
*
|
||||
* Default is <code>true</code>
|
||||
*/
|
||||
public boolean isAllowContainsSearches() {
|
||||
return myAllowContainsSearches;
|
||||
}
|
||||
|
||||
/**
|
||||
* If enabled, the server will support the use of :contains searches,
|
||||
* which are helpful but can have adverse effects on performance.
|
||||
*
|
||||
* Default is <code>true</code>
|
||||
*/
|
||||
public void setAllowContainsSearches(boolean theAllowContainsSearches) {
|
||||
this.myAllowContainsSearches = theAllowContainsSearches;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>false</code>) the server will allow
|
||||
* resources to have references to external servers. For example if this server is
|
||||
|
|
|
@ -20,29 +20,32 @@ package ca.uhn.fhir.jpa.dao;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
|
||||
public interface ISearchBuilder {
|
||||
|
||||
Iterator<Long> createQuery(SearchParameterMap theParams, String theSearchUuid);
|
||||
|
||||
void setType(Class<? extends IBaseResource> theResourceType, String theResourceName);
|
||||
|
||||
void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation, EntityManager theEntityManager,
|
||||
FhirContext theContext, IDao theDao);
|
||||
FhirContext theContext, IDao theDao);
|
||||
|
||||
Set<Long> loadReverseIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode,
|
||||
DateRangeParam theLastUpdated);
|
||||
DateRangeParam theLastUpdated);
|
||||
|
||||
/**
|
||||
* How many results may be fetched at once
|
||||
*/
|
||||
void setFetchSize(int theFetchSize);
|
||||
|
||||
void setType(Class<? extends IBaseResource> theResourceType, String theResourceName);
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
|
|||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
||||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
|
||||
|
@ -44,7 +43,9 @@ import ca.uhn.fhir.rest.api.SortSpec;
|
|||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Lists;
|
||||
|
@ -58,6 +59,9 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
|
|||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.internal.SessionImpl;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hl7.fhir.dstu3.model.BaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -103,6 +107,7 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
private String mySearchUuid;
|
||||
private IHapiTerminologySvc myTerminologySvc;
|
||||
private int myFetchSize;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -1090,6 +1095,11 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
} else if (theParameter instanceof StringParam) {
|
||||
StringParam id = (StringParam) theParameter;
|
||||
rawSearchTerm = id.getValue();
|
||||
if (id.isContains()) {
|
||||
if (!myCallingDao.getConfig().isAllowContainsSearches()) {
|
||||
throw new MethodNotAllowedException(":contains modifier is disabled on this server");
|
||||
}
|
||||
}
|
||||
} else if (theParameter instanceof IPrimitiveDatatype<?>) {
|
||||
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) theParameter;
|
||||
rawSearchTerm = id.getValueAsString();
|
||||
|
@ -1103,7 +1113,13 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
}
|
||||
|
||||
String likeExpression = BaseHapiFhirDao.normalizeString(rawSearchTerm);
|
||||
likeExpression = createLeftMatchLikeExpression(likeExpression);
|
||||
if (theParameter instanceof StringParam &&
|
||||
((StringParam) theParameter).isContains() &&
|
||||
myCallingDao.getConfig().isAllowContainsSearches()) {
|
||||
likeExpression = createLeftAndRightMatchLikeExpression(likeExpression);
|
||||
} else {
|
||||
likeExpression = createLeftMatchLikeExpression(likeExpression);
|
||||
}
|
||||
|
||||
Predicate singleCode = theBuilder.like(theFrom.get("myValueNormalized").as(String.class), likeExpression);
|
||||
if (theParameter instanceof StringParam && ((StringParam) theParameter).isExact()) {
|
||||
|
@ -1219,7 +1235,11 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
*/
|
||||
|
||||
if (StringUtils.isNotBlank(system)) {
|
||||
singleCodePredicates.add(theBuilder.equal(theFrom.get("mySystem"), system));
|
||||
if (modifier != null && modifier == TokenParamModifier.NOT) {
|
||||
singleCodePredicates.add(theBuilder.notEqual(theFrom.get("mySystem"), system));
|
||||
} else {
|
||||
singleCodePredicates.add(theBuilder.equal(theFrom.get("mySystem"), system));
|
||||
}
|
||||
} else if (system == null) {
|
||||
// don't check the system
|
||||
} else {
|
||||
|
@ -1228,7 +1248,11 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
}
|
||||
|
||||
if (StringUtils.isNotBlank(code)) {
|
||||
singleCodePredicates.add(theBuilder.equal(theFrom.get("myValue"), code));
|
||||
if (modifier != null && modifier == TokenParamModifier.NOT) {
|
||||
singleCodePredicates.add(theBuilder.notEqual(theFrom.get("myValue"), code));
|
||||
} else {
|
||||
singleCodePredicates.add(theBuilder.equal(theFrom.get("myValue"), code));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* As of HAPI FHIR 1.5, if the client searched for a token with a system but no specified value this means to
|
||||
|
@ -1906,6 +1930,11 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int theFetchSize) {
|
||||
myFetchSize = theFetchSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(Class<? extends IBaseResource> theResourceType, String theResourceName) {
|
||||
myResourceType = theResourceType;
|
||||
|
@ -1993,6 +2022,10 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
return lastUpdatedPredicates;
|
||||
}
|
||||
|
||||
private static String createLeftAndRightMatchLikeExpression(String likeExpression) {
|
||||
return "%" + likeExpression.replace("%", "[%]") + "%";
|
||||
}
|
||||
|
||||
private static String createLeftMatchLikeExpression(String likeExpression) {
|
||||
return likeExpression.replace("%", "[%]") + "%";
|
||||
}
|
||||
|
@ -2157,6 +2190,7 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
final TypedQuery<Long> query = createQuery(mySort, maximumResults);
|
||||
|
||||
Query<Long> hibernateQuery = (Query<Long>) query;
|
||||
hibernateQuery.setFetchSize(myFetchSize);
|
||||
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
||||
myResultsIterator = new ScrollableResultsIterator(scroll);
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
||||
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
|
||||
sb.setType(resourceTypeClass, theResourceType);
|
||||
sb.setFetchSize(mySyncSize);
|
||||
|
||||
final Integer loadSynchronousUpTo;
|
||||
if (theCacheControlDirective != null && theCacheControlDirective.isNoStore()) {
|
||||
|
@ -233,7 +234,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
public SimpleBundleProvider doInTransaction(TransactionStatus theStatus) {
|
||||
|
||||
// Load the results synchronously
|
||||
final List<Long> pids = new ArrayList<Long>();
|
||||
final List<Long> pids = new ArrayList<>();
|
||||
|
||||
Iterator<Long> resultIter = sb.createQuery(theParams, searchUuid);
|
||||
while (resultIter.hasNext()) {
|
||||
|
@ -458,8 +459,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
private final SearchParameterMap myParams;
|
||||
private final String myResourceType;
|
||||
private final Search mySearch;
|
||||
private final ArrayList<Long> mySyncedPids = new ArrayList<Long>();
|
||||
private final ArrayList<Long> myUnsyncedPids = new ArrayList<Long>();
|
||||
private final ArrayList<Long> mySyncedPids = new ArrayList<>();
|
||||
private final ArrayList<Long> myUnsyncedPids = new ArrayList<>();
|
||||
private boolean myAbortRequested;
|
||||
private int myCountSaved = 0;
|
||||
private String mySearchUuid;
|
||||
|
@ -503,7 +504,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
* It is called automatically by the thread pool.
|
||||
*/
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
public Void call() {
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
try {
|
||||
|
@ -631,10 +632,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
boolean keepWaiting;
|
||||
do {
|
||||
synchronized (mySyncedPids) {
|
||||
keepWaiting = false;
|
||||
if (mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING) {
|
||||
keepWaiting = true;
|
||||
}
|
||||
keepWaiting = mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING;
|
||||
}
|
||||
if (keepWaiting) {
|
||||
ourLog.info("Waiting, as we only have {} results", mySyncedPids.size());
|
||||
|
|
|
@ -1193,6 +1193,62 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionUpdateResourceNewVersionCreatedWhenDataChanges() {
|
||||
|
||||
Bundle request = new Bundle();
|
||||
String patientId = "Patient/IShouldUpdate";
|
||||
Patient p = new Patient();
|
||||
p.addName().addFamily("Hello");
|
||||
p.setId(patientId);
|
||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId);
|
||||
|
||||
Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(1, initialBundleResponse.getEntry().size());
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse));
|
||||
|
||||
Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0);
|
||||
assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus());
|
||||
assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
||||
|
||||
p.addName().addFamily("AnotherName");
|
||||
|
||||
Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(1, secondBundleResponse.getEntry().size());
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse));
|
||||
|
||||
Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0);
|
||||
assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus());
|
||||
assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionUpdateResourceNewVersionNotCreatedWhenDataNotChanged() {
|
||||
|
||||
Bundle request = new Bundle();
|
||||
String patientId = "Patient/IShouldNotUpdate";
|
||||
Patient p = new Patient();
|
||||
p.addName().addFamily("Hello");
|
||||
p.setId(patientId);
|
||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.PUT).setUrl(patientId);
|
||||
|
||||
Bundle initialBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(1, initialBundleResponse.getEntry().size());
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(initialBundleResponse));
|
||||
|
||||
Entry initialBundleResponseEntry = initialBundleResponse.getEntry().get(0);
|
||||
assertEquals("201 Created", initialBundleResponseEntry.getResponse().getStatus());
|
||||
assertThat(initialBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
||||
|
||||
Bundle secondBundleResponse = mySystemDao.transaction(mySrd, request);
|
||||
assertEquals(1, secondBundleResponse.getEntry().size());
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(secondBundleResponse));
|
||||
|
||||
Entry secondBundleResponseEntry = secondBundleResponse.getEntry().get(0);
|
||||
assertEquals("200 OK", secondBundleResponseEntry.getResponse().getStatus());
|
||||
assertThat(secondBundleResponseEntry.getResponse().getEtag(), is(equalTo("1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionUpdateMatchUrlWithTwoMatch() {
|
||||
String methodName = "testTransactionUpdateMatchUrlWithTwoMatch";
|
||||
|
|
|
@ -1,133 +1,116 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.*;
|
||||
import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.ContactPoint.ContactPointSystem;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchNoFtTest.class);
|
||||
|
||||
@After
|
||||
public void afterResetSearchSize() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeDisableCacheReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterResetSearchSize() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #744
|
||||
*/
|
||||
@Test
|
||||
public void testSearchWithVeryLongUrlShorter() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
public void testChainWithMultipleTypePossibilities() {
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("A1");
|
||||
myPatientDao.create(p);
|
||||
Patient sub1 = new Patient();
|
||||
sub1.setActive(true);
|
||||
sub1.addIdentifier().setSystem("foo").setValue("bar");
|
||||
String sub1Id = myPatientDao.create(sub1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
assertEquals(0, mySearchEntityDao.count());
|
||||
Group sub2 = new Group();
|
||||
sub2.setActive(true);
|
||||
sub2.addIdentifier().setSystem("foo").setValue("bar");
|
||||
String sub2Id = myGroupDao.create(sub2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
StringOrListParam or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'A')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'B')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'C')));
|
||||
map.add(Patient.SP_NAME, or);
|
||||
IBundleProvider results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
Encounter enc1 = new Encounter();
|
||||
enc1.getSubject().setReference(sub1Id);
|
||||
String enc1Id = myEncounterDao.create(enc1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc2 = new Encounter();
|
||||
enc2.getSubject().setReference(sub2Id);
|
||||
String enc2Id = myEncounterDao.create(enc2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
List<String> ids;
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'A')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'B')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'C')));
|
||||
map.add(Patient.SP_NAME, or);
|
||||
results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #744
|
||||
*/
|
||||
@Test
|
||||
public void testSearchWithVeryLongUrlLonger() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("A1");
|
||||
myPatientDao.create(p);
|
||||
|
||||
assertEquals(0, mySearchEntityDao.count());
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
StringOrListParam or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
for (int i = 0; i < 50; i++) {
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, (char)('A' + i))));
|
||||
}
|
||||
map.add(Patient.SP_NAME, or);
|
||||
IBundleProvider results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "foo|bar").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc1Id, enc2Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
or.addOr(new StringParam("A1"));
|
||||
for (int i = 0; i < 50; i++) {
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, (char)('A' + i))));
|
||||
}
|
||||
map.add(Patient.SP_NAME, or);
|
||||
results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
// We expect a new one because we don't cache the search URL for very long search URLs
|
||||
assertEquals(2, mySearchEntityDao.count());
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject:Patient", "foo|bar").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc1Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject:Group", "foo|bar").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc2Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "04823543").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, empty());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,50 +134,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(ids, contains(moId.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeLinkedObservations() {
|
||||
|
||||
DiagnosticReport dr = new DiagnosticReport();
|
||||
dr.setId("DiagnosticReport/DR");
|
||||
dr.setStatus(DiagnosticReport.DiagnosticReportStatus.FINAL);
|
||||
|
||||
Observation parentObs = new Observation();
|
||||
parentObs.setStatus(ObservationStatus.FINAL);
|
||||
parentObs.setId("Observation/parentObs");
|
||||
|
||||
Observation childObs = new Observation();
|
||||
childObs.setId("Observation/childObs");
|
||||
childObs.setStatus(ObservationStatus.FINAL);
|
||||
|
||||
dr.addResult().setReference("Observation/parentObs").setResource(parentObs);
|
||||
parentObs.addHasMember(new Reference(childObs).setReference("Observation/childObs"));
|
||||
childObs.addDerivedFrom(new Reference(parentObs).setReference("Observation/parentObs"));
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(dr)
|
||||
.getRequest().setMethod(HTTPVerb.PUT).setUrl(dr.getId());
|
||||
input.addEntry()
|
||||
.setResource(parentObs)
|
||||
.getRequest().setMethod(HTTPVerb.PUT).setUrl(parentObs.getId());
|
||||
input.addEntry()
|
||||
.setResource(childObs)
|
||||
.getRequest().setMethod(HTTPVerb.PUT).setUrl(childObs.getId());
|
||||
mySystemDao.transaction(mySrd, input);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("_id", new TokenParam(null, "DR"));
|
||||
params.addInclude(new Include("DiagnosticReport:subject").setRecurse(true));
|
||||
params.addInclude(new Include("DiagnosticReport:result").setRecurse(true));
|
||||
params.addInclude(Observation.INCLUDE_HAS_MEMBER.setRecurse(true));
|
||||
|
||||
IBundleProvider result = myDiagnosticReportDao.search(params);
|
||||
List<String> resultIds = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(resultIds, containsInAnyOrder("DiagnosticReport/DR", "Observation/parentObs", "Observation/childObs"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyChain() {
|
||||
|
||||
|
@ -206,56 +145,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(ids, empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChainWithMultipleTypePossibilities() {
|
||||
|
||||
Patient sub1 = new Patient();
|
||||
sub1.setActive(true);
|
||||
sub1.addIdentifier().setSystem("foo").setValue("bar");
|
||||
String sub1Id = myPatientDao.create(sub1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Group sub2 = new Group();
|
||||
sub2.setActive(true);
|
||||
sub2.addIdentifier().setSystem("foo").setValue("bar");
|
||||
String sub2Id = myGroupDao.create(sub2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc1 = new Encounter();
|
||||
enc1.getSubject().setReference(sub1Id);
|
||||
String enc1Id = myEncounterDao.create(enc1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Encounter enc2 = new Encounter();
|
||||
enc2.getSubject().setReference(sub2Id);
|
||||
String enc2Id = myEncounterDao.create(enc2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
List<String> ids;
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "foo|bar").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc1Id, enc2Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject:Patient", "foo|bar").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc1Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject:Group", "foo|bar").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, hasItems(enc2Id));
|
||||
|
||||
map = new SearchParameterMap();
|
||||
map.add(Encounter.SP_SUBJECT, new ReferenceParam("subject", "04823543").setChain("identifier"));
|
||||
results = myEncounterDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, empty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingTimings() {
|
||||
String methodName = "testEverythingTimings";
|
||||
|
@ -506,6 +395,50 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeLinkedObservations() {
|
||||
|
||||
DiagnosticReport dr = new DiagnosticReport();
|
||||
dr.setId("DiagnosticReport/DR");
|
||||
dr.setStatus(DiagnosticReport.DiagnosticReportStatus.FINAL);
|
||||
|
||||
Observation parentObs = new Observation();
|
||||
parentObs.setStatus(ObservationStatus.FINAL);
|
||||
parentObs.setId("Observation/parentObs");
|
||||
|
||||
Observation childObs = new Observation();
|
||||
childObs.setId("Observation/childObs");
|
||||
childObs.setStatus(ObservationStatus.FINAL);
|
||||
|
||||
dr.addResult().setReference("Observation/parentObs").setResource(parentObs);
|
||||
parentObs.addHasMember(new Reference(childObs).setReference("Observation/childObs"));
|
||||
childObs.addDerivedFrom(new Reference(parentObs).setReference("Observation/parentObs"));
|
||||
|
||||
Bundle input = new Bundle();
|
||||
input.setType(BundleType.TRANSACTION);
|
||||
input.addEntry()
|
||||
.setResource(dr)
|
||||
.getRequest().setMethod(HTTPVerb.PUT).setUrl(dr.getId());
|
||||
input.addEntry()
|
||||
.setResource(parentObs)
|
||||
.getRequest().setMethod(HTTPVerb.PUT).setUrl(parentObs.getId());
|
||||
input.addEntry()
|
||||
.setResource(childObs)
|
||||
.getRequest().setMethod(HTTPVerb.PUT).setUrl(childObs.getId());
|
||||
mySystemDao.transaction(mySrd, input);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("_id", new TokenParam(null, "DR"));
|
||||
params.addInclude(new Include("DiagnosticReport:subject").setRecurse(true));
|
||||
params.addInclude(new Include("DiagnosticReport:result").setRecurse(true));
|
||||
params.addInclude(Observation.INCLUDE_HAS_MEMBER.setRecurse(true));
|
||||
|
||||
IBundleProvider result = myDiagnosticReportDao.search(params);
|
||||
List<String> resultIds = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(resultIds, containsInAnyOrder("DiagnosticReport/DR", "Observation/parentObs", "Observation/childObs"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexNoDuplicatesDate() {
|
||||
Encounter order = new Encounter();
|
||||
|
@ -519,7 +452,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
IIdType id = myEncounterDao.create(order, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
myEncounterDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Encounter.SP_LOCATION_PERIOD, new DateParam("2011-12-12T11:12:12Z"))));
|
||||
myEncounterDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Encounter.SP_LOCATION_PERIOD, new DateParam("2011-12-12T11:12:12Z"))));
|
||||
assertThat(actual, contains(id));
|
||||
|
||||
Class<ResourceIndexedSearchParamDate> type = ResourceIndexedSearchParamDate.class;
|
||||
|
@ -553,9 +486,9 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
List<ResourceIndexedSearchParamNumber> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i", type).getResultList();
|
||||
ourLog.info(toStringMultiline(results));
|
||||
assertThat(results, containsInAnyOrder(
|
||||
((ResourceIndexedSearchParamNumber)(new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_SEQUENCE, null).setResource(resource).setMissing(true))),
|
||||
((ResourceIndexedSearchParamNumber)(new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_NUMBER, new BigDecimal("1.00")).setResource(resource))),
|
||||
((ResourceIndexedSearchParamNumber)(new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_NUMBER, new BigDecimal("2.00")).setResource(resource)))
|
||||
((ResourceIndexedSearchParamNumber) (new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_SEQUENCE, null).setResource(resource).setMissing(true))),
|
||||
((ResourceIndexedSearchParamNumber) (new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_NUMBER, new BigDecimal("1.00")).setResource(resource))),
|
||||
((ResourceIndexedSearchParamNumber) (new ResourceIndexedSearchParamNumber(ImmunizationRecommendation.SP_DOSE_NUMBER, new BigDecimal("2.00")).setResource(resource)))
|
||||
));
|
||||
}
|
||||
});
|
||||
|
@ -577,7 +510,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertEquals(2, results.size());
|
||||
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT"))));
|
||||
mySubstanceDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Substance.SP_QUANTITY, new QuantityParam(null, 123, "http://foo", "UNIT"))));
|
||||
assertThat(actual, contains(id));
|
||||
}
|
||||
|
||||
|
@ -610,11 +543,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
ourLog.info(toStringMultiline(results));
|
||||
assertEquals(2, results.size());
|
||||
List<IIdType> actual = toUnqualifiedVersionlessIds(
|
||||
myServiceRequestDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ServiceRequest.SP_REPLACES, new ReferenceParam("ServiceRequest/somepract"))));
|
||||
myServiceRequestDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ServiceRequest.SP_REPLACES, new ReferenceParam("ServiceRequest/somepract"))));
|
||||
assertThat(actual, contains(id));
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -681,6 +614,17 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(actual, contains(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* #454
|
||||
*/
|
||||
@Test
|
||||
public void testIndexWithUtf8Chars() throws IOException {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/bug454_utf8.json"), StandardCharsets.UTF_8);
|
||||
|
||||
CodeSystem cs = (CodeSystem) myFhirCtx.newJsonParser().parseResource(input);
|
||||
myCodeSystemDao.create(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReturnOnlyCorrectResourceType() {
|
||||
ValueSet vsRes = new ValueSet();
|
||||
|
@ -702,17 +646,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(actual, contains(csId));
|
||||
}
|
||||
|
||||
/**
|
||||
* #454
|
||||
*/
|
||||
@Test
|
||||
public void testIndexWithUtf8Chars() throws IOException {
|
||||
String input = IOUtils.toString(getClass().getResourceAsStream("/bug454_utf8.json"), StandardCharsets.UTF_8);
|
||||
|
||||
CodeSystem cs = (CodeSystem) myFhirCtx.newJsonParser().parseResource(input);
|
||||
myCodeSystemDao.create(cs);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchAll() {
|
||||
{
|
||||
|
@ -1324,8 +1257,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(patients, (hasItems(id1a, id1b)));
|
||||
assertThat(patients, not(hasItems(id2)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, beforeR2)));
|
||||
|
@ -1401,7 +1334,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
map = new SearchParameterMap();
|
||||
map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN, startDateTime.getValue()),
|
||||
new DateParam(ParamPrefixEnum.LESSTHAN, myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValue())));
|
||||
new DateParam(ParamPrefixEnum.LESSTHAN, myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValue())));
|
||||
ourLog.info("Searching: {}", map.getLastUpdated());
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a));
|
||||
}
|
||||
|
@ -1542,7 +1475,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
{
|
||||
IBundleProvider found = myPatientDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_GENDER, new TokenParam().setModifier(TokenParamModifier.IN).setValue("urn:testSearchOnCodesWithNone")));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Patient.SP_GENDER, new TokenParam().setModifier(TokenParamModifier.IN).setValue("urn:testSearchOnCodesWithNone")));
|
||||
assertThat(toUnqualifiedVersionlessIdValues(found), empty());
|
||||
assertEquals(0, found.size().intValue());
|
||||
}
|
||||
|
@ -1682,7 +1615,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
ourLog.info("P1[{}] P2[{}] O1[{}] O2[{}] D1[{}]", patientId01, patientId02, obsId01, obsId02, drId01);
|
||||
|
||||
List<Observation> result = toList(myObservationDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "urn:system|testSearchResourceLinkWithChain01"))));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "urn:system|testSearchResourceLinkWithChain01"))));
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(obsId01.getIdPart(), result.get(0).getIdElement().getIdPart());
|
||||
|
||||
|
@ -1696,15 +1629,15 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertEquals(0, result.size());
|
||||
|
||||
result = toList(myObservationDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "urn:system|testSearchResourceLinkWithChainXX"))));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "urn:system|testSearchResourceLinkWithChainXX"))));
|
||||
assertEquals(2, result.size());
|
||||
|
||||
result = toList(
|
||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "testSearchResourceLinkWithChainXX"))));
|
||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "testSearchResourceLinkWithChainXX"))));
|
||||
assertEquals(2, result.size());
|
||||
|
||||
result = toList(
|
||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "|testSearchResourceLinkWithChainXX"))));
|
||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_IDENTIFIER, "|testSearchResourceLinkWithChainXX"))));
|
||||
assertEquals(0, result.size());
|
||||
|
||||
}
|
||||
|
@ -1788,12 +1721,12 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
SearchParameterMap params;
|
||||
|
||||
result = toUnqualifiedVersionlessIds(myObservationDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesXX"))));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesXX"))));
|
||||
assertThat(result, containsInAnyOrder(obsId01));
|
||||
assertEquals(1, result.size());
|
||||
|
||||
result = toUnqualifiedVersionlessIds(myObservationDao.search(
|
||||
new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam("Patient", Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01"))));
|
||||
new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam("Patient", Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypes01"))));
|
||||
assertThat(result, containsInAnyOrder(obsId01));
|
||||
assertEquals(1, result.size());
|
||||
|
||||
|
@ -1811,7 +1744,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(result, containsInAnyOrder(obsId02));
|
||||
|
||||
result = toUnqualifiedVersionlessIds(myObservationDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesYY"))));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam(Patient.SP_NAME, "testSearchResourceLinkWithChainWithMultipleTypesYY"))));
|
||||
assertEquals(0, result.size());
|
||||
|
||||
}
|
||||
|
@ -1848,7 +1781,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
ourLog.info("P1[{}] P2[{}] O1[{}] O2[{}] D1[{}]", patientId01, patientId02, obsId01, obsId02, drId01);
|
||||
|
||||
List<Observation> result = toList(
|
||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam("testSearchResourceLinkWithTextLogicalId01"))));
|
||||
myObservationDao.search(new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_SUBJECT, new ReferenceParam("testSearchResourceLinkWithTextLogicalId01"))));
|
||||
assertEquals(1, result.size());
|
||||
assertEquals(obsId01.getIdPart(), result.get(0).getIdElement().getIdPart());
|
||||
|
||||
|
@ -1860,7 +1793,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchResourceReferenceOnlyCorrectPath() {
|
||||
|
@ -1893,48 +1825,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStringParamDoesntMatchWrongType() {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("HELLO");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Practitioner patient = new Practitioner();
|
||||
patient.addName().setFamily("HELLO");
|
||||
pid2 = myPractitionerDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
SearchParameterMap params;
|
||||
List<IIdType> patients;
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("HELLO"));
|
||||
patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
|
||||
assertThat(patients, containsInAnyOrder(pid1));
|
||||
assertThat(patients, not(containsInAnyOrder(pid2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFetchSizeDefaultMaximum() {
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(5);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PT" + i);
|
||||
myPatientDao.create(p);
|
||||
}
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
IBundleProvider values = myPatientDao.search(map);
|
||||
assertEquals(5, values.size().intValue());
|
||||
assertEquals(5, values.getResources(0, 1000).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStringParam() throws Exception {
|
||||
IIdType pid1;
|
||||
|
@ -1978,6 +1868,31 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStringParamDoesntMatchWrongType() {
|
||||
IIdType pid1;
|
||||
IIdType pid2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("HELLO");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
{
|
||||
Practitioner patient = new Practitioner();
|
||||
patient.addName().setFamily("HELLO");
|
||||
pid2 = myPractitionerDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
SearchParameterMap params;
|
||||
List<IIdType> patients;
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_FAMILY, new StringParam("HELLO"));
|
||||
patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
|
||||
assertThat(patients, containsInAnyOrder(pid1));
|
||||
assertThat(patients, not(containsInAnyOrder(pid2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStringParamReallyLong() {
|
||||
String methodName = "testSearchStringParamReallyLong";
|
||||
|
@ -2071,7 +1986,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("testSearchTokenParam001");
|
||||
patient.addName().setFamily("Tester").addGiven("testSearchTokenParam1");
|
||||
patient.addCommunication().getLanguage().setText("testSearchTokenParamComText").addCoding().setCode("testSearchTokenParamCode").setSystem("testSearchTokenParamSystem")
|
||||
.setDisplay("testSearchTokenParamDisplay");
|
||||
.setDisplay("testSearchTokenParamDisplay");
|
||||
myPatientDao.create(patient, mySrd);
|
||||
|
||||
patient = new Patient();
|
||||
|
@ -2145,7 +2060,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("testSearchTokenParam001");
|
||||
patient.addName().setFamily("Tester").addGiven("testSearchTokenParam1");
|
||||
patient.addCommunication().getLanguage().setText("testSearchTokenParamComText").addCoding().setCode("testSearchTokenParamCode").setSystem("testSearchTokenParamSystem")
|
||||
.setDisplay("testSearchTokenParamDisplay");
|
||||
.setDisplay("testSearchTokenParamDisplay");
|
||||
myPatientDao.create(patient, mySrd);
|
||||
|
||||
patient = new Patient();
|
||||
|
@ -2172,6 +2087,43 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #819
|
||||
*/
|
||||
@Test
|
||||
public void testSearchTokenWithNotModifier() {
|
||||
String male, female;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
patient.setGender(AdministrativeGender.MALE);
|
||||
male = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
}
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
patient.addName().setFamily("Tester").addGiven("Jane");
|
||||
patient.setGender(AdministrativeGender.FEMALE);
|
||||
female = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
|
||||
}
|
||||
|
||||
List<String> patients;
|
||||
SearchParameterMap params;
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_GENDER, new TokenParam(null, "male"));
|
||||
params.setLoadSynchronous(true);
|
||||
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
|
||||
assertThat(patients, contains(male));
|
||||
|
||||
params = new SearchParameterMap();
|
||||
params.add(Patient.SP_GENDER, new TokenParam(null, "male").setModifier(TokenParamModifier.NOT));
|
||||
params.setLoadSynchronous(true);
|
||||
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
|
||||
assertThat(patients, contains(female));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchTokenWrongParam() {
|
||||
Patient p1 = new Patient();
|
||||
|
@ -2307,6 +2259,67 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithContains() {
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("ABCDEFGHIJK");
|
||||
String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.addName().setFamily("FGHIJK");
|
||||
String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient pt3 = new Patient();
|
||||
pt3.addName().setFamily("ZZZZZ");
|
||||
myPatientDao.create(pt3).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
|
||||
List<String> ids;
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
|
||||
// Contains = true
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(true));
|
||||
map.setLoadSynchronous(true);
|
||||
results = myPatientDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, containsInAnyOrder(pt1id, pt2id));
|
||||
|
||||
// Contains = false
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(false));
|
||||
map.setLoadSynchronous(true);
|
||||
results = myPatientDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, containsInAnyOrder(pt2id));
|
||||
|
||||
// No contains
|
||||
map = new SearchParameterMap();
|
||||
map.add(Patient.SP_NAME, new StringParam("FGHIJK"));
|
||||
map.setLoadSynchronous(true);
|
||||
results = myPatientDao.search(map);
|
||||
ids = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(ids, containsInAnyOrder(pt2id));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithContainsDisabled() {
|
||||
myDaoConfig.setAllowContainsSearches(false);
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(true));
|
||||
|
||||
try {
|
||||
myPatientDao.search(map);
|
||||
fail();
|
||||
} catch (MethodNotAllowedException e) {
|
||||
assertEquals(":contains modifier is disabled on this server", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithDate() {
|
||||
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId();
|
||||
|
@ -2355,6 +2368,22 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithFetchSizeDefaultMaximum() {
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(5);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("PT" + i);
|
||||
myPatientDao.create(p);
|
||||
}
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronous(true);
|
||||
IBundleProvider values = myPatientDao.search(map);
|
||||
assertEquals(5, values.size().intValue());
|
||||
assertEquals(5, values.getResources(0, 1000).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithIncludes() {
|
||||
|
@ -2670,7 +2699,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchWithNoResults() {
|
||||
Device dev = new Device();
|
||||
|
@ -2887,7 +2915,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* https://chat.fhir.org/#narrow/stream/implementers/topic/Understanding.20_include
|
||||
*/
|
||||
|
@ -2933,7 +2960,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
|
||||
|
||||
result = myValueSetDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type").setQualifier(UriParamQualifierEnum.BELOW)));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type").setQualifier(UriParamQualifierEnum.BELOW)));
|
||||
assertThat(toUnqualifiedVersionlessIds(result), contains(id1));
|
||||
|
||||
result = myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/").setQualifier(UriParamQualifierEnum.BELOW)));
|
||||
|
@ -2969,7 +2996,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder(id2));
|
||||
|
||||
result = myValueSetDao
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type").setQualifier(UriParamQualifierEnum.ABOVE)));
|
||||
.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_URL, new UriParam("http://hl7.org/fhir/ValueSet/basic-resource-type").setQualifier(UriParamQualifierEnum.ABOVE)));
|
||||
assertThat(toUnqualifiedVersionlessIds(result), empty());
|
||||
|
||||
result = myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_URL, new UriParam("http://hl7.org").setQualifier(UriParamQualifierEnum.ABOVE)));
|
||||
|
@ -3004,6 +3031,81 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
assertThat(toUnqualifiedVersionlessIds(result), containsInAnyOrder());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #744
|
||||
*/
|
||||
@Test
|
||||
public void testSearchWithVeryLongUrlLonger() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("A1");
|
||||
myPatientDao.create(p);
|
||||
|
||||
assertEquals(0, mySearchEntityDao.count());
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
StringOrListParam or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
for (int i = 0; i < 50; i++) {
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, (char) ('A' + i))));
|
||||
}
|
||||
map.add(Patient.SP_NAME, or);
|
||||
IBundleProvider results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
or.addOr(new StringParam("A1"));
|
||||
for (int i = 0; i < 50; i++) {
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, (char) ('A' + i))));
|
||||
}
|
||||
map.add(Patient.SP_NAME, or);
|
||||
results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
// We expect a new one because we don't cache the search URL for very long search URLs
|
||||
assertEquals(2, mySearchEntityDao.count());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #744
|
||||
*/
|
||||
@Test
|
||||
public void testSearchWithVeryLongUrlShorter() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("A1");
|
||||
myPatientDao.create(p);
|
||||
|
||||
assertEquals(0, mySearchEntityDao.count());
|
||||
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
StringOrListParam or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'A')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'B')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'C')));
|
||||
map.add(Patient.SP_NAME, or);
|
||||
IBundleProvider results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
|
||||
map = new SearchParameterMap();
|
||||
or = new StringOrListParam();
|
||||
or.addOr(new StringParam("A1"));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'A')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'B')));
|
||||
or.addOr(new StringParam(StringUtils.leftPad("", 200, 'C')));
|
||||
map.add(Patient.SP_NAME, or);
|
||||
results = myPatientDao.search(map);
|
||||
assertEquals(1, results.getResources(0, 10).size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
|
||||
}
|
||||
|
||||
private String toStringMultiline(List<?> theResults) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
|
|
|
@ -8,6 +8,7 @@ import ca.uhn.fhir.rest.api.server.ResponseDetails;
|
|||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -43,9 +44,9 @@ import static org.mockito.Mockito.*;
|
|||
public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderInterceptorR4Test.class);
|
||||
private IServerInterceptor myDaoInterceptor;
|
||||
private IServerOperationInterceptor myDaoInterceptor;
|
||||
|
||||
private IServerInterceptor myServerInterceptor;
|
||||
private IServerOperationInterceptor myServerInterceptor;
|
||||
|
||||
@Override
|
||||
@After
|
||||
|
@ -60,8 +61,8 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
|||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
myServerInterceptor = mock(IServerInterceptor.class);
|
||||
myDaoInterceptor = mock(IServerInterceptor.class);
|
||||
myServerInterceptor = mock(IServerOperationInterceptor.class);
|
||||
myDaoInterceptor = mock(IServerOperationInterceptor.class);
|
||||
|
||||
resetServerInterceptor();
|
||||
|
||||
|
@ -88,6 +89,57 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
|||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(ResponseDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConditionalNoOpResourceInTransaction() throws Exception {
|
||||
String methodName = "foo";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
BundleEntryComponent entry = bundle.addEntry();
|
||||
entry.setFullUrl("Patient");
|
||||
entry.setResource(pt);
|
||||
entry.getRequest().setMethod(HTTPVerb.POST);
|
||||
entry.getRequest().setUrl("Patient");
|
||||
|
||||
// Transaction time!
|
||||
transaction(bundle);
|
||||
|
||||
// Do it again but with a conditional create that shouldn't actually create
|
||||
resetServerInterceptor();
|
||||
entry.getRequest().setIfNoneExist("Patient?name=" + methodName);
|
||||
transaction(bundle);
|
||||
|
||||
/*
|
||||
* Server Interceptor
|
||||
*/
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myServerInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
|
||||
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
verify(myServerInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
/*
|
||||
* DAO Interceptor
|
||||
*/
|
||||
|
||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myDaoInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
|
||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
verify(myDaoInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myDaoInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateResource() throws IOException {
|
||||
String methodName = "testCreateResource";
|
||||
|
@ -123,11 +175,11 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
|||
}
|
||||
|
||||
/*
|
||||
* This is a weird way of verifying, but because this class
|
||||
* is a child of a superclass that has other test children
|
||||
* it's possible that other tests are hitting the server
|
||||
* at the same time
|
||||
*/
|
||||
* This is a weird way of verifying, but because this class
|
||||
* is a child of a superclass that has other test children
|
||||
* it's possible that other tests are hitting the server
|
||||
* at the same time
|
||||
*/
|
||||
@Test
|
||||
public void testCreateResourceInTransaction() throws IOException {
|
||||
String methodName = "testCreateResourceInTransaction";
|
||||
|
@ -143,16 +195,7 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
|||
entry.getRequest().setMethod(HTTPVerb.POST);
|
||||
entry.getRequest().setUrl("Patient");
|
||||
|
||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(bundle);
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
transaction(bundle);
|
||||
|
||||
/*
|
||||
* Server Interceptor
|
||||
|
@ -246,6 +289,72 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateNoOpResourceInTransaction() throws Exception {
|
||||
String methodName = "foo";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
String ptId = myPatientDao.create(pt).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleType.TRANSACTION);
|
||||
BundleEntryComponent entry = bundle.addEntry();
|
||||
entry.setFullUrl(ptId);
|
||||
entry.setResource(pt);
|
||||
entry.getRequest().setMethod(HTTPVerb.PUT);
|
||||
entry.getRequest().setUrl(ptId);
|
||||
|
||||
// Transaction time!
|
||||
transaction(bundle);
|
||||
|
||||
// Do it again but with an update that shouldn't actually create
|
||||
resetServerInterceptor();
|
||||
entry.getRequest().setIfNoneExist("Patient?name=" + methodName);
|
||||
transaction(bundle);
|
||||
|
||||
/*
|
||||
* Server Interceptor
|
||||
*/
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myServerInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
assertEquals(RestOperationTypeEnum.UPDATE, opTypeCaptor.getAllValues().get(1));
|
||||
|
||||
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
verify(myServerInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myServerInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
/*
|
||||
* DAO Interceptor
|
||||
*/
|
||||
|
||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myDaoInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
assertEquals(RestOperationTypeEnum.UPDATE, opTypeCaptor.getAllValues().get(1));
|
||||
|
||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
verify(myDaoInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
||||
verify(myDaoInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||
|
||||
}
|
||||
|
||||
private void transaction(Bundle theBundle) throws IOException {
|
||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(theBundle);
|
||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
try {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -135,6 +135,41 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test {
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(1, ourUpdatedObservations);
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionNoopUpdateDoesntTriggerNewDelivery() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
Observation obs = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification
|
||||
waitForQueueToDrain();
|
||||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(1, ourUpdatedObservations);
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||
|
||||
// Send an update with no changes
|
||||
obs.setId(obs.getIdElement().toUnqualifiedVersionless());
|
||||
myClient.update().resource(obs).execute();
|
||||
|
||||
// Should be no further deliveries
|
||||
Thread.sleep(1000);
|
||||
waitForQueueToDrain();
|
||||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(1, ourUpdatedObservations);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
package ca.uhn.fhir.jpa.search;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server - ElasticSearch Integration
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2018 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.hibernate.search.elasticsearch.analyzer.definition.ElasticsearchAnalysisDefinitionRegistryBuilder;
|
||||
import org.hibernate.search.elasticsearch.analyzer.definition.spi.ElasticsearchAnalysisDefinitionProvider;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -158,7 +158,7 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
|
|
@ -68,6 +68,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu2");
|
||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
retVal.setFetchSizeDefaultMaximum(10000);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu3");
|
||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
retVal.setFetchSizeDefaultMaximum(10000);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
|||
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseR4");
|
||||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
retVal.setFetchSizeDefaultMaximum(10000);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
|||
public PublicSecurityInterceptor() {
|
||||
String passwordsString = System.getProperty("fhir.tdlpass");
|
||||
String[] passwords = passwordsString.split(",");
|
||||
myTokens = new HashSet<String>(Arrays.asList(passwords));
|
||||
myTokens = new HashSet<>(Arrays.asList(passwords));
|
||||
|
||||
ourLog.info("We have {} valid security tokens", myTokens.size());
|
||||
}
|
||||
|
@ -27,7 +27,6 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
|||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
String authHeader = theRequestDetails.getHeader("Authorization");
|
||||
|
||||
//@formatter:off
|
||||
if (isBlank(authHeader)) {
|
||||
return new RuleBuilder()
|
||||
.deny().operation().named(BaseJpaSystemProvider.MARK_ALL_RESOURCES_FOR_REINDEXING).onServer().andThen()
|
||||
|
@ -35,8 +34,7 @@ public class PublicSecurityInterceptor extends AuthorizationInterceptor {
|
|||
.allowAll()
|
||||
.build();
|
||||
}
|
||||
//@formatter:off
|
||||
|
||||
|
||||
if (!authHeader.startsWith("Bearer ")) {
|
||||
throw new ForbiddenOperationException("Invalid bearer token, must be in the form \"Authorization: Bearer [token]\"");
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jpa</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.3.0-SNAPSHOT</version>
|
||||
<version>3.3.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>HAPI FHIR Structures - DSTU2.1 (2016May)</name>
|
||||
|
||||
|
@ -273,6 +273,22 @@
|
|||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Fragment-Host>
|
||||
ca.uhn.hapi.fhir.hapi-fhir-base
|
||||
</Fragment-Host>
|
||||
<Import-Package>
|
||||
javax.servlet*;resolution:=optional,
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue