Merge remote-tracking branch 'jamesagnew/master'
This commit is contained in:
commit
de9b59488b
|
@ -20,4 +20,4 @@ before_script:
|
|||
|
||||
script:
|
||||
# - mvn -e -B clean install && cd hapi-fhir-ra && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID clean test jacoco:report coveralls:report
|
||||
- mvn -Dci=true -e -B -P ALLMODULES,NOPARALLEL clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
|
||||
- mvn -Dci=true -e -B -P ALLMODULES,NOPARALLEL,ERRORPRONE clean install && cd hapi-fhir-jacoco && mvn -e -B -DTRAVIS_JOB_ID=$TRAVIS_JOB_ID jacoco:report coveralls:report
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# Help Wanted
|
||||
|
||||
This page is a work in progress!
|
||||
|
||||
It serves as a place to list potential help a new volunteer could offer.
|
||||
|
||||
* Investigate adding support for FHIR's RDF (Turtle) encoding to HAPI
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding/<project>=UTF-8
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
|
@ -5,6 +5,7 @@
|
|||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
@ -26,22 +27,37 @@
|
|||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>3.0</version>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<version>3.0</version>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-guice</artifactId>
|
||||
<version>1.18.1</version>
|
||||
<version>1.19.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ebaysf.web</groupId>
|
||||
<artifactId>cors-filter</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>1.2</version>
|
||||
<version>2.1-SNAPSHOT</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>
|
||||
</dependencies>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package embedded;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import org.ebaysf.web.cors.CORSFilter;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.servlet.GuiceServletContextListener;
|
||||
import com.sun.jersey.guice.JerseyServletModule;
|
||||
|
||||
public class ContextListener extends GuiceServletContextListener {
|
||||
|
||||
@Override
|
||||
protected Injector getInjector() {
|
||||
|
||||
return Guice.createInjector(new JerseyServletModule() {
|
||||
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
bind(CORSFilter.class).in(Singleton.class);
|
||||
filter("/*").through(CORSFilter.class);
|
||||
serve("/model/*").with(FhirRestfulServlet.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -6,8 +6,6 @@ import java.util.List;
|
|||
import javax.inject.Singleton;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
|
@ -29,29 +27,10 @@ public class FhirRestfulServlet extends RestfulServer {
|
|||
*/
|
||||
@Override
|
||||
public void initialize() {
|
||||
/*
|
||||
* Two resource providers are defined. Each one handles a specific type
|
||||
* of resource.
|
||||
*/
|
||||
final List<IResourceProvider> providers = new ArrayList<IResourceProvider>();
|
||||
providers.add(new SomeResourceProvider());
|
||||
setResourceProviders(providers);
|
||||
|
||||
/*
|
||||
* Use a narrative generator. This is a completely optional step, but
|
||||
* can be useful as it causes HAPI to generate narratives for resources
|
||||
* which don't otherwise have one.
|
||||
*/
|
||||
final INarrativeGenerator narrativeGen = new DefaultThymeleafNarrativeGenerator();
|
||||
getFhirContext().setNarrativeGenerator(narrativeGen);
|
||||
|
||||
/*
|
||||
* Tells HAPI to use content types which are not technically FHIR
|
||||
* compliant when a browser is detected as the requesting client. This
|
||||
* prevents browsers from trying to download resource responses instead
|
||||
* of displaying them inline which can be handy for troubleshooting.
|
||||
*/
|
||||
setUseBrowserFriendlyContentTypes(true);
|
||||
|
||||
registerInterceptor(new ResponseHighlighterInterceptor());
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
package embedded;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import javax.servlet.DispatcherType;
|
||||
|
@ -6,6 +7,7 @@ import javax.servlet.DispatcherType;
|
|||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.slf4j.bridge.SLF4JBridgeHandler;
|
||||
|
||||
import com.google.inject.servlet.GuiceFilter;
|
||||
|
||||
|
@ -13,13 +15,18 @@ public class ServerStartup {
|
|||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
|
||||
SLF4JBridgeHandler.removeHandlersForRootLogger();
|
||||
SLF4JBridgeHandler.install();
|
||||
|
||||
final Server server = new Server(9090);
|
||||
final ServletContextHandler sch = new ServletContextHandler(server, "/");
|
||||
sch.addEventListener(new ContextListener());
|
||||
sch.addFilter(GuiceFilter.class, "/*",
|
||||
EnumSet.of(DispatcherType.REQUEST));
|
||||
sch.addFilter(GuiceFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
sch.addServlet(DefaultServlet.class, "/");
|
||||
server.start();
|
||||
|
||||
// Service is now accessible through
|
||||
// http://localhost:9090/model/Practitioner
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,8 @@ import java.util.List;
|
|||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.model.dstu2.resource.Practitioner;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
|
@ -21,8 +23,9 @@ public class SomeResourceProvider implements IResourceProvider {
|
|||
@Search()
|
||||
public List<Practitioner> findPractitionersByName(
|
||||
@RequiredParam(name = Practitioner.SP_NAME) final StringDt theName) {
|
||||
throw new UnprocessableEntityException(
|
||||
"Please provide more than 4 characters for the name");
|
||||
// throw new UnprocessableEntityException(
|
||||
// "Please provide more than 4 characters for the name");
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
eclipse.preferences.version=1
|
||||
encoding//src/main/java=UTF-8
|
||||
encoding//src/test/java=UTF-8
|
||||
encoding/<project>=UTF-8
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
|
@ -0,0 +1,4 @@
|
|||
activeProfiles=
|
||||
eclipse.preferences.version=1
|
||||
resolveWorkspaceProjects=true
|
||||
version=1
|
|
@ -0,0 +1,81 @@
|
|||
<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-standalone-overlay-example</artifactId>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-war-plugin</artifactId>
|
||||
<configuration>
|
||||
<overlays>
|
||||
<overlay>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
</overlay>
|
||||
</overlays>
|
||||
<warName>fhirtester</warName>
|
||||
<failOnMissingWebXml>true</failOnMissingWebXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
<type>war</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
<classifier>classes</classifier>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject</groupId>
|
||||
<artifactId>guice</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.inject.extensions</groupId>
|
||||
<artifactId>guice-servlet</artifactId>
|
||||
<version>4.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-guice</artifactId>
|
||||
<version>1.19.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.ebaysf.web</groupId>
|
||||
<artifactId>cors-filter</artifactId>
|
||||
<version>1.0.1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,51 @@
|
|||
package embedded.example;
|
||||
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import org.ebaysf.web.cors.CORSFilter;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.servlet.GuiceServletContextListener;
|
||||
import com.sun.jersey.guice.JerseyServletModule;
|
||||
|
||||
public class ContextListener extends GuiceServletContextListener {
|
||||
|
||||
static String username;
|
||||
static String password;
|
||||
static String serverAddress;
|
||||
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent servletContextEvent) {
|
||||
super.contextInitialized(servletContextEvent);
|
||||
|
||||
username = servletContextEvent.getServletContext().getInitParameter("username") != null
|
||||
? servletContextEvent.getServletContext().getInitParameter("username")
|
||||
: null;
|
||||
password = servletContextEvent.getServletContext().getInitParameter("password") != null
|
||||
? servletContextEvent.getServletContext().getInitParameter("password")
|
||||
: null;
|
||||
serverAddress = servletContextEvent.getServletContext().getInitParameter("serverAddress") != null
|
||||
? servletContextEvent.getServletContext().getInitParameter("serverAddress")
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Injector getInjector() {
|
||||
return Guice.createInjector(new JerseyServletModule() {
|
||||
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
|
||||
AnnotationConfigWebApplicationContext webApp = new AnnotationConfigWebApplicationContext();
|
||||
webApp.setConfigLocation(FhirTesterConfig.class.getName());
|
||||
serve("/*").with(new DispatcherServlet(webApp));
|
||||
bind(CORSFilter.class).in(Singleton.class);
|
||||
filter("/*").through(CORSFilter.class);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package embedded.example;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
|
||||
import ca.uhn.fhir.to.FhirTesterMvcConfig;
|
||||
import ca.uhn.fhir.to.TesterConfig;
|
||||
import ca.uhn.fhir.util.ITestingUiClientFactory;
|
||||
|
||||
//@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
|
||||
*/
|
||||
@Configuration
|
||||
@Import(FhirTesterMvcConfig.class)
|
||||
public class FhirTesterConfig {
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
final TesterConfig retVal = new TesterConfig();
|
||||
retVal.addServer().withId("Test-Server").withFhirVersion(FhirVersionEnum.DSTU2)
|
||||
.withBaseUrl(ContextListener.serverAddress).withName("FHIR Server Test Front End");
|
||||
|
||||
if (!Strings.isNullOrEmpty(ContextListener.username)) {
|
||||
ITestingUiClientFactory clientFactory = new ITestingUiClientFactory() {
|
||||
|
||||
@Override
|
||||
public IGenericClient newClient(FhirContext theFhirContext, HttpServletRequest theRequest,
|
||||
String theServerBaseUrl) {
|
||||
// Create a client
|
||||
IGenericClient client = theFhirContext.newRestfulGenericClient(theServerBaseUrl);
|
||||
|
||||
// Register an interceptor which adds credentials
|
||||
client.registerInterceptor(
|
||||
new BasicAuthInterceptor(ContextListener.username, ContextListener.password));
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
};
|
||||
retVal.setClientFactory(clientFactory);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
// @formatter:on
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>hapi-fhir-android-realm</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -1,37 +0,0 @@
|
|||
package embedded;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import com.google.inject.servlet.GuiceServletContextListener;
|
||||
import com.sun.jersey.api.container.filter.GZIPContentEncodingFilter;
|
||||
import com.sun.jersey.api.core.ResourceConfig;
|
||||
import com.sun.jersey.guice.JerseyServletModule;
|
||||
|
||||
import filters.CharsetResponseFilter;
|
||||
import filters.CorsResponseFilter;
|
||||
|
||||
public class ContextListener extends GuiceServletContextListener {
|
||||
|
||||
@Override
|
||||
protected Injector getInjector() {
|
||||
|
||||
return Guice.createInjector(new JerseyServletModule() {
|
||||
|
||||
@Override
|
||||
protected void configureServlets() {
|
||||
final Map<String, String> params = ImmutableMap
|
||||
.<String, String> builder()
|
||||
.put(ResourceConfig.PROPERTY_CONTAINER_RESPONSE_FILTERS,
|
||||
Joiner.on(";").join(
|
||||
CharsetResponseFilter.class.getName(),
|
||||
CorsResponseFilter.class.getName(),
|
||||
GZIPContentEncodingFilter.class
|
||||
.getName())).build();
|
||||
serve("/model/*").with(FhirRestfulServlet.class, params);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package filters;
|
||||
|
||||
|
||||
import javax.ws.rs.core.HttpHeaders;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import com.sun.jersey.spi.container.ContainerRequest;
|
||||
import com.sun.jersey.spi.container.ContainerResponse;
|
||||
import com.sun.jersey.spi.container.ContainerResponseFilter;
|
||||
|
||||
public class CharsetResponseFilter implements ContainerResponseFilter {
|
||||
|
||||
@Override
|
||||
public ContainerResponse filter(final ContainerRequest request,
|
||||
final ContainerResponse response) {
|
||||
|
||||
final MediaType contentType = response.getMediaType();
|
||||
if (contentType != null) {
|
||||
response.getHttpHeaders().putSingle(HttpHeaders.CONTENT_TYPE,
|
||||
contentType.toString() + ";charset=UTF-8");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package filters;
|
||||
|
||||
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||
|
||||
import com.sun.jersey.spi.container.ContainerRequest;
|
||||
import com.sun.jersey.spi.container.ContainerResponse;
|
||||
import com.sun.jersey.spi.container.ContainerResponseFilter;
|
||||
|
||||
public class CorsResponseFilter implements ContainerResponseFilter {
|
||||
|
||||
@Override
|
||||
public ContainerResponse filter(final ContainerRequest req,
|
||||
final ContainerResponse contResp) {
|
||||
|
||||
final ResponseBuilder resp = Response.fromResponse(contResp
|
||||
.getResponse());
|
||||
resp.header("Access-Control-Allow-Origin", "*").header(
|
||||
"Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
||||
|
||||
final String reqHead = req
|
||||
.getHeaderValue("Access-Control-Request-Headers");
|
||||
|
||||
if (null != reqHead && !reqHead.equals("")) {
|
||||
resp.header("Access-Control-Allow-Headers", reqHead);
|
||||
}
|
||||
|
||||
contResp.setResponse(resp.build());
|
||||
return contResp;
|
||||
}
|
||||
|
||||
}
|
|
@ -82,87 +82,22 @@ public class FhirContext {
|
|||
private Map<String, Class<? extends IBaseResource>> myDefaultTypeForProfile = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
private volatile Map<String, RuntimeResourceDefinition> myIdToResourceDefinition = Collections.emptyMap();
|
||||
private boolean myInitialized;
|
||||
private boolean myInitializing;
|
||||
private HapiLocalizer myLocalizer = new HapiLocalizer();
|
||||
private volatile Map<String, BaseRuntimeElementDefinition<?>> myNameToElementDefinition = Collections.emptyMap();
|
||||
private volatile Map<String, RuntimeResourceDefinition> myNameToResourceDefinition = Collections.emptyMap();
|
||||
private volatile Map<String, Class<? extends IBaseResource>> myNameToResourceType;
|
||||
private volatile INarrativeGenerator myNarrativeGenerator;
|
||||
private volatile IParserErrorHandler myParserErrorHandler = new LenientErrorHandler();
|
||||
private ParserOptions myParserOptions = new ParserOptions();
|
||||
private Set<PerformanceOptionsEnum> myPerformanceOptions = new HashSet<PerformanceOptionsEnum>();
|
||||
private Collection<Class<? extends IBaseResource>> myResourceTypesToScan;
|
||||
private volatile IRestfulClientFactory myRestfulClientFactory;
|
||||
private volatile RuntimeChildUndeclaredExtensionDefinition myRuntimeChildUndeclaredExtensionDefinition;
|
||||
private final IFhirVersion myVersion;
|
||||
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
|
||||
private boolean myInitializing;
|
||||
private IContextValidationSupport<?, ?, ?, ?, ?, ?> myValidationSupport;
|
||||
private final IFhirVersion myVersion;
|
||||
|
||||
/**
|
||||
* Returns the validation support module configured for this context, creating a default
|
||||
* implementation if no module has been passed in via the {@link #setValidationSupport(IContextValidationSupport)}
|
||||
* method
|
||||
* @see #setValidationSupport(IContextValidationSupport)
|
||||
*/
|
||||
public IContextValidationSupport<?, ?, ?, ?, ?, ?> getValidationSupport() {
|
||||
if (myValidationSupport == null) {
|
||||
myValidationSupport = myVersion.createValidationSupport();
|
||||
}
|
||||
return myValidationSupport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FluentPath engine which can be used to exvaluate
|
||||
* path expressions over FHIR resources. Note that this engine will use the
|
||||
* {@link IContextValidationSupport context validation support} module which is
|
||||
* configured on the context at the time this method is called.
|
||||
* <p>
|
||||
* In other words, call {@link #setValidationSupport(IContextValidationSupport)} before
|
||||
* calling {@link #newFluentPath()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this feature was added for FHIR DSTU3 and is not available
|
||||
* for contexts configured to use an older version of FHIR. Calling this method
|
||||
* on a context for a previous version of fhir will result in an
|
||||
* {@link UnsupportedOperationException}
|
||||
* </p>
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public IFluentPath newFluentPath() {
|
||||
return myVersion.createFluentPathExecutor(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the validation support module to use for this context. The validation support module
|
||||
* is used to supply underlying infrastructure such as conformance resources (StructureDefinition, ValueSet, etc)
|
||||
* as well as to provide terminology services to modules such as the validator and FluentPath executor
|
||||
*/
|
||||
public void setValidationSupport(IContextValidationSupport<?, ?, ?, ?, ?, ?> theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
private ParserOptions myParserOptions = new ParserOptions();
|
||||
|
||||
/**
|
||||
* Returns the parser options object which will be used to supply default
|
||||
* options to newly created parsers
|
||||
*
|
||||
* @return The parser options - Will not return <code>null</code>
|
||||
*/
|
||||
public ParserOptions getParserOptions() {
|
||||
return myParserOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parser options object which will be used to supply default
|
||||
* options to newly created parsers
|
||||
*
|
||||
* @param theParserOptions The parser options object - Must not be <code>null</code>
|
||||
*/
|
||||
public void setParserOptions(ParserOptions theParserOptions) {
|
||||
Validate.notNull(theParserOptions, "theParserOptions must not be null");
|
||||
myParserOptions = theParserOptions;
|
||||
}
|
||||
private Map<FhirVersionEnum, Map<String, Class<? extends IBaseResource>>> myVersionToNameToResourceType = Collections.emptyMap();
|
||||
|
||||
/**
|
||||
* @deprecated It is recommended that you use one of the static initializer methods instead
|
||||
|
@ -348,6 +283,16 @@ public class FhirContext {
|
|||
return myNarrativeGenerator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parser options object which will be used to supply default
|
||||
* options to newly created parsers
|
||||
*
|
||||
* @return The parser options - Will not return <code>null</code>
|
||||
*/
|
||||
public ParserOptions getParserOptions() {
|
||||
return myParserOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured performance options
|
||||
*/
|
||||
|
@ -449,6 +394,20 @@ public class FhirContext {
|
|||
return myIdToResourceDefinition.get(theId);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Return an unmodifiable collection containing all known resource definitions
|
||||
// */
|
||||
// public Collection<RuntimeResourceDefinition> getResourceDefinitions() {
|
||||
//
|
||||
// Set<Class<? extends IBase>> datatypes = Collections.emptySet();
|
||||
// Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> existing = Collections.emptyMap();
|
||||
// HashMap<String, Class<? extends IBaseResource>> types = new HashMap<String, Class<? extends IBaseResource>>();
|
||||
// ModelScanner.scanVersionPropertyFile(datatypes, types, myVersion.getVersion(), existing);
|
||||
// for (int next : types.)
|
||||
//
|
||||
// return Collections.unmodifiableCollection(myIdToResourceDefinition.values());
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the scanned runtime models. This is an advanced feature which is generally only needed for extending the
|
||||
* core library.
|
||||
|
@ -476,6 +435,19 @@ public class FhirContext {
|
|||
return myRuntimeChildUndeclaredExtensionDefinition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the validation support module configured for this context, creating a default
|
||||
* implementation if no module has been passed in via the {@link #setValidationSupport(IContextValidationSupport)}
|
||||
* method
|
||||
* @see #setValidationSupport(IContextValidationSupport)
|
||||
*/
|
||||
public IContextValidationSupport<?, ?, ?, ?, ?, ?> getValidationSupport() {
|
||||
if (myValidationSupport == null) {
|
||||
myValidationSupport = myVersion.createValidationSupport();
|
||||
}
|
||||
return myValidationSupport;
|
||||
}
|
||||
|
||||
public IFhirVersion getVersion() {
|
||||
return myVersion;
|
||||
}
|
||||
|
@ -500,6 +472,28 @@ public class FhirContext {
|
|||
return myVersion.newBundleFactory(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FluentPath engine which can be used to exvaluate
|
||||
* path expressions over FHIR resources. Note that this engine will use the
|
||||
* {@link IContextValidationSupport context validation support} module which is
|
||||
* configured on the context at the time this method is called.
|
||||
* <p>
|
||||
* In other words, call {@link #setValidationSupport(IContextValidationSupport)} before
|
||||
* calling {@link #newFluentPath()}
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that this feature was added for FHIR DSTU3 and is not available
|
||||
* for contexts configured to use an older version of FHIR. Calling this method
|
||||
* on a context for a previous version of fhir will result in an
|
||||
* {@link UnsupportedOperationException}
|
||||
* </p>
|
||||
*
|
||||
* @since 2.2
|
||||
*/
|
||||
public IFluentPath newFluentPath() {
|
||||
return myVersion.createFluentPathExecutor(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and return a new JSON parser.
|
||||
*
|
||||
|
@ -783,6 +777,17 @@ public class FhirContext {
|
|||
myParserErrorHandler = theParserErrorHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the parser options object which will be used to supply default
|
||||
* options to newly created parsers
|
||||
*
|
||||
* @param theParserOptions The parser options object - Must not be <code>null</code>
|
||||
*/
|
||||
public void setParserOptions(ParserOptions theParserOptions) {
|
||||
Validate.notNull(theParserOptions, "theParserOptions must not be null");
|
||||
myParserOptions = theParserOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configured performance options
|
||||
*
|
||||
|
@ -818,6 +823,15 @@ public class FhirContext {
|
|||
this.myRestfulClientFactory = theRestfulClientFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the validation support module to use for this context. The validation support module
|
||||
* is used to supply underlying infrastructure such as conformance resources (StructureDefinition, ValueSet, etc)
|
||||
* as well as to provide terminology services to modules such as the validator and FluentPath executor
|
||||
*/
|
||||
public void setValidationSupport(IContextValidationSupport<?, ?, ?, ?, ?, ?> theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "cast" })
|
||||
private List<Class<? extends IElement>> toElementList(Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
if (theResourceTypes == null) {
|
||||
|
@ -850,6 +864,13 @@ public class FhirContext {
|
|||
return new FhirContext(FhirVersionEnum.DSTU2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2 DSTU2} (2016 May DSTU3 Snapshot)
|
||||
*/
|
||||
public static FhirContext forDstu2_1() {
|
||||
return new FhirContext(FhirVersionEnum.DSTU2_1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2_HL7ORG DSTU2} (using the Reference
|
||||
* Implementation Structures)
|
||||
|
@ -885,11 +906,4 @@ public class FhirContext {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2 DSTU2} (2016 May DSTU3 Snapshot)
|
||||
*/
|
||||
public static FhirContext forDstu2_1() {
|
||||
return new FhirContext(FhirVersionEnum.DSTU2_1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.util.Map.Entry;
|
|||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.IDatatype;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
|
@ -437,7 +438,7 @@ class ModelScanner {
|
|||
}
|
||||
|
||||
|
||||
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments, toTargetList(searchParam.target()));
|
||||
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments, toTargetList(searchParam.target()), RuntimeSearchParamStatusEnum.ACTIVE);
|
||||
theResourceDef.addSearchParam(param);
|
||||
nameToParam.put(param.getName(), param);
|
||||
}
|
||||
|
@ -457,7 +458,7 @@ class ModelScanner {
|
|||
compositeOf.add(param);
|
||||
}
|
||||
|
||||
RuntimeSearchParam param = new RuntimeSearchParam(searchParam.name(), searchParam.description(), searchParam.path(), RestSearchParameterTypeEnum.COMPOSITE, compositeOf, null, toTargetList(searchParam.target()));
|
||||
RuntimeSearchParam param = new RuntimeSearchParam(null, null, searchParam.name(), searchParam.description(), searchParam.path(), RestSearchParameterTypeEnum.COMPOSITE, compositeOf, null, toTargetList(searchParam.target()), RuntimeSearchParamStatusEnum.ACTIVE);
|
||||
theResourceDef.addSearchParam(param);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
|
||||
/*
|
||||
|
@ -29,7 +31,7 @@ import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
|||
*/
|
||||
|
||||
public class RuntimeSearchParam {
|
||||
|
||||
private final IIdType myId;
|
||||
private final List<RuntimeSearchParam> myCompositeOf;
|
||||
private final String myDescription;
|
||||
private final String myName;
|
||||
|
@ -37,15 +39,28 @@ public class RuntimeSearchParam {
|
|||
private final String myPath;
|
||||
private final Set<String> myTargets;
|
||||
private final Set<String> myProvidesMembershipInCompartments;
|
||||
private final RuntimeSearchParamStatusEnum myStatus;
|
||||
private final String myUri;
|
||||
|
||||
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List<RuntimeSearchParam> theCompositeOf,
|
||||
Set<String> theProvidesMembershipInCompartments, Set<String> theTargets) {
|
||||
public IIdType getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public String getUri() {
|
||||
return myUri;
|
||||
}
|
||||
|
||||
public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, List<RuntimeSearchParam> theCompositeOf,
|
||||
Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus) {
|
||||
super();
|
||||
myId = theId;
|
||||
myUri = theUri;
|
||||
myName = theName;
|
||||
myDescription = theDescription;
|
||||
myPath = thePath;
|
||||
myParamType = theParamType;
|
||||
myCompositeOf = theCompositeOf;
|
||||
myStatus = theStatus;
|
||||
if (theProvidesMembershipInCompartments != null && !theProvidesMembershipInCompartments.isEmpty()) {
|
||||
myProvidesMembershipInCompartments = Collections.unmodifiableSet(theProvidesMembershipInCompartments);
|
||||
} else {
|
||||
|
@ -62,8 +77,12 @@ public class RuntimeSearchParam {
|
|||
return myTargets;
|
||||
}
|
||||
|
||||
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments, Set<String> theTargets) {
|
||||
this(theName, theDescription, thePath, theParamType, null, theProvidesMembershipInCompartments, theTargets);
|
||||
public RuntimeSearchParamStatusEnum getStatus() {
|
||||
return myStatus;
|
||||
}
|
||||
|
||||
public RuntimeSearchParam(String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus) {
|
||||
this(null, null, theName, theDescription, thePath, theParamType, null, theProvidesMembershipInCompartments, theTargets, theStatus);
|
||||
}
|
||||
|
||||
public List<RuntimeSearchParam> getCompositeOf() {
|
||||
|
@ -108,4 +127,10 @@ public class RuntimeSearchParam {
|
|||
return myProvidesMembershipInCompartments;
|
||||
}
|
||||
|
||||
public enum RuntimeSearchParamStatusEnum {
|
||||
ACTIVE,
|
||||
DRAFT,
|
||||
RETIRED
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,15 @@ public interface ICompositeElement extends IElement {
|
|||
* Returns a list containing all child elements matching a given type
|
||||
*
|
||||
* @param theType The type to match. If set to null, all child elements will be returned
|
||||
*
|
||||
* @deprecated This method is not used by HAPI at this point, so there isn't much
|
||||
* point to keeping it around. We are not deleting it just so that we don't break
|
||||
* existing implementer code, but you do not need to supply an implementation
|
||||
* of this code in your own structures. Deprecated in HAPI FHIR 2.3 (Jan 2017).
|
||||
* See See <a href="https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/hapi-fhir/AeV2hTDt--E/6EOgRA8YBwAJ"> for
|
||||
* a discussion about this.
|
||||
*/
|
||||
@Deprecated
|
||||
<T extends IElement>
|
||||
List<T> getAllPopulatedChildElementsOfType(Class<T> theType);
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.rest.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -10,7 +12,7 @@ package ca.uhn.fhir.rest.annotation;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -22,19 +24,19 @@ package ca.uhn.fhir.rest.annotation;
|
|||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
//import ca.uhn.fhir.testmodel.Patient; // TODO: qualify this correctly
|
||||
|
||||
|
||||
/**
|
||||
* Parameter annotation which specifies a search parameter for a {@link Search} method.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value=ElementType.PARAMETER)
|
||||
public @interface OptionalParam {
|
||||
|
||||
public static final String ALLOW_CHAIN_ANY = "*";
|
||||
|
@ -42,55 +44,55 @@ public @interface OptionalParam {
|
|||
public static final String ALLOW_CHAIN_NOTCHAINED = "";
|
||||
|
||||
/**
|
||||
* For reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate which chain values (if any) are <b>not</b> valid
|
||||
* for the given parameter. Values here will supercede any values specified
|
||||
* in {@link #chainWhitelist()}
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
* For reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate which chain values (if any) are <b>not</b> valid
|
||||
* for the given parameter. Values here will supercede any values specified
|
||||
* in {@link #chainWhitelist()}
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
String[] chainBlacklist() default {};
|
||||
|
||||
/**
|
||||
* For reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate which chain values (if any) are valid for the given
|
||||
* parameter. If the list contains the value {@link #ALLOW_CHAIN_ANY}, all values are valid. (this is the default)
|
||||
* If the list contains the value {@link #ALLOW_CHAIN_NOTCHAINED}
|
||||
* then the reference param only supports the empty chain (i.e. the resource
|
||||
* ID).
|
||||
* <p>
|
||||
* Valid values for this parameter include:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_NOTCHAINED }</code> - Only allow resource reference (no chaining allowed for this parameter)</li>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_ANY }</code> - Allow any chaining at all (including a non chained value, <b>this is the default</b>)</li>
|
||||
* <li><code>chainWhitelist={ "foo", "bar" }</code> - Allow property.foo and property.bar</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Any values specified in
|
||||
* {@link #chainBlacklist()} will supercede (have priority over) values
|
||||
* here.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
String[] chainWhitelist() default {ALLOW_CHAIN_ANY};
|
||||
/**
|
||||
* For reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate which chain values (if any) are valid for the given
|
||||
* parameter. If the list contains the value {@link #ALLOW_CHAIN_ANY}, all values are valid. (this is the default)
|
||||
* If the list contains the value {@link #ALLOW_CHAIN_NOTCHAINED}
|
||||
* then the reference param only supports the empty chain (i.e. the resource
|
||||
* ID).
|
||||
* <p>
|
||||
* Valid values for this parameter include:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_NOTCHAINED }</code> - Only allow resource reference (no chaining allowed for this parameter)</li>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_ANY }</code> - Allow any chaining at all (including a non chained value, <b>this is the default</b>)</li>
|
||||
* <li><code>chainWhitelist={ "foo", "bar" }</code> - Allow property.foo and property.bar</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Any values specified in
|
||||
* {@link #chainBlacklist()} will supercede (have priority over) values
|
||||
* here.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
String[] chainWhitelist() default { ALLOW_CHAIN_ANY };
|
||||
|
||||
/**
|
||||
* For composite parameters ({@link CompositeParam}) this value may be
|
||||
* used to indicate the parameter type(s) which may be referenced by this param.
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link CompositeParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
Class<? extends IQueryParameterType>[] compositeTypes() default {};
|
||||
/**
|
||||
* For composite parameters ({@link CompositeParam}) this value may be
|
||||
* used to indicate the parameter type(s) which may be referenced by this param.
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link CompositeParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
Class<? extends IQueryParameterType>[] compositeTypes() default {};
|
||||
|
||||
/**
|
||||
/**
|
||||
* This is the name for the parameter. Generally this should be a
|
||||
* simple string (e.g. "name", or "identifier") which will be the name
|
||||
* of the URL parameter used to populate this method parameter.
|
||||
|
@ -109,13 +111,13 @@ public @interface OptionalParam {
|
|||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* For resource reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate the resource type(s) which may be referenced by this param.
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
Class<? extends IBaseResource>[] targetTypes() default {};
|
||||
/**
|
||||
* For resource reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate the resource type(s) which may be referenced by this param.
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
Class<? extends IBaseResource>[] targetTypes() default {};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package ca.uhn.fhir.rest.annotation;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* On a {@link Search} method, a parameter marked with this annotation
|
||||
* will receive search parameters not captured by other parameters.
|
||||
* <p>
|
||||
* Parameters with this annotation must be of type
|
||||
* {@code Map<String, List<String>>}
|
||||
* </p>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value=ElementType.PARAMETER)
|
||||
public @interface RawParam {
|
||||
// nothing
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.rest.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
|
@ -10,7 +12,7 @@ package ca.uhn.fhir.rest.annotation;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -22,18 +24,19 @@ package ca.uhn.fhir.rest.annotation;
|
|||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||
//import ca.uhn.fhir.testmodel.Patient; // TODO: qualify this correctly
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
/**
|
||||
* Parameter annotation which specifies a search parameter for a {@link Search} method.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(value=ElementType.PARAMETER)
|
||||
public @interface RequiredParam {
|
||||
|
||||
/**
|
||||
|
@ -45,32 +48,32 @@ public @interface RequiredParam {
|
|||
*/
|
||||
String[] chainBlacklist() default {};
|
||||
|
||||
/**
|
||||
* For reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate which chain values (if any) are valid for the given
|
||||
* parameter. If the list contains the value {@link OptionalParam#ALLOW_CHAIN_ANY}, all values are valid. (this is the default)
|
||||
* If the list contains the value {@link OptionalParam#ALLOW_CHAIN_NOTCHAINED}
|
||||
* then the reference param only supports the empty chain (i.e. the resource
|
||||
* ID).
|
||||
* <p>
|
||||
* Valid values for this parameter include:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_NOTCHAINED }</code> - Only allow resource reference (no chaining allowed for this parameter)</li>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_ANY }</code> - Allow any chaining at all (including a non chained value, <b>this is the default</b>)</li>
|
||||
* <li><code>chainWhitelist={ "foo", "bar" }</code> - Allow property.foo and property.bar</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Any values specified in
|
||||
* {@link #chainBlacklist()} will supercede (have priority over) values
|
||||
* here.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
String[] chainWhitelist() default {OptionalParam.ALLOW_CHAIN_ANY};
|
||||
/**
|
||||
* For reference parameters ({@link ReferenceParam}) this value may be
|
||||
* used to indicate which chain values (if any) are valid for the given
|
||||
* parameter. If the list contains the value {@link OptionalParam#ALLOW_CHAIN_ANY}, all values are valid. (this is the default)
|
||||
* If the list contains the value {@link OptionalParam#ALLOW_CHAIN_NOTCHAINED}
|
||||
* then the reference param only supports the empty chain (i.e. the resource
|
||||
* ID).
|
||||
* <p>
|
||||
* Valid values for this parameter include:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_NOTCHAINED }</code> - Only allow resource reference (no chaining allowed for this parameter)</li>
|
||||
* <li><code>chainWhitelist={ OptionalParam.ALLOW_CHAIN_ANY }</code> - Allow any chaining at all (including a non chained value, <b>this is the default</b>)</li>
|
||||
* <li><code>chainWhitelist={ "foo", "bar" }</code> - Allow property.foo and property.bar</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* Any values specified in
|
||||
* {@link #chainBlacklist()} will supercede (have priority over) values
|
||||
* here.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the parameter annotated with this annotation is not a {@link ReferenceParam},
|
||||
* this value must not be populated.
|
||||
* </p>
|
||||
*/
|
||||
String[] chainWhitelist() default { OptionalParam.ALLOW_CHAIN_ANY };
|
||||
|
||||
/**
|
||||
* For composite parameters ({@link CompositeParam}) this parameter may be used to indicate the parameter type(s) which may be referenced by this param.
|
||||
|
|
|
@ -23,6 +23,11 @@ package ca.uhn.fhir.rest.client.interceptor;
|
|||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Client interceptor which simply captures request and response objects and stores them so that they can be inspected after a client
|
||||
|
@ -55,8 +60,23 @@ public class CapturingInterceptor implements IClientInterceptor {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(IHttpResponse theRequest) {
|
||||
myLastResponse = theRequest;
|
||||
public void interceptResponse(IHttpResponse theResponse) {
|
||||
//Buffer the reponse to avoid errors when content has already been read and the entity is not repeatable
|
||||
try {
|
||||
if(theResponse.getResponse() instanceof HttpResponse) {
|
||||
HttpEntity entity = ((HttpResponse) theResponse.getResponse()).getEntity();
|
||||
if( entity != null && !entity.isRepeatable()){
|
||||
theResponse.bufferEntity();
|
||||
}
|
||||
} else {
|
||||
theResponse.bufferEntity();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new InternalErrorException("Unable to buffer the entity for capturing", e);
|
||||
}
|
||||
|
||||
|
||||
myLastResponse = theResponse;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -407,6 +407,8 @@ public class MethodUtil {
|
|||
parameter.setType(theContext, parameterType, innerCollectionType, outerCollectionType);
|
||||
MethodUtil.extractDescription(parameter, annotations);
|
||||
param = parameter;
|
||||
} else if (nextAnnotation instanceof RawParam) {
|
||||
param = new RawParamsParmeter(parameters);
|
||||
} else if (nextAnnotation instanceof IncludeParam) {
|
||||
Class<? extends Collection<Include>> instantiableCollectionType;
|
||||
Class<?> specType;
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.RawParam;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding.QualifierDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class RawParamsParmeter implements IParameter {
|
||||
|
||||
private final List<IParameter> myAllMethodParameters;
|
||||
|
||||
public RawParamsParmeter(List<IParameter> theParameters) {
|
||||
myAllMethodParameters = theParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
|
||||
throws InternalErrorException {
|
||||
// not supported on client for now
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
||||
HashMap<String, List<String>> retVal = null;
|
||||
|
||||
for (String nextName : theRequest.getParameters().keySet()) {
|
||||
if (nextName.startsWith("_")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QualifierDetails qualifiers = SearchMethodBinding.extractQualifiersFromParameterName(nextName);
|
||||
|
||||
boolean alreadyCaptured = false;
|
||||
for (IParameter nextParameter : myAllMethodParameters) {
|
||||
if (nextParameter instanceof SearchParameter) {
|
||||
SearchParameter nextSearchParam = (SearchParameter)nextParameter;
|
||||
if (nextSearchParam.getName().equals(qualifiers.getParamName())) {
|
||||
if (qualifiers.passes(nextSearchParam.getQualifierWhitelist(), nextSearchParam.getQualifierBlacklist())) {
|
||||
alreadyCaptured = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyCaptured) {
|
||||
if (retVal == null) {
|
||||
retVal = new HashMap<String, List<String>>();
|
||||
}
|
||||
retVal.put(nextName, Arrays.asList(theRequest.getParameters().get(nextName)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
|
||||
Validate.isTrue(theParameterType.equals(Map.class), "Parameter with @" + RawParam.class + " must be of type Map<String, List<String>>");
|
||||
}
|
||||
|
||||
}
|
|
@ -37,7 +37,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
|
@ -131,15 +130,26 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
|
||||
@Override
|
||||
public ReturnTypeEnum getReturnType() {
|
||||
// if (getContext().getVersion().getVersion() == FhirVersionEnum.DSTU1) {
|
||||
return ReturnTypeEnum.BUNDLE;
|
||||
// } else {
|
||||
// return ReturnTypeEnum.RESOURCE;
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
|
||||
|
||||
String clientPreference = theRequest.getHeader(Constants.HEADER_PREFER);
|
||||
boolean lenientHandling = false;
|
||||
if(clientPreference != null)
|
||||
{
|
||||
String[] preferences = clientPreference.split(";");
|
||||
for( String p : preferences){
|
||||
if("handling:lenient".equalsIgnoreCase(p))
|
||||
{
|
||||
lenientHandling = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (theRequest.getId() != null && myIdParamIndex == null) {
|
||||
ourLog.trace("Method {} doesn't match because ID is not null: {}", theRequest.getId());
|
||||
return false;
|
||||
|
@ -235,6 +245,9 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
}
|
||||
}
|
||||
Set<String> keySet = theRequest.getParameters().keySet();
|
||||
if(lenientHandling == true)
|
||||
return true;
|
||||
|
||||
if (myAllowUnknownParams == false) {
|
||||
for (String next : keySet) {
|
||||
if (!methodParamsTemp.contains(next)) {
|
||||
|
@ -271,7 +284,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider invokeServer(IRestfulServer theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
|
||||
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
|
||||
if (myIdParamIndex != null) {
|
||||
theMethodParams[myIdParamIndex] = theRequest.getId();
|
||||
}
|
||||
|
@ -389,14 +402,27 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
if (dotIdx < colonIdx) {
|
||||
retVal.setDotQualifier(theParamName.substring(dotIdx, colonIdx));
|
||||
retVal.setColonQualifier(theParamName.substring(colonIdx));
|
||||
retVal.setParamName(theParamName.substring(0, dotIdx));
|
||||
retVal.setWholeQualifier(theParamName.substring(dotIdx));
|
||||
} else {
|
||||
retVal.setColonQualifier(theParamName.substring(colonIdx, dotIdx));
|
||||
retVal.setDotQualifier(theParamName.substring(dotIdx));
|
||||
retVal.setParamName(theParamName.substring(0, colonIdx));
|
||||
retVal.setWholeQualifier(theParamName.substring(colonIdx));
|
||||
}
|
||||
} else if (dotIdx != -1) {
|
||||
retVal.setDotQualifier(theParamName.substring(dotIdx));
|
||||
retVal.setParamName(theParamName.substring(0, dotIdx));
|
||||
retVal.setWholeQualifier(theParamName.substring(dotIdx));
|
||||
} else if (colonIdx != -1) {
|
||||
retVal.setColonQualifier(theParamName.substring(colonIdx));
|
||||
retVal.setParamName(theParamName.substring(0, colonIdx));
|
||||
retVal.setWholeQualifier(theParamName.substring(colonIdx));
|
||||
} else {
|
||||
retVal.setParamName(theParamName);
|
||||
retVal.setColonQualifier(null);
|
||||
retVal.setDotQualifier(null);
|
||||
retVal.setWholeQualifier(null);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
@ -406,6 +432,8 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
|
||||
private String myColonQualifier;
|
||||
private String myDotQualifier;
|
||||
private String myParamName;
|
||||
private String myWholeQualifier;
|
||||
|
||||
public boolean passes(Set<String> theQualifierWhitelist, Set<String> theQualifierBlacklist) {
|
||||
if (theQualifierWhitelist != null) {
|
||||
|
@ -451,6 +479,14 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
return true;
|
||||
}
|
||||
|
||||
public void setParamName(String theParamName) {
|
||||
myParamName = theParamName;
|
||||
}
|
||||
|
||||
public String getParamName() {
|
||||
return myParamName;
|
||||
}
|
||||
|
||||
public void setColonQualifier(String theColonQualifier) {
|
||||
myColonQualifier = theColonQualifier;
|
||||
}
|
||||
|
@ -459,6 +495,14 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
myDotQualifier = theDotQualifier;
|
||||
}
|
||||
|
||||
public String getWholeQualifier() {
|
||||
return myWholeQualifier;
|
||||
}
|
||||
|
||||
public void setWholeQualifier(String theWholeQualifier) {
|
||||
myWholeQualifier = theWholeQualifier;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theSearchUrl, Map<String, List<String>> theParams) {
|
||||
|
|
|
@ -108,8 +108,10 @@ public class ParameterUtil {
|
|||
} else {
|
||||
if (b.length() > 0) {
|
||||
retVal.add(b.toString());
|
||||
b.setLength(0);
|
||||
} else {
|
||||
retVal.add(null);
|
||||
}
|
||||
b.setLength(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -61,7 +61,6 @@ import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
|||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.method.ElementsParameter;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
|
@ -378,7 +377,7 @@ public class RestfulServerUtils {
|
|||
break;
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
ourLog.debug("Invalid {} parameger: {}", Constants.PARAM_NARRATIVE, narrative[0]);
|
||||
ourLog.debug("Invalid {} parameter: {}", Constants.PARAM_NARRATIVE, narrative[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,7 @@ import java.io.Reader;
|
|||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
@ -41,7 +38,6 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.apache.http.entity.ContentType;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding.IRequestReader;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
|
@ -168,17 +164,6 @@ public class ServletRequestDetails extends RequestDetails {
|
|||
this.myServletResponse = myServletResponse;
|
||||
}
|
||||
|
||||
public static RequestDetails withResourceAndParams(String theResourceName, RequestTypeEnum theRequestType, Set<String> theParamNames) {
|
||||
RequestDetails retVal = new ServletRequestDetails();
|
||||
retVal.setResourceName(theResourceName);
|
||||
retVal.setRequestType(theRequestType);
|
||||
Map<String, String[]> paramNames = new HashMap<String, String[]>();
|
||||
for (String next : theParamNames) {
|
||||
paramNames.put(next, new String[0]);
|
||||
}
|
||||
retVal.setParameters(paramNames);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Charset getCharset() {
|
||||
|
|
|
@ -38,7 +38,7 @@ package org.hl7.fhir.utilities.xhtml;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -48,7 +48,6 @@ package org.hl7.fhir.utilities.xhtml;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
|
@ -378,10 +377,12 @@ public class XhtmlParser {
|
|||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public XhtmlDocument parse(String source, String entryName) throws FHIRFormatError, IOException {
|
||||
rdr = new StringReader(source);
|
||||
return parse(entryName);
|
||||
}
|
||||
|
||||
private void parseAttributes(XhtmlNode node) throws FHIRFormatError, IOException {
|
||||
while (Character.isWhitespace(peekChar()))
|
||||
readChar();
|
||||
|
@ -410,6 +411,7 @@ public class XhtmlParser {
|
|||
readChar();
|
||||
}
|
||||
}
|
||||
|
||||
private String parseAttributeValue(char term) throws IOException, FHIRFormatError {
|
||||
StringBuilder b = new StringBuilder();
|
||||
while (peekChar() != '\0' && peekChar() != '>' && (term != '\0' || peekChar() != '/') && peekChar() != term) {
|
||||
|
@ -422,6 +424,7 @@ public class XhtmlParser {
|
|||
readChar();
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
private void parseElement(XhtmlNode parent, List<XhtmlNode> parents, NSMap nsm) throws IOException, FHIRFormatError {
|
||||
QName name = new QName(readName());
|
||||
XhtmlNode node = parent.addTag(name.getName());
|
||||
|
@ -438,6 +441,7 @@ public class XhtmlParser {
|
|||
parseElementInner(node, newParents, nsm);
|
||||
}
|
||||
}
|
||||
|
||||
private void parseElementInner(XhtmlNode node, List<XhtmlNode> parents, NSMap nsm) throws FHIRFormatError, IOException {
|
||||
StringBuilder s = new StringBuilder();
|
||||
while (peekChar() != '\0' && !parents.contains(unwindPoint) && !(node == unwindPoint)) {
|
||||
|
@ -488,6 +492,7 @@ public class XhtmlParser {
|
|||
}
|
||||
addTextNode(node, s);
|
||||
}
|
||||
|
||||
private XhtmlNode parseFragment() throws IOException, FHIRException {
|
||||
skipWhiteSpace();
|
||||
if (peekChar() != '<')
|
||||
|
@ -558,6 +563,8 @@ public class XhtmlParser {
|
|||
s.append(XhtmlNode.NBSP);
|
||||
else if (c.equals("amp"))
|
||||
s.append('&');
|
||||
else if (c.equals("rsquo"))
|
||||
s.append('’');
|
||||
else if (c.equals("gt"))
|
||||
s.append('>');
|
||||
else if (c.equals("lt"))
|
||||
|
@ -860,7 +867,7 @@ public class XhtmlParser {
|
|||
StartElement firstEvent = (StartElement) xpp.nextEvent();
|
||||
res.setName(firstEvent.getSchemaType().getLocalPart());
|
||||
|
||||
for (Iterator<?> attrIter = firstEvent.getAttributes(); attrIter.hasNext(); ) {
|
||||
for (Iterator<?> attrIter = firstEvent.getAttributes(); attrIter.hasNext();) {
|
||||
Attribute nextAttr = (Attribute) attrIter.next();
|
||||
if (attributeIsOk(firstEvent.getName().getLocalPart(), nextAttr.getName().getLocalPart(), nextAttr.getValue()))
|
||||
res.getAttributes().put(nextAttr.getName().getLocalPart(), nextAttr.getValue());
|
||||
|
@ -873,11 +880,11 @@ public class XhtmlParser {
|
|||
break;
|
||||
}
|
||||
if (eventType == XMLEvent.CHARACTERS) {
|
||||
res.addText(((Characters)xpp).getData());
|
||||
res.addText(((Characters) xpp).getData());
|
||||
} else if (eventType == XMLEvent.COMMENT) {
|
||||
res.addComment(((Comment)xpp).getText());
|
||||
res.addComment(((Comment) xpp).getText());
|
||||
} else if (eventType == XMLEvent.START_ELEMENT) {
|
||||
StartElement nextStart = (StartElement)nextEvent;
|
||||
StartElement nextStart = (StartElement) nextEvent;
|
||||
if (elementIsOk(nextStart.getName().getLocalPart())) {
|
||||
res.getChildNodes().add(parseNode(xpp));
|
||||
}
|
||||
|
|
|
@ -43,11 +43,9 @@ ca.uhn.fhir.rest.param.ResourceParameter.noContentTypeInRequest=No Content-Type
|
|||
ca.uhn.fhir.rest.param.ResourceParameter.failedToParseRequest=Failed to parse request body as {0} resource. Error was: {1}
|
||||
|
||||
ca.uhn.fhir.parser.ParserState.wrongResourceTypeFound=Incorrect resource type found, expected "{0}" but found "{1}"
|
||||
|
||||
ca.uhn.fhir.rest.server.RestfulServer.getPagesNonHttpGet=Requests for _getpages must use HTTP GET
|
||||
ca.uhn.fhir.rest.server.RestfulServer.unknownMethod=Invalid request: The FHIR endpoint on this server does not know how to handle {0} operation[{1}] with parameters [{2}]
|
||||
ca.uhn.fhir.rest.server.RestfulServer.rootRequest=This is the base URL of FHIR server. Unable to handle this request, as it does not contain a resource type or operation name.
|
||||
|
||||
ca.uhn.fhir.validation.ValidationContext.unableToDetermineEncoding=Unable to determine encoding (e.g. XML / JSON) on validation input. Is this a valid FHIR resource body?
|
||||
ca.uhn.fhir.validation.FhirValidator.noPhlocWarningOnStartup=Phloc-schematron library not found on classpath, will not attempt to perform schematron validation
|
||||
ca.uhn.fhir.validation.FhirValidator.noPhlocError=Phloc-schematron library not found on classpath, can not enable perform schematron validation
|
||||
|
@ -81,6 +79,7 @@ ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.unableToDeleteNotFound=Unable to fin
|
|||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulCreate=Successfully created resource "{0}" in {1}ms
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulUpdate=Successfully updated resource "{0}" in {1}ms
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.successfulDeletes=Successfully deleted {0} resource(s) in {1}ms
|
||||
ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao.invalidSearchParameter=Unknown search parameter "{0}". Value search parameters for this search are: {1}
|
||||
|
||||
ca.uhn.fhir.jpa.dao.SearchBuilder.invalidQuantityPrefix=Unable to handle quantity prefix "{0}" for value: {1}
|
||||
ca.uhn.fhir.jpa.dao.SearchBuilder.invalidNumberPrefix=Unable to handle number prefix "{0}" for value: {1}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -447,6 +447,7 @@
|
|||
<configuration>
|
||||
<runOrder>alphabetical</runOrder>
|
||||
<argLine>${argLine} -Dfile.encoding=UTF-8 -Xmx1024m</argLine>
|
||||
<forkCount>0.6C</forkCount>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -523,14 +524,29 @@
|
|||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>target/generated-sources/tinder</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${basedir}/target/generated-sources/tinder</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${basedir}/target/generated-resources/tinder</directory>
|
||||
</resource>
|
||||
|
@ -553,6 +569,20 @@
|
|||
<skip-hib4>true</skip-hib4>
|
||||
</properties>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>NOPARALLEL</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkCount>1</forkCount>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<!-- <profile> <id>DIST</id> <build> <plugins> <plugin> <groupId>de.juplo</groupId> <artifactId>hibernate4-maven-plugin</artifactId> <configuration> <force>true</force> <target>SCRIPT</target> <skip>${skip-hib4}</skip>
|
||||
</configuration> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate_version}</version> </dependency> </dependencies> <executions>
|
||||
<execution> <id>o10g</id> <goals> <goal>export</goal> </goals> <phase>test</phase> <configuration> <hibernateDialect>org.hibernate.dialect.Oracle10gDialect</hibernateDialect> <outputFile>${project.build.directory}/schema_oracle_10g.sql</outputFile>
|
||||
|
|
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.config;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -29,7 +29,9 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.context.annotation.Primary;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParamExtractorDstu1;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParamRegistryDstu1;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu1;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
@ -39,9 +41,10 @@ import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
|||
public class BaseDstu1Config extends BaseConfig {
|
||||
private static FhirContext ourFhirContextDstu1;
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologySvc terminologyService() {
|
||||
return new HapiTerminologySvcDstu1();
|
||||
@Bean
|
||||
@Primary
|
||||
public FhirContext defaultFhirContext() {
|
||||
return fhirContextDstu1();
|
||||
}
|
||||
|
||||
@Bean(name = "myFhirContextDstu1")
|
||||
|
@ -53,19 +56,22 @@ public class BaseDstu1Config extends BaseConfig {
|
|||
return ourFhirContextDstu1;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public FhirContext defaultFhirContext() {
|
||||
return fhirContextDstu1();
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoDstu1", autowire = Autowire.BY_NAME)
|
||||
public ca.uhn.fhir.jpa.dao.IFhirSystemDao<List<IResource>, MetaDt> fhirSystemDaoDstu1() {
|
||||
ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu1 retVal = new ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu1();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public SearchParamExtractorDstu1 searchParamExtractor() {
|
||||
return new SearchParamExtractorDstu1();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISearchParamRegistry searchParamRegistry() {
|
||||
return new SearchParamRegistryDstu1();
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemProviderDstu1")
|
||||
public ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1 systemDaoDstu1() {
|
||||
ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1 retVal = new ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1();
|
||||
|
@ -73,9 +79,9 @@ public class BaseDstu1Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_TYPE)
|
||||
public SearchParamExtractorDstu1 searchParamExtractor() {
|
||||
return new SearchParamExtractorDstu1();
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologySvc terminologyService() {
|
||||
return new HapiTerminologySvcDstu1();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,9 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParamExtractorDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParamRegistryDstu2;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu2;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
|
@ -84,6 +86,11 @@ public class BaseDstu2Config extends BaseConfig {
|
|||
return new SearchParamExtractorDstu2();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISearchParamRegistry searchParamRegistry() {
|
||||
return new SearchParamRegistryDstu2();
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoDstu2", autowire = Autowire.BY_NAME)
|
||||
public IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDaoDstu2() {
|
||||
ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2 retVal = new ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2();
|
||||
|
|
|
@ -14,7 +14,7 @@ import org.hl7.fhir.dstu3.validation.IResourceValidator.BestPracticeWarningLevel
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -37,7 +37,9 @@ import ca.uhn.fhir.jpa.config.BaseConfig;
|
|||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamExtractorDstu3;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.SearchParamRegistryDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcDstu3;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
|
@ -50,16 +52,6 @@ import ca.uhn.fhir.validation.IValidatorModule;
|
|||
@EnableTransactionManagement
|
||||
public class BaseDstu3Config extends BaseConfig {
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologySvcDstu3 terminologyService() {
|
||||
return new HapiTerminologySvcDstu3();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologyLoaderSvc terminologyLoaderService() {
|
||||
return new TerminologyLoaderSvc();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public FhirContext fhirContextDstu3() {
|
||||
|
@ -93,6 +85,16 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
return searchDao;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public SearchParamExtractorDstu3 searchParamExtractor() {
|
||||
return new SearchParamExtractorDstu3();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISearchParamRegistry searchParamRegistry() {
|
||||
return new SearchParamRegistryDstu3();
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoDstu3", autowire = Autowire.BY_NAME)
|
||||
public IFhirSystemDao<org.hl7.fhir.dstu3.model.Bundle, org.hl7.fhir.dstu3.model.Meta> systemDaoDstu3() {
|
||||
ca.uhn.fhir.jpa.dao.dstu3.FhirSystemDaoDstu3 retVal = new ca.uhn.fhir.jpa.dao.dstu3.FhirSystemDaoDstu3();
|
||||
|
@ -107,23 +109,27 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(autowire = Autowire.BY_NAME, name = "myJpaValidationSupportChainDstu3")
|
||||
public IValidationSupport validationSupportChainDstu3() {
|
||||
return new JpaValidationSupportChainDstu3();
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologyLoaderSvc terminologyLoaderService() {
|
||||
return new TerminologyLoaderSvc();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public SearchParamExtractorDstu3 searchParamExtractor() {
|
||||
return new SearchParamExtractorDstu3();
|
||||
public IHapiTerminologySvcDstu3 terminologyService() {
|
||||
return new HapiTerminologySvcDstu3();
|
||||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_TYPE)
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public TerminologyUploaderProviderDstu3 terminologyUploaderProvider() {
|
||||
TerminologyUploaderProviderDstu3 retVal = new TerminologyUploaderProviderDstu3();
|
||||
retVal.setContext(fhirContextDstu3());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(autowire = Autowire.BY_NAME, name = "myJpaValidationSupportChainDstu3")
|
||||
public IValidationSupport validationSupportChainDstu3() {
|
||||
return new JpaValidationSupportChainDstu3();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -130,7 +130,13 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
|||
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.method.QualifiedParamList;
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.param.UriAndListParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -148,16 +154,17 @@ import ca.uhn.fhir.util.OperationOutcomeUtil;
|
|||
|
||||
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||
|
||||
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
||||
public static final long INDEX_STATUS_INDEXED = Long.valueOf(1L);
|
||||
|
||||
public static final long INDEX_STATUS_INDEXING_FAILED = Long.valueOf(2L);
|
||||
public static final String NS_JPA_PROFILE = "https://github.com/jamesagnew/hapi-fhir/ns/jpa/profile";
|
||||
public static final String OO_SEVERITY_ERROR = "error";
|
||||
public static final String OO_SEVERITY_INFO = "information";
|
||||
public static final String OO_SEVERITY_WARN = "warning";
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
|
||||
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
|
||||
|
||||
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
||||
/**
|
||||
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
|
||||
*/
|
||||
|
@ -166,8 +173,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
|
||||
*/
|
||||
static final Map<String, Class<? extends IQueryParameterType>> RESOURCE_META_PARAMS;
|
||||
|
||||
public static final String UCUM_NS = "http://unitsofmeasure.org";
|
||||
|
||||
static {
|
||||
Map<String, Class<? extends IQueryParameterType>> resourceMetaParams = new HashMap<String, Class<? extends IQueryParameterType>>();
|
||||
Map<String, Class<? extends IQueryParameterAnd<?>>> resourceMetaAndParams = new HashMap<String, Class<? extends IQueryParameterAnd<?>>>();
|
||||
|
@ -184,7 +191,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
RESOURCE_META_PARAMS = Collections.unmodifiableMap(resourceMetaParams);
|
||||
RESOURCE_META_AND_PARAMS = Collections.unmodifiableMap(resourceMetaAndParams);
|
||||
}
|
||||
|
||||
@Autowired(required = true)
|
||||
private DaoConfig myConfig;
|
||||
|
||||
|
@ -213,9 +219,18 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
@Autowired
|
||||
private ISearchParamExtractor mySearchParamExtractor;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
@Autowired
|
||||
private ISearchResultDao mySearchResultDao;
|
||||
|
||||
protected void clearRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getUserData().remove(PROCESSING_SUB_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
protected void createForcedIdIfNeeded(ResourceTable theEntity, IIdType theId) {
|
||||
if (theId.isEmpty() == false && theId.hasIdPart()) {
|
||||
if (isValidPid(theId)) {
|
||||
|
@ -530,6 +545,17 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return (IFhirResourceDao<R>) myResourceTypeToDao.get(theType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName) {
|
||||
Map<String, RuntimeSearchParam> params = mySearchParamRegistry.getActiveSearchParams(theResourceDef.getName());
|
||||
return params.get(theParamName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||
return mySearchParamRegistry.getActiveSearchParams(theResourceDef.getName()).values();
|
||||
}
|
||||
|
||||
protected TagDefinition getTag(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<TagDefinition> cq = builder.createQuery(TagDefinition.class);
|
||||
|
@ -646,6 +672,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
theProvider.setSearchResultDao(mySearchResultDao);
|
||||
}
|
||||
|
||||
protected void markRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getUserData().put(PROCESSING_SUB_REQUEST, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyInterceptors(RestOperationTypeEnum theOperationType, ActionRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails.getId() != null && theRequestDetails.getId().hasResourceType() && isNotBlank(theRequestDetails.getResourceType())) {
|
||||
if (theRequestDetails.getId().getResourceType().equals(theRequestDetails.getResourceType()) == false) {
|
||||
|
@ -666,18 +698,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
protected void markRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getUserData().put(PROCESSING_SUB_REQUEST, Boolean.TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getUserData().remove(PROCESSING_SUB_REQUEST);
|
||||
}
|
||||
}
|
||||
|
||||
public String parseContentTextIntoWords(IBaseResource theResource) {
|
||||
StringBuilder retVal = new StringBuilder();
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
@ -914,7 +934,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the first time.
|
||||
* Subclasses may override to provide behaviour. Called when a resource has been inserted into the database for the first time.
|
||||
*
|
||||
* @param theEntity
|
||||
* The entity being updated (Do not modify the entity! Undefined behaviour will occur!)
|
||||
|
@ -928,7 +948,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override to provide behaviour. Called when a resource has been inserved into the database for the first time.
|
||||
* Subclasses may override to provide behaviour. Called when a pre-existing resource has been updated in the database
|
||||
*
|
||||
* @param theEntity
|
||||
* The resource
|
||||
|
@ -943,7 +963,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
public <R extends IBaseResource> Set<Long> processMatchUrl(String theMatchUrl, Class<R> theResourceType) {
|
||||
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
|
||||
|
||||
SearchParameterMap paramMap = translateMatchUrl(myContext, theMatchUrl, resourceDef);
|
||||
SearchParameterMap paramMap = translateMatchUrl(this, myContext, theMatchUrl, resourceDef);
|
||||
paramMap.setPersistResults(false);
|
||||
|
||||
if (paramMap.isEmpty() && paramMap.getLastUpdated() == null) {
|
||||
|
@ -962,24 +982,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
throw new NotImplementedException("");
|
||||
}
|
||||
|
||||
// protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
|
||||
// MetaDt retVal = new MetaDt();
|
||||
// for (TagDefinition next : tagDefinitions) {
|
||||
// switch (next.getTagType()) {
|
||||
// case PROFILE:
|
||||
// retVal.addProfile(next.getCode());
|
||||
// break;
|
||||
// case SECURITY_LABEL:
|
||||
// retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
// break;
|
||||
// case TAG:
|
||||
// retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return retVal;
|
||||
// }
|
||||
|
||||
public void setConfig(DaoConfig theConfig) {
|
||||
myConfig = theConfig;
|
||||
}
|
||||
|
@ -1698,27 +1700,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
}
|
||||
|
||||
protected static List<NameValuePair> translateMatchUrl(String theMatchUrl) {
|
||||
List<NameValuePair> parameters;
|
||||
String matchUrl = theMatchUrl;
|
||||
int questionMarkIndex = matchUrl.indexOf('?');
|
||||
if (questionMarkIndex != -1) {
|
||||
matchUrl = matchUrl.substring(questionMarkIndex + 1);
|
||||
}
|
||||
matchUrl = matchUrl.replace("|", "%7C");
|
||||
matchUrl = matchUrl.replace("=>=", "=%3E%3D");
|
||||
matchUrl = matchUrl.replace("=<=", "=%3C%3D");
|
||||
matchUrl = matchUrl.replace("=>", "=%3E");
|
||||
matchUrl = matchUrl.replace("=<", "=%3C");
|
||||
if (matchUrl.contains(" ")) {
|
||||
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)");
|
||||
}
|
||||
|
||||
parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&');
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public static SearchParameterMap translateMatchUrl(FhirContext theContext, String theMatchUrl, RuntimeResourceDefinition resourceDef) {
|
||||
public static SearchParameterMap translateMatchUrl(IDao theCallingDao, FhirContext theContext, String theMatchUrl, RuntimeResourceDefinition resourceDef) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
List<NameValuePair> parameters = translateMatchUrl(theMatchUrl);
|
||||
|
||||
|
@ -1788,7 +1770,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
} else if (nextParamName.startsWith("_")) {
|
||||
// ignore these since they aren't search params (e.g. _sort)
|
||||
} else {
|
||||
RuntimeSearchParam paramDef = resourceDef.getSearchParam(nextParamName);
|
||||
RuntimeSearchParam paramDef = theCallingDao.getSearchParamByName(resourceDef, nextParamName);
|
||||
if (paramDef == null) {
|
||||
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - Resource type " + resourceDef.getName() + " does not have a parameter with name: " + nextParamName);
|
||||
}
|
||||
|
@ -1800,6 +1782,26 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return paramMap;
|
||||
}
|
||||
|
||||
protected static List<NameValuePair> translateMatchUrl(String theMatchUrl) {
|
||||
List<NameValuePair> parameters;
|
||||
String matchUrl = theMatchUrl;
|
||||
int questionMarkIndex = matchUrl.indexOf('?');
|
||||
if (questionMarkIndex != -1) {
|
||||
matchUrl = matchUrl.substring(questionMarkIndex + 1);
|
||||
}
|
||||
matchUrl = matchUrl.replace("|", "%7C");
|
||||
matchUrl = matchUrl.replace("=>=", "=%3E%3D");
|
||||
matchUrl = matchUrl.replace("=<=", "=%3C%3D");
|
||||
matchUrl = matchUrl.replace("=>", "=%3E");
|
||||
matchUrl = matchUrl.replace("=<", "=%3C");
|
||||
if (matchUrl.contains(" ")) {
|
||||
throw new InvalidRequestException("Failed to parse match URL[" + theMatchUrl + "] - URL is invalid (must not contain spaces)");
|
||||
}
|
||||
|
||||
parameters = URLEncodedUtils.parse((matchUrl), Constants.CHARSET_UTF8, '&');
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public static void validateResourceType(BaseHasResource theEntity, String theResourceName) {
|
||||
if (!theResourceName.equals(theEntity.getResourceType())) {
|
||||
throw new ResourceNotFoundException(
|
||||
|
|
|
@ -22,15 +22,29 @@ package ca.uhn.fhir.jpa.dao;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||
import org.hl7.fhir.instance.model.api.IBaseMetaType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
@ -43,22 +57,44 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamUriDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||
import ca.uhn.fhir.jpa.entity.BaseTag;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.entity.TagTypeEnum;
|
||||
import ca.uhn.fhir.jpa.interceptor.IJpaServerInterceptor;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.util.DeleteConflict;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils;
|
||||
import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.PatchTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.method.QualifiedParamList;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||
import ca.uhn.fhir.rest.method.SearchMethodBinding.QualifierDetails;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
|
@ -74,6 +110,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
protected IResourceTableDao myResourceTableDao;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myPlatformTransactionManager;
|
||||
@Autowired
|
||||
private IResourceHistoryTableDao myResourceHistoryTableDao;
|
||||
|
@ -86,6 +124,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
@Autowired()
|
||||
protected ISearchResultDao mySearchResultDao;
|
||||
private String mySecondaryPrimaryKeyParamName;
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySerarchParamRegistry;
|
||||
@Autowired()
|
||||
protected IHapiTerminologySvc myTerminologySvc;
|
||||
|
||||
|
@ -662,13 +702,37 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome patch(IIdType theId, PatchTypeEnum thePatchType, String thePatchBody, RequestDetails theRequestDetails) {
|
||||
ResourceTable entityToUpdate = readEntityLatestVersion(theId);
|
||||
if (theId.hasVersionIdPart()) {
|
||||
if (theId.getVersionIdPartAsLong() != entityToUpdate.getVersion()) {
|
||||
throw new ResourceVersionConflictException("Version " + theId.getVersionIdPart() + " is not the most recent version of this resource, unable to apply patch");
|
||||
}
|
||||
}
|
||||
|
||||
validateResourceType(entityToUpdate);
|
||||
|
||||
IBaseResource resourceToUpdate = toResource(entityToUpdate, false);
|
||||
IBaseResource destination;
|
||||
if (thePatchType == PatchTypeEnum.JSON_PATCH) {
|
||||
destination = JsonPatchUtils.apply(getContext(), resourceToUpdate, thePatchBody);
|
||||
} else {
|
||||
destination = XmlPatchUtils.apply(getContext(), resourceToUpdate, thePatchBody);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T destinationCasted = (T) destination;
|
||||
return update(destinationCasted, null, true, theRequestDetails);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(myResourceType);
|
||||
myResourceName = def.getName();
|
||||
|
||||
if (mySecondaryPrimaryKeyParamName != null) {
|
||||
RuntimeSearchParam sp = def.getSearchParam(mySecondaryPrimaryKeyParamName);
|
||||
RuntimeSearchParam sp = getSearchParamByName(def, mySecondaryPrimaryKeyParamName);
|
||||
if (sp == null) {
|
||||
throw new ConfigurationException("Unknown search param on resource[" + myResourceName + "] for secondary key[" + mySecondaryPrimaryKeyParamName + "]");
|
||||
}
|
||||
|
@ -870,7 +934,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
|
||||
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao,
|
||||
myTerminologySvc);
|
||||
myTerminologySvc, mySerarchParamRegistry);
|
||||
builder.setType(getResourceType(), getResourceName());
|
||||
return builder.search(theParams);
|
||||
}
|
||||
|
@ -899,7 +963,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
theParams.setPersistResults(false);
|
||||
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao,
|
||||
myTerminologySvc);
|
||||
myTerminologySvc, mySerarchParamRegistry);
|
||||
builder.setType(getResourceType(), getResourceName());
|
||||
builder.search(theParams);
|
||||
return builder.doGetPids();
|
||||
|
@ -985,6 +1049,39 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translateRawParameters(Map<String, List<String>> theSource, SearchParameterMap theTarget) {
|
||||
if (theSource == null || theSource.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, RuntimeSearchParam> searchParams = mySerarchParamRegistry.getActiveSearchParams(getResourceName());
|
||||
|
||||
Set<String> paramNames = theSource.keySet();
|
||||
for (String nextParamName : paramNames) {
|
||||
QualifierDetails qualifiedParamName = SearchMethodBinding.extractQualifiersFromParameterName(nextParamName);
|
||||
RuntimeSearchParam param = searchParams.get(qualifiedParamName.getParamName());
|
||||
if (param == null) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "invalidSearchParameter", qualifiedParamName.getParamName(), new TreeSet<String>(searchParams.keySet()));
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
|
||||
// Should not be null since the check above would have caught it
|
||||
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(myResourceName);
|
||||
RuntimeSearchParam paramDef = getSearchParamByName(resourceDef, qualifiedParamName.getParamName());
|
||||
|
||||
for (String nextValue : theSource.get(nextParamName)) {
|
||||
if (isNotBlank(nextValue)) {
|
||||
QualifiedParamList qualifiedParam = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifiedParamName.getWholeQualifier(), nextValue);
|
||||
List<QualifiedParamList> paramList = Collections.singletonList(qualifiedParam);
|
||||
IQueryParameterAnd<?> parsedParam = MethodUtil.parseQueryParams(getContext(), paramDef, nextParamName, paramList);
|
||||
theTarget.add(qualifiedParamName.getParamName(), parsedParam);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource) {
|
||||
return update(theResource, null, null);
|
||||
|
@ -1076,30 +1173,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return outcome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome patch(IIdType theId, PatchTypeEnum thePatchType, String thePatchBody, RequestDetails theRequestDetails) {
|
||||
ResourceTable entityToUpdate = readEntityLatestVersion(theId);
|
||||
if (theId.hasVersionIdPart()) {
|
||||
if (theId.getVersionIdPartAsLong() != entityToUpdate.getVersion()) {
|
||||
throw new ResourceVersionConflictException("Version " + theId.getVersionIdPart() + " is not the most recent version of this resource, unable to apply patch");
|
||||
}
|
||||
}
|
||||
|
||||
validateResourceType(entityToUpdate);
|
||||
|
||||
IBaseResource resourceToUpdate = toResource(entityToUpdate, false);
|
||||
IBaseResource destination;
|
||||
if (thePatchType == PatchTypeEnum.JSON_PATCH) {
|
||||
destination = JsonPatchUtils.apply(getContext(), resourceToUpdate, thePatchBody);
|
||||
} else {
|
||||
destination = XmlPatchUtils.apply(getContext(), resourceToUpdate, thePatchBody);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T destinationCasted = (T) destination;
|
||||
return update(destinationCasted, null, true, theRequestDetails);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, RequestDetails theRequestDetails) {
|
||||
|
|
|
@ -21,9 +21,12 @@ package ca.uhn.fhir.jpa.dao;
|
|||
*/
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
|
@ -37,17 +40,37 @@ import ca.uhn.fhir.util.FhirTerser;
|
|||
public abstract class BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
||||
protected static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
||||
public static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
||||
|
||||
@Autowired
|
||||
private FhirContext myContext;
|
||||
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
public BaseSearchParamExtractor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public BaseSearchParamExtractor(FhirContext theCtx) {
|
||||
public BaseSearchParamExtractor(FhirContext theCtx, ISearchParamRegistry theSearchParamRegistry) {
|
||||
myContext = theCtx;
|
||||
mySearchParamRegistry = theSearchParamRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
|
||||
List<PathAndRef> refs = new ArrayList<PathAndRef>();
|
||||
String[] nextPathsSplit = theNextSpDef.getPath().split("\\|");
|
||||
for (String nextPath : nextPathsSplit) {
|
||||
nextPath = nextPath.trim();
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null) {
|
||||
continue;
|
||||
}
|
||||
refs.add(new PathAndRef(nextPath, nextObject));
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
|
||||
|
@ -70,26 +93,18 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
return myContext;
|
||||
}
|
||||
|
||||
protected Collection<RuntimeSearchParam> getSearchParams(IBaseResource theResource) {
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
Collection<RuntimeSearchParam> retVal = mySearchParamRegistry.getActiveSearchParams(def.getName()).values();
|
||||
List<RuntimeSearchParam> defaultList= Collections.emptyList();
|
||||
retVal = ObjectUtils.defaultIfNull(retVal, defaultList);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setContextForUnitTest(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
|
||||
List<PathAndRef> refs = new ArrayList<PathAndRef>();
|
||||
String[] nextPathsSplit = theNextSpDef.getPath().split("\\|");
|
||||
for (String nextPath : nextPathsSplit) {
|
||||
nextPath = nextPath.trim();
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null) {
|
||||
continue;
|
||||
}
|
||||
refs.add(new PathAndRef(nextPath, nextObject));
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
|
||||
public abstract class BaseSearchParamRegistry implements ISearchParamRegistry {
|
||||
|
||||
private static final Map<String, RuntimeSearchParam> EMPTY_SP_MAP = Collections.emptyMap();
|
||||
|
||||
private Map<String, Map<String, RuntimeSearchParam>> myBuiltInSearchParams;
|
||||
|
||||
@Autowired
|
||||
private FhirContext myCtx;
|
||||
|
||||
@Autowired
|
||||
private Collection<IFhirResourceDao<?>> myDaos;
|
||||
|
||||
public BaseSearchParamRegistry() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
public Map<String, Map<String, RuntimeSearchParam>> getBuiltInSearchParams() {
|
||||
return myBuiltInSearchParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String,RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
||||
Validate.notBlank(theResourceName, "theResourceName must not be blank or null");
|
||||
|
||||
return myBuiltInSearchParams.get(theResourceName);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
Map<String, Map<String, RuntimeSearchParam>> resourceNameToSearchParams = new HashMap<String, Map<String,RuntimeSearchParam>>();
|
||||
|
||||
for (IFhirResourceDao<?> nextDao : myDaos) {
|
||||
RuntimeResourceDefinition nextResDef = myCtx.getResourceDefinition(nextDao.getResourceType());
|
||||
String nextResourceName = nextResDef.getName();
|
||||
HashMap<String, RuntimeSearchParam> nameToParam = new HashMap<String, RuntimeSearchParam>();
|
||||
resourceNameToSearchParams.put(nextResourceName, nameToParam);
|
||||
|
||||
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
|
||||
nameToParam.put(nextSp.getName(), nextSp);
|
||||
}
|
||||
}
|
||||
|
||||
myBuiltInSearchParams = Collections.unmodifiableMap(resourceNameToSearchParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RuntimeSearchParam> getAllSearchParams(String theResourceName) {
|
||||
Validate.notBlank(theResourceName, "theResourceName must not be null or blank");
|
||||
|
||||
Map<String, RuntimeSearchParam> map = myBuiltInSearchParams.get(theResourceName);
|
||||
map = ObjectUtils.defaultIfNull(map, EMPTY_SP_MAP);
|
||||
return Collections.unmodifiableCollection(map.values());
|
||||
}
|
||||
|
||||
}
|
|
@ -16,7 +16,7 @@ import org.apache.commons.lang3.time.DateUtils;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -43,11 +43,13 @@ public class DaoConfig {
|
|||
private boolean myAllowInlineMatchUrlReferences = false;
|
||||
|
||||
private boolean myAllowMultipleDelete;
|
||||
private boolean myDefaultSearchParamsCanBeOverridden = false;
|
||||
// ***
|
||||
// update setter javadoc if default changes
|
||||
// ***
|
||||
private int myDeferIndexingForCodesystemsOfSize = 2000;
|
||||
private boolean myDeleteStaleSearches = true;
|
||||
|
||||
// ***
|
||||
// update setter javadoc if default changes
|
||||
// ***
|
||||
|
@ -63,11 +65,11 @@ public class DaoConfig {
|
|||
private boolean myIndexContainedResources = true;
|
||||
|
||||
private List<IServerInterceptor> myInterceptors;
|
||||
|
||||
// ***
|
||||
// update setter javadoc if default changes
|
||||
// ***
|
||||
private int myMaximumExpansionSize = 5000;
|
||||
|
||||
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
|
||||
|
||||
private boolean mySchedulingDisabled;
|
||||
|
@ -91,6 +93,7 @@ public class DaoConfig {
|
|||
public int getDeferIndexingForCodesystemsOfSize() {
|
||||
return myDeferIndexingForCodesystemsOfSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of milliseconds that search results for a given client search
|
||||
* should be preserved before being purged from the database.
|
||||
|
@ -101,8 +104,9 @@ public class DaoConfig {
|
|||
* (next/prev links in search response bundles) will become invalid. Defaults to 1 hour.
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* @see To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
|
||||
* </p>
|
||||
* </p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
|
@ -126,7 +130,7 @@ public class DaoConfig {
|
|||
*
|
||||
* @see #setInterceptors(List)
|
||||
* @deprecated As of 2.2 this method is deprecated. There is no good reason to register an interceptor
|
||||
* with the DaoConfig and not with the server via {@link RestfulServer#registerInterceptor(IServerInterceptor)}
|
||||
* with the DaoConfig and not with the server via {@link RestfulServer#registerInterceptor(IServerInterceptor)}
|
||||
*/
|
||||
@Deprecated
|
||||
public List<IServerInterceptor> getInterceptors() {
|
||||
|
@ -142,15 +146,19 @@ public class DaoConfig {
|
|||
public int getMaximumExpansionSize() {
|
||||
return myMaximumExpansionSize;
|
||||
}
|
||||
|
||||
public ResourceEncodingEnum getResourceEncoding() {
|
||||
return myResourceEncoding;
|
||||
}
|
||||
|
||||
public long getSubscriptionPollDelay() {
|
||||
return mySubscriptionPollDelay;
|
||||
}
|
||||
|
||||
public Long getSubscriptionPurgeInactiveAfterMillis() {
|
||||
return mySubscriptionPurgeInactiveAfterMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting may be used to advise the server that any references found in
|
||||
* resources that have any of the base URLs given here will be replaced with
|
||||
|
@ -165,6 +173,7 @@ public class DaoConfig {
|
|||
public Set<String> getTreatBaseUrlsAsLocal() {
|
||||
return myTreatBaseUrlsAsLocal;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -193,16 +202,34 @@ public class DaoConfig {
|
|||
public boolean isAllowExternalReferences() {
|
||||
return myAllowExternalReferences;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #setAllowInlineMatchUrlReferences(boolean)
|
||||
*/
|
||||
public boolean isAllowInlineMatchUrlReferences() {
|
||||
return myAllowInlineMatchUrlReferences;
|
||||
}
|
||||
|
||||
public boolean isAllowMultipleDelete() {
|
||||
return myAllowMultipleDelete;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true} the default search params (i.e. the search parameters that are
|
||||
* defined by the FHIR specification itself) may be overridden by uploading search
|
||||
* parameters to the server with the same code as the built-in search parameter.
|
||||
* <p>
|
||||
* This can be useful if you want to be able to disable or alter
|
||||
* the behaviour of the default search parameters.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default value for this setting is {@code false}
|
||||
* </p>
|
||||
*/
|
||||
public boolean isDefaultSearchParamsCanBeOverridden() {
|
||||
return myDefaultSearchParamsCanBeOverridden;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this is set to <code>false</code> (default is <code>true</code>) the stale search deletion
|
||||
* task will be disabled (meaning that search results will be retained in the database indefinitely). USE WITH CAUTION.
|
||||
|
@ -271,6 +298,7 @@ public class DaoConfig {
|
|||
* <p>
|
||||
* Default is false for now, as this is an experimental feature.
|
||||
* </p>
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setAllowInlineMatchUrlReferences(boolean theAllowInlineMatchUrlReferences) {
|
||||
|
@ -281,6 +309,22 @@ public class DaoConfig {
|
|||
myAllowMultipleDelete = theAllowMultipleDelete;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@code true} the default search params (i.e. the search parameters that are
|
||||
* defined by the FHIR specification itself) may be overridden by uploading search
|
||||
* parameters to the server with the same code as the built-in search parameter.
|
||||
* <p>
|
||||
* This can be useful if you want to be able to disable or alter
|
||||
* the behaviour of the default search parameters.
|
||||
* </p>
|
||||
* <p>
|
||||
* The default value for this setting is {@code false}
|
||||
* </p>
|
||||
*/
|
||||
public void setDefaultSearchParamsCanBeOverridden(boolean theDefaultSearchParamsCanBeOverridden) {
|
||||
myDefaultSearchParamsCanBeOverridden = theDefaultSearchParamsCanBeOverridden;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a code system is added that contains more than this number of codes,
|
||||
* the code system will be indexed later in an incremental process in order to
|
||||
|
@ -315,8 +359,9 @@ public class DaoConfig {
|
|||
* (next/prev links in search response bundles) will become invalid. Defaults to 1 hour.
|
||||
* </p>
|
||||
* <p>
|
||||
*
|
||||
* @see To disable this feature entirely, see {@link #setExpireSearchResults(boolean)}
|
||||
* </p>
|
||||
* </p>
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setExpireSearchResultsAfterMillis(long theExpireSearchResultsAfterMillis) {
|
||||
|
@ -329,7 +374,7 @@ public class DaoConfig {
|
|||
* paging provider instead.
|
||||
*
|
||||
* @deprecated This method does not do anything. Configure the page size on your
|
||||
* paging provider instead. Deprecated in HAPI FHIR 2.3 (Jan 2017)
|
||||
* paging provider instead. Deprecated in HAPI FHIR 2.3 (Jan 2017)
|
||||
*/
|
||||
@Deprecated
|
||||
public void setHardSearchLimit(@SuppressWarnings("unused") int theHardSearchLimit) {
|
||||
|
@ -362,8 +407,9 @@ public class DaoConfig {
|
|||
|
||||
/**
|
||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||
*
|
||||
* @deprecated As of 2.2 this method is deprecated. There is no good reason to register an interceptor
|
||||
* with the DaoConfig and not with the server via {@link RestfulServer#registerInterceptor(IServerInterceptor)}
|
||||
* with the DaoConfig and not with the server via {@link RestfulServer#registerInterceptor(IServerInterceptor)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
||||
|
@ -375,8 +421,9 @@ public class DaoConfig {
|
|||
|
||||
/**
|
||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||
*
|
||||
* @deprecated As of 2.2 this method is deprecated. There is no good reason to register an interceptor
|
||||
* with the DaoConfig and not with the server via {@link RestfulServer#registerInterceptor(IServerInterceptor)}
|
||||
* with the DaoConfig and not with the server via {@link RestfulServer#registerInterceptor(IServerInterceptor)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
|
||||
|
@ -435,8 +482,9 @@ public class DaoConfig {
|
|||
* convert this reference to <code>Patient/1</code>
|
||||
* </p>
|
||||
*
|
||||
* @param theTreatBaseUrlsAsLocal The set of base URLs. May be <code>null</code>, which
|
||||
* means no references will be treated as external
|
||||
* @param theTreatBaseUrlsAsLocal
|
||||
* The set of base URLs. May be <code>null</code>, which
|
||||
* means no references will be treated as external
|
||||
*/
|
||||
public void setTreatBaseUrlsAsLocal(Set<String> theTreatBaseUrlsAsLocal) {
|
||||
HashSet<String> treatBaseUrlsAsLocal = new HashSet<String>();
|
||||
|
|
|
@ -79,7 +79,8 @@ public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResou
|
|||
values.addAll(theTerser.getAllPopulatedChildElementsOfType(theResource, BaseResourceReferenceDt.class));
|
||||
} else if (theInclude.getValue().startsWith(theResourceDef.getName() + ":")) {
|
||||
values = new ArrayList<Object>();
|
||||
RuntimeSearchParam sp = theResourceDef.getSearchParam(theInclude.getValue().substring(theInclude.getValue().indexOf(':') + 1));
|
||||
String paramName = theInclude.getValue().substring(theInclude.getValue().indexOf(':') + 1);
|
||||
RuntimeSearchParam sp = getSearchParamByName(theResourceDef, paramName);
|
||||
for (String nextPath : sp.getPathsSplit()) {
|
||||
values.addAll(theTerser.getValues(theResource, nextPath));
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
|
@ -46,6 +47,9 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
|
|||
super();
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySerarchParamRegistry;
|
||||
|
||||
private IBundleProvider doEverythingOperation(IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
if (theCount != null) {
|
||||
|
@ -65,7 +69,7 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
|
|||
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
||||
}
|
||||
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao, myTerminologySvc);
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao, myTerminologySvc, mySerarchParamRegistry);
|
||||
builder.setType(getResourceType(), getResourceName());
|
||||
return builder.search(paramMap);
|
||||
}
|
||||
|
|
|
@ -152,7 +152,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
|||
private int pollForNewUndeliveredResources(SubscriptionTable theSubscriptionTable) {
|
||||
Subscription subscription = toResource(Subscription.class, theSubscriptionTable.getSubscriptionResource(), false);
|
||||
RuntimeResourceDefinition resourceDef = validateCriteriaAndReturnResourceDefinition(subscription);
|
||||
SearchParameterMap criteriaUrl = translateMatchUrl(getContext(), subscription.getCriteria(), resourceDef);
|
||||
SearchParameterMap criteriaUrl = translateMatchUrl(this, getContext(), subscription.getCriteria(), resourceDef);
|
||||
|
||||
criteriaUrl = new SearchParameterMap();
|
||||
long start = theSubscriptionTable.getMostRecentMatch().getTime();
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.BaseHasResource;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||
|
@ -73,4 +76,9 @@ public interface IDao {
|
|||
<R extends IBaseResource> R toResource(Class<R> theResourceType, BaseHasResource theEntity, boolean theForHistoryOperation);
|
||||
|
||||
void populateFullTextFields(IBaseResource theResource, ResourceTable theEntity);
|
||||
|
||||
RuntimeSearchParam getSearchParamByName(RuntimeResourceDefinition theResourceDef, String theParamName);
|
||||
|
||||
Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef);
|
||||
|
||||
}
|
||||
|
|
|
@ -39,8 +39,10 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
|
|||
import ca.uhn.fhir.rest.api.PatchTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
||||
|
@ -134,6 +136,8 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
*/
|
||||
<MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, RequestDetails theRequestDetails);
|
||||
|
||||
DaoMethodOutcome patch(IIdType theId, PatchTypeEnum thePatchType, String thePatchBody, RequestDetails theRequestDetails);
|
||||
|
||||
Set<Long> processMatchUrl(String theMatchUrl);
|
||||
|
||||
/**
|
||||
|
@ -181,6 +185,15 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
|
||||
Set<Long> searchForIdsWithAndOr(SearchParameterMap theParams);
|
||||
|
||||
/**
|
||||
* Takes a map of incoming raw search parameters and translates/parses them into
|
||||
* appropriate {@link IQueryParameterType} instances of the appropriate type
|
||||
* for the given param
|
||||
*
|
||||
* @throws InvalidRequestException If any of the parameters are not known
|
||||
*/
|
||||
void translateRawParameters(Map<String, List<String>> theSource, SearchParameterMap theTarget);
|
||||
|
||||
/**
|
||||
* Update a resource - Note that this variant of the method does not take in a {@link RequestDetails} and
|
||||
* therefore can not fire any interceptors. Use only for internal system calls
|
||||
|
@ -211,8 +224,6 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
|
|||
*/
|
||||
MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequestDetails);
|
||||
|
||||
DaoMethodOutcome patch(IIdType theId, PatchTypeEnum thePatchType, String thePatchBody, RequestDetails theRequestDetails);
|
||||
|
||||
// /**
|
||||
// * Invoke the everything operation
|
||||
// */
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
|
||||
public interface ISearchParamRegistry {
|
||||
|
||||
Map<String,RuntimeSearchParam> getActiveSearchParams(String theResourceName);
|
||||
|
||||
Collection<RuntimeSearchParam> getAllSearchParams(String theResourceName);
|
||||
|
||||
void forceRefresh();
|
||||
|
||||
}
|
|
@ -41,6 +41,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||
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.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
|
@ -95,10 +96,12 @@ public class SearchBuilder {
|
|||
private IFulltextSearchSvc mySearchDao;
|
||||
private Search mySearchEntity;
|
||||
private ISearchResultDao mySearchResultDao;
|
||||
private ISearchParamRegistry mySerarchParamRegistry;
|
||||
|
||||
private IHapiTerminologySvc myTerminologySvc;
|
||||
|
||||
public SearchBuilder(FhirContext theFhirContext, EntityManager theEntityManager, PlatformTransactionManager thePlatformTransactionManager, IFulltextSearchSvc theSearchDao, ISearchResultDao theSearchResultDao, BaseHapiFhirDao<?> theDao,
|
||||
IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao, IForcedIdDao theForcedIdDao, IHapiTerminologySvc theTerminologySvc) {
|
||||
IResourceIndexedSearchParamUriDao theResourceIndexedSearchParamUriDao, IForcedIdDao theForcedIdDao, IHapiTerminologySvc theTerminologySvc, ISearchParamRegistry theSearchParamRegistry) {
|
||||
myContext = theFhirContext;
|
||||
myEntityManager = theEntityManager;
|
||||
myPlatformTransactionManager = thePlatformTransactionManager;
|
||||
|
@ -108,6 +111,7 @@ public class SearchBuilder {
|
|||
myResourceIndexedSearchParamUriDao = theResourceIndexedSearchParamUriDao;
|
||||
myForcedIdDao = theForcedIdDao;
|
||||
myTerminologySvc = theTerminologySvc;
|
||||
mySerarchParamRegistry = theSearchParamRegistry;
|
||||
}
|
||||
|
||||
private void addPredicateComposite(RuntimeSearchParam theParamDef, List<? extends IQueryParameterType> theNextAnd) {
|
||||
|
@ -212,12 +216,13 @@ public class SearchBuilder {
|
|||
throw new InvalidRequestException("Invalid resource type: " + targetResourceType);
|
||||
}
|
||||
|
||||
RuntimeSearchParam owningParameterDef = targetResourceDefinition.getSearchParam(parameterName.replaceAll("\\..*", ""));
|
||||
String paramName = parameterName.replaceAll("\\..*", "");
|
||||
RuntimeSearchParam owningParameterDef = myCallingDao.getSearchParamByName(targetResourceDefinition, paramName);
|
||||
if (owningParameterDef == null) {
|
||||
throw new InvalidRequestException("Unknown parameter name: " + targetResourceType + ':' + parameterName);
|
||||
}
|
||||
|
||||
owningParameterDef = targetResourceDefinition.getSearchParam(owningParameter);
|
||||
owningParameterDef = myCallingDao.getSearchParamByName(targetResourceDefinition, owningParameter);
|
||||
if (owningParameterDef == null) {
|
||||
throw new InvalidRequestException("Unknown parameter name: " + targetResourceType + ':' + owningParameter);
|
||||
}
|
||||
|
@ -237,7 +242,7 @@ public class SearchBuilder {
|
|||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
predicates.add(builder.equal(from.get("mySourceResourceType"), targetResourceType));
|
||||
predicates.add(from.get("mySourceResourcePid").in(match));
|
||||
predicates.add(createResourceLinkPathPredicate(myContext, owningParameter, from, resourceType));
|
||||
predicates.add(createResourceLinkPathPredicate(myCallingDao, myContext, owningParameter, from, resourceType));
|
||||
predicates.add(builder.equal(from.get("myTargetResourceType"), myResourceName));
|
||||
createPredicateResourceId(builder, cq, predicates, from.get("myId").as(Long.class));
|
||||
createPredicateLastUpdatedForResourceLink(builder, from, predicates);
|
||||
|
@ -548,7 +553,8 @@ public class SearchBuilder {
|
|||
String resourceId;
|
||||
if (!ref.getValue().matches("[a-zA-Z]+\\/.*")) {
|
||||
|
||||
String paramPath = myContext.getResourceDefinition(myResourceType).getSearchParam(theParamName).getPath();
|
||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
||||
String paramPath = myCallingDao.getSearchParamByName(resourceDef, theParamName).getPath();
|
||||
if (paramPath.endsWith(".as(Reference)")) {
|
||||
paramPath = paramPath.substring(0, paramPath.length() - ".as(Reference)".length()) + "Reference";
|
||||
}
|
||||
|
@ -602,7 +608,7 @@ public class SearchBuilder {
|
|||
boolean isMeta = BaseHapiFhirDao.RESOURCE_META_PARAMS.containsKey(chain);
|
||||
RuntimeSearchParam param = null;
|
||||
if (!isMeta) {
|
||||
param = typeDef.getSearchParam(chain);
|
||||
param = myCallingDao.getSearchParamByName(typeDef, chain);
|
||||
if (param == null) {
|
||||
ourLog.debug("Type {} doesn't have search param {}", nextType.getSimpleName(), param);
|
||||
continue;
|
||||
|
@ -1380,43 +1386,8 @@ public class SearchBuilder {
|
|||
return singleCode;
|
||||
}
|
||||
|
||||
private String determineSystemIfMissing(String theParamName, String code, String system) {
|
||||
if (system == null) {
|
||||
RuntimeSearchParam param = getSearchParam(theParamName);
|
||||
if (param != null) {
|
||||
Set<String> valueSetUris = Sets.newHashSet();
|
||||
for (String nextPath : param.getPathsSplit()) {
|
||||
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, nextPath);
|
||||
if (def instanceof BaseRuntimeDeclaredChildDefinition) {
|
||||
String valueSet = ((BaseRuntimeDeclaredChildDefinition) def).getBindingValueSet();
|
||||
if (isNotBlank(valueSet)) {
|
||||
valueSetUris.add(valueSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valueSetUris.size() == 1) {
|
||||
List<VersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(valueSetUris.iterator().next());
|
||||
for (VersionIndependentConcept nextCandidate : candidateCodes) {
|
||||
if (nextCandidate.getCode().equals(code)) {
|
||||
system = nextCandidate.getSystem();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return system;
|
||||
}
|
||||
|
||||
private Predicate createResourceLinkPathPredicate(String theParamName, Root<? extends ResourceLink> from) {
|
||||
return createResourceLinkPathPredicate(myContext, theParamName, from, myResourceType);
|
||||
}
|
||||
|
||||
private static Predicate createResourceLinkPathPredicate(FhirContext theContext, String theParamName, Root<? extends ResourceLink> from, Class<? extends IBaseResource> resourceType) {
|
||||
RuntimeSearchParam param = theContext.getResourceDefinition(resourceType).getSearchParam(theParamName);
|
||||
List<String> path = param.getPathsSplit();
|
||||
Predicate type = from.get("mySourcePath").in(path);
|
||||
return type;
|
||||
return createResourceLinkPathPredicate(myCallingDao, myContext, theParamName, from, myResourceType);
|
||||
}
|
||||
|
||||
private TypedQuery<Long> createSearchAllByTypeQuery(DateRangeParam theLastUpdated) {
|
||||
|
@ -1468,7 +1439,8 @@ public class SearchBuilder {
|
|||
return;
|
||||
}
|
||||
|
||||
RuntimeSearchParam param = getSearchParam(theSort.getParamName());
|
||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceName);
|
||||
RuntimeSearchParam param = myCallingDao.getSearchParamByName(resourceDef, theSort.getParamName());
|
||||
if (param == null) {
|
||||
throw new InvalidRequestException("Unknown sort parameter '" + theSort.getParamName() + "'");
|
||||
}
|
||||
|
@ -1532,10 +1504,33 @@ public class SearchBuilder {
|
|||
createSort(theBuilder, theFrom, theSort.getChain(), theOrders, thePredicates);
|
||||
}
|
||||
|
||||
private RuntimeSearchParam getSearchParam(String theParamName) {
|
||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
||||
RuntimeSearchParam param = resourceDef.getSearchParam(theParamName);
|
||||
return param;
|
||||
private String determineSystemIfMissing(String theParamName, String code, String system) {
|
||||
if (system == null) {
|
||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceName);
|
||||
RuntimeSearchParam param = myCallingDao.getSearchParamByName(resourceDef, theParamName);
|
||||
if (param != null) {
|
||||
Set<String> valueSetUris = Sets.newHashSet();
|
||||
for (String nextPath : param.getPathsSplit()) {
|
||||
BaseRuntimeChildDefinition def = myContext.newTerser().getDefinition(myResourceType, nextPath);
|
||||
if (def instanceof BaseRuntimeDeclaredChildDefinition) {
|
||||
String valueSet = ((BaseRuntimeDeclaredChildDefinition) def).getBindingValueSet();
|
||||
if (isNotBlank(valueSet)) {
|
||||
valueSetUris.add(valueSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (valueSetUris.size() == 1) {
|
||||
List<VersionIndependentConcept> candidateCodes = myTerminologySvc.expandValueSet(valueSetUris.iterator().next());
|
||||
for (VersionIndependentConcept nextCandidate : candidateCodes) {
|
||||
if (nextCandidate.getCode().equals(code)) {
|
||||
system = nextCandidate.getSystem();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return system;
|
||||
}
|
||||
|
||||
public Set<Long> doGetPids() {
|
||||
|
@ -1820,7 +1815,8 @@ public class SearchBuilder {
|
|||
|
||||
doInitializeSearch();
|
||||
|
||||
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
||||
// RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(myResourceType);
|
||||
Map<String, RuntimeSearchParam> searchParams = mySerarchParamRegistry.getActiveSearchParams(myResourceName);
|
||||
|
||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamEntry : params.entrySet()) {
|
||||
String nextParamName = nextParamEntry.getKey();
|
||||
|
@ -1875,7 +1871,7 @@ public class SearchBuilder {
|
|||
|
||||
} else {
|
||||
|
||||
RuntimeSearchParam nextParamDef = resourceDef.getSearchParam(nextParamName);
|
||||
RuntimeSearchParam nextParamDef = searchParams.get(nextParamName);
|
||||
if (nextParamDef != null) {
|
||||
switch (nextParamDef.getParamType()) {
|
||||
case DATE:
|
||||
|
@ -2044,6 +2040,14 @@ public class SearchBuilder {
|
|||
return likeExpression.replace("%", "[%]") + "%";
|
||||
}
|
||||
|
||||
private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, Root<? extends ResourceLink> from, Class<? extends IBaseResource> resourceType) {
|
||||
RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(resourceType);
|
||||
RuntimeSearchParam param = theCallingDao.getSearchParamByName(resourceDef, theParamName);
|
||||
List<String> path = param.getPathsSplit();
|
||||
Predicate type = from.get("mySourcePath").in(path);
|
||||
return type;
|
||||
}
|
||||
|
||||
private static List<Long> filterResourceIdsByLastUpdated(EntityManager theEntityManager, final DateRangeParam theLastUpdated, Collection<Long> thePids) {
|
||||
CriteriaBuilder builder = theEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> cq = builder.createQuery(Long.class);
|
||||
|
@ -2109,7 +2113,7 @@ public class SearchBuilder {
|
|||
*
|
||||
* @param theLastUpdated
|
||||
*/
|
||||
public static HashSet<Long> loadReverseIncludes(FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode, DateRangeParam theLastUpdated) {
|
||||
public static HashSet<Long> loadReverseIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode, DateRangeParam theLastUpdated) {
|
||||
if (theMatches.size() == 0) {
|
||||
return new HashSet<Long>();
|
||||
}
|
||||
|
@ -2177,7 +2181,11 @@ public class SearchBuilder {
|
|||
}
|
||||
|
||||
String paramName = nextInclude.getParamName();
|
||||
param = isNotBlank(paramName) ? def.getSearchParam(paramName) : null;
|
||||
if (isNotBlank(paramName)) {
|
||||
param = theCallingDao.getSearchParamByName(def, paramName);
|
||||
} else {
|
||||
param = null;
|
||||
}
|
||||
if (param == null) {
|
||||
ourLog.warn("Unknown param name in include/revinclude=" + nextInclude.getValue());
|
||||
continue;
|
||||
|
@ -2278,9 +2286,9 @@ public class SearchBuilder {
|
|||
|
||||
Set<Long> revIncludedPids = new HashSet<Long>();
|
||||
if (myParams.getEverythingMode() == null) {
|
||||
revIncludedPids.addAll(loadReverseIncludes(myContext, myEntityManager, pidsSubList, myParams.getRevIncludes(), true, myParams.getLastUpdated()));
|
||||
revIncludedPids.addAll(loadReverseIncludes(myCallingDao, myContext, myEntityManager, pidsSubList, myParams.getRevIncludes(), true, myParams.getLastUpdated()));
|
||||
}
|
||||
revIncludedPids.addAll(loadReverseIncludes(myContext, myEntityManager, pidsSubList, myParams.getIncludes(), false, myParams.getLastUpdated()));
|
||||
revIncludedPids.addAll(loadReverseIncludes(myCallingDao, myContext, myEntityManager, pidsSubList, myParams.getIncludes(), false, myParams.getLastUpdated()));
|
||||
|
||||
// Execute the query and make sure we return distinct results
|
||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -38,8 +39,6 @@ import org.apache.commons.lang3.tuple.Pair;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
|
||||
|
@ -79,8 +78,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.DATE) {
|
||||
continue;
|
||||
}
|
||||
|
@ -130,12 +129,13 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.NUMBER) {
|
||||
continue;
|
||||
}
|
||||
|
@ -229,8 +229,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.QUANTITY) {
|
||||
continue;
|
||||
}
|
||||
|
@ -277,8 +277,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
|
||||
continue;
|
||||
}
|
||||
|
@ -363,8 +363,8 @@ public class SearchParamExtractorDstu1 extends BaseSearchParamExtractor implemen
|
|||
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<BaseResourceIndexedSearchParam> retVal = new HashSet<BaseResourceIndexedSearchParam>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -120,8 +121,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.DATE) {
|
||||
continue;
|
||||
}
|
||||
|
@ -181,8 +182,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.NUMBER) {
|
||||
continue;
|
||||
}
|
||||
|
@ -281,8 +282,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.QUANTITY) {
|
||||
continue;
|
||||
}
|
||||
|
@ -335,23 +336,25 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
String resourceName = getContext().getResourceDefinition(theResource).getName();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
String resourceName = nextSpDef.getName();
|
||||
String nextSpName = nextSpDef.getName();
|
||||
|
||||
if (isBlank(nextPath)) {
|
||||
|
||||
// TODO: implement phonetic, and any others that have no path
|
||||
|
||||
if ("Questionnaire".equals(def.getName()) && nextSpDef.getName().equals("title")) {
|
||||
if ("Questionnaire".equals(resourceName) && nextSpDef.getName().equals("title")) {
|
||||
Questionnaire q = (Questionnaire) theResource;
|
||||
String title = q.getGroup().getTitle();
|
||||
addSearchTerm(theEntity, retVal, resourceName, title);
|
||||
addSearchTerm(theEntity, retVal, nextSpName, title);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -369,7 +372,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
if (nextObject instanceof IPrimitiveDatatype<?>) {
|
||||
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
|
||||
String searchTerm = nextValue.getValueAsString();
|
||||
addSearchTerm(theEntity, retVal, resourceName, searchTerm);
|
||||
addSearchTerm(theEntity, retVal, nextSpName, searchTerm);
|
||||
} else {
|
||||
if (nextObject instanceof BaseHumanNameDt) {
|
||||
ArrayList<StringDt> allNames = new ArrayList<StringDt>();
|
||||
|
@ -377,7 +380,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
allNames.addAll(nextHumanName.getFamily());
|
||||
allNames.addAll(nextHumanName.getGiven());
|
||||
for (StringDt nextName : allNames) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, nextName.getValue());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof AddressDt) {
|
||||
ArrayList<StringDt> allNames = new ArrayList<StringDt>();
|
||||
|
@ -388,16 +391,16 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
allNames.add(nextAddress.getCountryElement());
|
||||
allNames.add(nextAddress.getPostalCodeElement());
|
||||
for (StringDt nextName : allNames) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, nextName.getValue());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof ContactPointDt) {
|
||||
ContactPointDt nextContact = (ContactPointDt) nextObject;
|
||||
if (nextContact.getValueElement().isEmpty() == false) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, nextContact.getValue());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextContact.getValue());
|
||||
}
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
throw new ConfigurationException("Search param " + nextSpName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -423,8 +426,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
useSystem = vs.getCodeSystem().getSystem();
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
|
||||
continue;
|
||||
}
|
||||
|
@ -575,8 +578,8 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamUri> retVal = new HashSet<ResourceIndexedSearchParamUri>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.URI) {
|
||||
continue;
|
||||
}
|
||||
|
@ -622,6 +625,7 @@ public class SearchParamExtractorDstu2 extends BaseSearchParamExtractor implemen
|
|||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
|
||||
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
|
||||
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public class SearchParamRegistryDstu1 extends BaseSearchParamRegistry {
|
||||
// nothing yet
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
public class SearchParamRegistryDstu2 extends BaseSearchParamRegistry {
|
||||
// nothing yet
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -21,9 +21,16 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
|
||||
public interface IResourceTableDao extends JpaRepository<ResourceTable, Long> {
|
||||
// nothing yet
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE ResourceTable r SET r.myIndexStatus = null WHERE r.myResourceType = :restype")
|
||||
int markResourcesOfTypeAsRequiringReindexing(@Param("restype") String theResourceType);
|
||||
|
||||
}
|
||||
|
|
|
@ -92,7 +92,8 @@ public class FhirResourceDaoDstu3<T extends IAnyResource> extends BaseHapiFhirRe
|
|||
values.addAll(theTerser.getAllPopulatedChildElementsOfType(theResource, BaseResourceReferenceDt.class));
|
||||
} else if (theInclude.getValue().startsWith(theResourceDef.getName() + ":")) {
|
||||
values = new ArrayList<Object>();
|
||||
RuntimeSearchParam sp = theResourceDef.getSearchParam(theInclude.getValue().substring(theInclude.getValue().indexOf(':') + 1));
|
||||
String paramName = theInclude.getValue().substring(theInclude.getValue().indexOf(':') + 1);
|
||||
RuntimeSearchParam sp = getSearchParamByName(theResourceDef, paramName);
|
||||
for (String nextPath : sp.getPathsSplit()) {
|
||||
values.addAll(theTerser.getValues(theResource, nextPath));
|
||||
}
|
||||
|
|
|
@ -27,8 +27,10 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
|
||||
|
@ -45,6 +47,9 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetai
|
|||
|
||||
public class FhirResourceDaoPatientDstu3 extends FhirResourceDaoDstu3<Patient>implements IFhirResourceDaoPatient<Patient> {
|
||||
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySerarchParamRegistry;
|
||||
|
||||
private IBundleProvider doEverythingOperation(IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
if (theCount != null) {
|
||||
|
@ -64,7 +69,7 @@ public class FhirResourceDaoPatientDstu3 extends FhirResourceDaoDstu3<Patient>im
|
|||
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
||||
}
|
||||
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao, myTerminologySvc);
|
||||
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this, myResourceIndexedSearchParamUriDao, myForcedIdDao, myTerminologySvc, mySerarchParamRegistry);
|
||||
builder.setType(getResourceType(), getResourceName());
|
||||
return builder.search(paramMap);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -10,7 +12,7 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
|||
* 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
|
||||
* 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,
|
||||
|
@ -27,22 +29,37 @@ import org.hl7.fhir.dstu3.model.SearchParameter;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseSearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<SearchParameter>implements IFhirResourceDaoSearchParameter<SearchParameter> {
|
||||
public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<SearchParameter> implements IFhirResourceDaoSearchParameter<SearchParameter> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSearchParameterDstu3.class);
|
||||
|
||||
@Autowired
|
||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
|
||||
private void markAffectedResources(SearchParameter theResource) {
|
||||
String xpath = theResource.getXpath();
|
||||
String resourceType = xpath.substring(0, xpath.indexOf('.'));
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", xpath);
|
||||
int updatedCount = myResourceTableDao.markResourcesOfTypeAsRequiringReindexing(resourceType);
|
||||
ourLog.info("Marked {} resources for reindexing", updatedCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called once per minute to perform any required re-indexing. During most passes this will
|
||||
* just check and find that there are no resources requiring re-indexing. In that case the method just returns
|
||||
* immediately. If the search finds that some resources require reindexing, the system will do a bunch of
|
||||
* reindexing and then return.
|
||||
* immediately. If the search finds that some resources require reindexing, the system will do multiple
|
||||
* reindexing passes and then return.
|
||||
*/
|
||||
@Override
|
||||
@Scheduled(fixedDelay=DateUtils.MILLIS_PER_MINUTE)
|
||||
@Scheduled(fixedDelay = DateUtils.MILLIS_PER_MINUTE)
|
||||
public void performReindexingPass() {
|
||||
if (getConfig().isSchedulingDisabled()) {
|
||||
return;
|
||||
|
@ -60,4 +77,54 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postPersist(ResourceTable theEntity, SearchParameter theResource) {
|
||||
markAffectedResources(theResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postUpdate(ResourceTable theEntity, SearchParameter theResource) {
|
||||
markAffectedResources(theResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateResourceForStorage(SearchParameter theResource, ResourceTable theEntityToSave) {
|
||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||
|
||||
if (theResource.getStatus() == null) {
|
||||
throw new UnprocessableEntityException("Resource.status is missing or invalid: " + theResource.getStatusElement().getValueAsString());
|
||||
}
|
||||
|
||||
String xpath = theResource.getXpath();
|
||||
if (isBlank(xpath)) {
|
||||
throw new UnprocessableEntityException("Resource.xpath is missing");
|
||||
}
|
||||
|
||||
String[] xpathSplit = BaseSearchParamExtractor.SPLIT.split(xpath);
|
||||
String allResourceName = null;
|
||||
for (String nextPath : xpathSplit) {
|
||||
int dotIdx = nextPath.indexOf('.');
|
||||
if (dotIdx == -1) {
|
||||
throw new UnprocessableEntityException("Invalid path value \"" + nextPath + "\". Must start with a resource name");
|
||||
}
|
||||
|
||||
String resourceName = nextPath.substring(0, dotIdx);
|
||||
try {
|
||||
getContext().getResourceDefinition(resourceName);
|
||||
} catch (DataFormatException e) {
|
||||
throw new UnprocessableEntityException("Invalid path value \"" + nextPath + "\": " + e.getMessage());
|
||||
}
|
||||
|
||||
if (allResourceName == null) {
|
||||
allResourceName = resourceName;
|
||||
} else {
|
||||
if (!allResourceName.equals(resourceName)) {
|
||||
throw new UnprocessableEntityException("Invalid path value \"" + nextPath + "\". All paths in a single SearchParameter must match the same resource type");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
|||
private int pollForNewUndeliveredResources(SubscriptionTable theSubscriptionTable) {
|
||||
Subscription subscription = toResource(Subscription.class, theSubscriptionTable.getSubscriptionResource(), false);
|
||||
RuntimeResourceDefinition resourceDef = validateCriteriaAndReturnResourceDefinition(subscription);
|
||||
SearchParameterMap criteriaUrl = translateMatchUrl(getContext(), subscription.getCriteria(), resourceDef);
|
||||
SearchParameterMap criteriaUrl = translateMatchUrl(this, getContext(), subscription.getCriteria(), resourceDef);
|
||||
|
||||
criteriaUrl = new SearchParameterMap();
|
||||
long start = theSubscriptionTable.getMostRecentMatch().getTime();
|
||||
|
|
|
@ -60,7 +60,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
|||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, CodeableConcept, Coding> myCodeSystemDao;
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
||||
|
||||
@Override
|
||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
|
@ -56,7 +57,6 @@ import org.hl7.fhir.dstu3.model.Location.LocationPositionComponent;
|
|||
import org.hl7.fhir.dstu3.model.Patient.PatientCommunicationComponent;
|
||||
import org.hl7.fhir.dstu3.model.Period;
|
||||
import org.hl7.fhir.dstu3.model.Quantity;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire;
|
||||
import org.hl7.fhir.dstu3.model.Range;
|
||||
import org.hl7.fhir.dstu3.model.SimpleQuantity;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
|
@ -73,11 +73,11 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.BaseSearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.PathAndRef;
|
||||
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
|
||||
|
@ -105,8 +105,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
super();
|
||||
}
|
||||
|
||||
public SearchParamExtractorDstu3(FhirContext theCtx, IValidationSupport theValidationSupport) {
|
||||
super(theCtx);
|
||||
public SearchParamExtractorDstu3(FhirContext theCtx, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
|
||||
super(theCtx, theSearchParamRegistry);
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
|
@ -147,8 +147,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.DATE) {
|
||||
continue;
|
||||
}
|
||||
|
@ -226,8 +226,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.NUMBER) {
|
||||
continue;
|
||||
}
|
||||
|
@ -320,8 +320,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.QUANTITY) {
|
||||
continue;
|
||||
}
|
||||
|
@ -384,24 +384,28 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
String resourceName = getContext().getResourceDefinition(theResource).getName();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
String resourceName = nextSpDef.getName();
|
||||
String nextSpName = nextSpDef.getName();
|
||||
|
||||
if (isBlank(nextPath)) {
|
||||
|
||||
// TODO: implement phonetic, and any others that have no path
|
||||
// // TODO: implement phonetic, and any others that have no path
|
||||
//
|
||||
// // TODO: do we still need this check?
|
||||
// if ("Questionnaire".equals(nextSpName) && nextSpDef.getName().equals("title")) {
|
||||
// Questionnaire q = (Questionnaire) theResource;
|
||||
// String title = "";// q.getGroup().getTitle();
|
||||
// addSearchTerm(theEntity, retVal, nextSpName, title);
|
||||
// }
|
||||
|
||||
if ("Questionnaire".equals(def.getName()) && nextSpDef.getName().equals("title")) {
|
||||
Questionnaire q = (Questionnaire) theResource;
|
||||
String title = "";// q.getGroup().getTitle();
|
||||
addSearchTerm(theEntity, retVal, resourceName, title);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -418,7 +422,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
if (nextObject instanceof IPrimitiveType<?>) {
|
||||
IPrimitiveType<?> nextValue = (IPrimitiveType<?>) nextObject;
|
||||
String searchTerm = nextValue.getValueAsString();
|
||||
addSearchTerm(theEntity, retVal, resourceName, searchTerm);
|
||||
addSearchTerm(theEntity, retVal, nextSpName, searchTerm);
|
||||
} else {
|
||||
if (nextObject instanceof HumanName) {
|
||||
ArrayList<StringType> allNames = new ArrayList<StringType>();
|
||||
|
@ -428,7 +432,7 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
}
|
||||
allNames.addAll(nextHumanName.getGiven());
|
||||
for (StringType nextName : allNames) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, nextName.getValue());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof Address) {
|
||||
ArrayList<StringType> allNames = new ArrayList<StringType>();
|
||||
|
@ -439,29 +443,29 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
allNames.add(nextAddress.getCountryElement());
|
||||
allNames.add(nextAddress.getPostalCodeElement());
|
||||
for (StringType nextName : allNames) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, nextName.getValue());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof ContactPoint) {
|
||||
ContactPoint nextContact = (ContactPoint) nextObject;
|
||||
if (nextContact.getValueElement().isEmpty() == false) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, nextContact.getValue());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextContact.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof Quantity) {
|
||||
BigDecimal value = ((Quantity) nextObject).getValue();
|
||||
if (value != null) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, value.toPlainString());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
||||
}
|
||||
} else if (nextObject instanceof Range) {
|
||||
SimpleQuantity low = ((Range) nextObject).getLow();
|
||||
if (low != null) {
|
||||
BigDecimal value = low.getValue();
|
||||
if (value != null) {
|
||||
addSearchTerm(theEntity, retVal, resourceName, value.toPlainString());
|
||||
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
throw new ConfigurationException("Search param " + nextSpName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -486,8 +490,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
useSystem = cs.getUrl();
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
|
||||
continue;
|
||||
}
|
||||
|
@ -633,8 +637,8 @@ public class SearchParamExtractorDstu3 extends BaseSearchParamExtractor implemen
|
|||
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamUri> retVal = new HashSet<ResourceIndexedSearchParamUri>();
|
||||
|
||||
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.URI) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 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 static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.dstu3.model.CodeType;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||
import ca.uhn.fhir.jpa.dao.BaseSearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
|
||||
public class SearchParamRegistryDstu3 extends BaseSearchParamRegistry {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamRegistryDstu3.class);
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDao<SearchParameter> mySpDao;
|
||||
|
||||
private long myLastRefresh;
|
||||
|
||||
private volatile Map<String, Map<String, RuntimeSearchParam>> myActiveSearchParams;
|
||||
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
|
||||
@Override
|
||||
public Map<String, RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
||||
|
||||
long refreshInterval = 60 * DateUtils.MILLIS_PER_MINUTE;
|
||||
if (System.currentTimeMillis() - refreshInterval > myLastRefresh) {
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
Map<String, Map<String, RuntimeSearchParam>> searchParams = new HashMap<String, Map<String, RuntimeSearchParam>>();
|
||||
for (Entry<String, Map<String, RuntimeSearchParam>> nextBuiltInEntry : getBuiltInSearchParams().entrySet()) {
|
||||
for (RuntimeSearchParam nextParam : nextBuiltInEntry.getValue().values()) {
|
||||
String nextResourceName = nextBuiltInEntry.getKey();
|
||||
getSearchParamMap(searchParams, nextResourceName).put(nextParam.getName(), nextParam);
|
||||
}
|
||||
}
|
||||
|
||||
IBundleProvider allSearchParamsBp = mySpDao.search(new SearchParameterMap());
|
||||
int size = allSearchParamsBp.size();
|
||||
|
||||
// Just in case..
|
||||
if (size > 10000) {
|
||||
ourLog.warn("Unable to support >10000 search params!");
|
||||
size = 10000;
|
||||
}
|
||||
|
||||
List<IBaseResource> allSearchParams = allSearchParamsBp.getResources(0, size);
|
||||
for (IBaseResource nextResource : allSearchParams) {
|
||||
SearchParameter nextSp = (SearchParameter) nextResource;
|
||||
RuntimeSearchParam runtimeSp = toRuntimeSp(nextSp);
|
||||
if (runtimeSp == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int dotIdx = runtimeSp.getPath().indexOf('.');
|
||||
if (dotIdx == -1) {
|
||||
ourLog.warn("Can not determine resource type of {}", runtimeSp.getPath());
|
||||
continue;
|
||||
}
|
||||
String resourceType = runtimeSp.getPath().substring(0, dotIdx);
|
||||
|
||||
Map<String, RuntimeSearchParam> searchParamMap = getSearchParamMap(searchParams, resourceType);
|
||||
String name = runtimeSp.getName();
|
||||
if (myDaoConfig.isDefaultSearchParamsCanBeOverridden() || !searchParamMap.containsKey(name)) {
|
||||
searchParamMap.put(name, runtimeSp);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Map<String, RuntimeSearchParam>> activeSearchParams = new HashMap<String, Map<String, RuntimeSearchParam>>();
|
||||
for (Entry<String, Map<String, RuntimeSearchParam>> nextEntry : searchParams.entrySet()) {
|
||||
for (RuntimeSearchParam nextSp : nextEntry.getValue().values()) {
|
||||
String nextName = nextSp.getName();
|
||||
if (nextSp.getStatus() != RuntimeSearchParamStatusEnum.ACTIVE) {
|
||||
nextSp = null;
|
||||
}
|
||||
|
||||
if (!activeSearchParams.containsKey(nextEntry.getKey())) {
|
||||
activeSearchParams.put(nextEntry.getKey(), new HashMap<String, RuntimeSearchParam>());
|
||||
}
|
||||
if (activeSearchParams.containsKey(nextEntry.getKey())) {
|
||||
ourLog.info("Replacing existing/built in search param {}:{} with new one", nextEntry.getKey(), nextName);
|
||||
}
|
||||
|
||||
if (nextSp != null) {
|
||||
activeSearchParams.get(nextEntry.getKey()).put(nextName, nextSp);
|
||||
} else {
|
||||
activeSearchParams.get(nextEntry.getKey()).remove(nextName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
myActiveSearchParams = activeSearchParams;
|
||||
|
||||
myLastRefresh = System.currentTimeMillis();
|
||||
ourLog.info("Refreshed search parameter cache in {}ms", sw.getMillis());
|
||||
}
|
||||
|
||||
return myActiveSearchParams.get(theResourceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
myLastRefresh = 0;
|
||||
}
|
||||
|
||||
private Map<String, RuntimeSearchParam> getSearchParamMap(Map<String, Map<String, RuntimeSearchParam>> searchParams, String theResourceName) {
|
||||
Map<String, RuntimeSearchParam> retVal = searchParams.get(theResourceName);
|
||||
if (retVal == null) {
|
||||
retVal = new HashMap<String, RuntimeSearchParam>();
|
||||
searchParams.put(theResourceName, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private RuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getXpath();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = toStrings(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RuntimeSearchParam retVal = new RuntimeSearchParam(name, description, path, paramType, providesMembershipInCompartments, targets, status);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Set<String> toStrings(List<CodeType> theTarget) {
|
||||
HashSet<String> retVal = new HashSet<String>();
|
||||
for (CodeType next : theTarget) {
|
||||
if (isNotBlank(next.getValue())) {
|
||||
retVal.add(next.getValue());
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
|
@ -77,6 +77,7 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
|||
@Index(name = "IDX_RES_DATE", columnList="RES_UPDATED"),
|
||||
@Index(name = "IDX_RES_LANG", columnList="RES_TYPE,RES_LANGUAGE"),
|
||||
@Index(name = "IDX_RES_PROFILE", columnList="RES_PROFILE"),
|
||||
@Index(name = "IDX_RES_TYPE", columnList="RES_TYPE"),
|
||||
@Index(name = "IDX_INDEXSTATUS", columnList="SP_INDEX_STATUS")
|
||||
})
|
||||
@AnalyzerDefs({
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -27,10 +29,15 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.*;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.SearchParamType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
|
@ -89,17 +96,46 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
|
|||
nextResource.addExtension(new Extension(ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalType(count)));
|
||||
}
|
||||
|
||||
// Add chained params
|
||||
for (CapabilityStatementRestResourceSearchParamComponent nextParam : nextResource.getSearchParam()) {
|
||||
if (nextParam.getType() == SearchParamType.REFERENCE) {
|
||||
// List<CodeType> targets = nextParam.getTarget();
|
||||
// for (CodeType next : targets) {
|
||||
// RuntimeResourceDefinition def = ctx.getResourceDefinition(next.getValue());
|
||||
// for (RuntimeSearchParam nextChainedParam : def.getSearchParams()) {
|
||||
// nextParam.addChain(nextChainedParam.getName());
|
||||
// }
|
||||
// }
|
||||
nextResource.getSearchParam().clear();
|
||||
String resourceName = nextResource.getType();
|
||||
RuntimeResourceDefinition resourceDef = myRestfulServer.getFhirContext().getResourceDefinition(resourceName);
|
||||
Collection<RuntimeSearchParam> searchParams = mySystemDao.getSearchParamsByResourceType(resourceDef);
|
||||
for (RuntimeSearchParam runtimeSp : searchParams) {
|
||||
CapabilityStatementRestResourceSearchParamComponent confSp = nextResource.addSearchParam();
|
||||
|
||||
confSp.setName(runtimeSp.getName());
|
||||
confSp.setDocumentation(runtimeSp.getDescription());
|
||||
confSp.setDefinition(runtimeSp.getUri());
|
||||
switch (runtimeSp.getParamType()) {
|
||||
case COMPOSITE:
|
||||
confSp.setType(SearchParamType.COMPOSITE);
|
||||
break;
|
||||
case DATE:
|
||||
confSp.setType(SearchParamType.DATE);
|
||||
break;
|
||||
case NUMBER:
|
||||
confSp.setType(SearchParamType.NUMBER);
|
||||
break;
|
||||
case QUANTITY:
|
||||
confSp.setType(SearchParamType.QUANTITY);
|
||||
break;
|
||||
case REFERENCE:
|
||||
confSp.setType(SearchParamType.REFERENCE);
|
||||
break;
|
||||
case STRING:
|
||||
confSp.setType(SearchParamType.STRING);
|
||||
break;
|
||||
case TOKEN:
|
||||
confSp.setType(SearchParamType.TOKEN);
|
||||
break;
|
||||
case URI:
|
||||
confSp.setType(SearchParamType.URI);
|
||||
break;
|
||||
case HAS:
|
||||
// Shouldn't happen
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -141,9 +141,9 @@ public final class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
|
||||
Set<Long> revIncludedPids = new HashSet<Long>();
|
||||
if (mySearchEntity.getSearchType() == SearchTypeEnum.SEARCH) {
|
||||
revIncludedPids.addAll(SearchBuilder.loadReverseIncludes(myContext, myEntityManager, pidsSubList, mySearchEntity.toRevIncludesList(), true, mySearchEntity.getLastUpdated()));
|
||||
revIncludedPids.addAll(SearchBuilder.loadReverseIncludes(myDao, myContext, myEntityManager, pidsSubList, mySearchEntity.toRevIncludesList(), true, mySearchEntity.getLastUpdated()));
|
||||
}
|
||||
revIncludedPids.addAll(SearchBuilder.loadReverseIncludes(myContext, myEntityManager, pidsSubList, mySearchEntity.toIncludesList(), false, mySearchEntity.getLastUpdated()));
|
||||
revIncludedPids.addAll(SearchBuilder.loadReverseIncludes(myDao, myContext, myEntityManager, pidsSubList, mySearchEntity.toIncludesList(), false, mySearchEntity.getLastUpdated()));
|
||||
|
||||
// Execute the query and make sure we return distinct results
|
||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||
|
|
|
@ -58,6 +58,9 @@ public class TestDstu1Config extends BaseJavaConfigDstu1 {
|
|||
extraProperties.put("hibernate.format_sql", "false");
|
||||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
|
||||
return extraProperties;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Condition;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||
|
@ -25,7 +30,12 @@ public class BaseHapiFhirDaoTest extends BaseJpaTest {
|
|||
|
||||
@Test
|
||||
public void testTranslateMatchUrl() {
|
||||
SearchParameterMap match = BaseHapiFhirDao.translateMatchUrl(ourCtx, "Condition?patient=304&_lastUpdated=>2011-01-01T11:12:21.0000Z", ourCtx.getResourceDefinition(Condition.class));
|
||||
RuntimeResourceDefinition resourceDef = ourCtx.getResourceDefinition(Condition.class);
|
||||
|
||||
IDao dao = mock(IDao.class);
|
||||
when(dao.getSearchParamByName(any(RuntimeResourceDefinition.class), eq("patient"))).thenReturn(resourceDef.getSearchParam("patient"));
|
||||
|
||||
SearchParameterMap match = BaseHapiFhirDao.translateMatchUrl(dao, ourCtx, "Condition?patient=304&_lastUpdated=>2011-01-01T11:12:21.0000Z", resourceDef);
|
||||
assertEquals("2011-01-01T11:12:21.0000Z", match.getLastUpdated().getLowerBound().getValueAsString());
|
||||
assertEquals(ReferenceParam.class, match.get("patient").get(0).get(0).getClass());
|
||||
assertEquals("304", ((ReferenceParam)match.get("patient").get(0).get(0)).getIdPart());
|
||||
|
|
|
@ -53,6 +53,12 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
private static JpaValidationSupportChainDstu3 ourJpaValidationSupportChainDstu3;
|
||||
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
|
||||
|
||||
|
||||
@Autowired
|
||||
@Qualifier("mySearchParameterDaoDstu3")
|
||||
protected IFhirResourceDao<SearchParameter> mySearchParameterDao;
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegsitry;
|
||||
// @Autowired
|
||||
// protected HapiWorkerContext myHapiWorkerContext;
|
||||
@Autowired
|
||||
|
|
|
@ -0,0 +1,202 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu3Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3SearchCustomSearchParamTest.class);
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamInvalidResourceName() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("PatientFoo.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Invalid path value \"PatientFoo.gender\": Unknown resource name \"PatientFoo\" (this name is not known in FHIR version \"DSTU3\")", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamMismatchedResourceName() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender or Observation.code");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Invalid path value \"Observation.code\". All paths in a single SearchParameter must match the same resource type", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamNoPath() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Resource.xpath is missing", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamNoResourceName() {
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Invalid path value \"gender\". Must start with a resource name", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateInvalidParamParamNullStatus() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(null);
|
||||
try {
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Resource.status is missing or invalid: null", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithCustomParam() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat2 = new Patient();
|
||||
pat.setGender(AdministrativeGender.FEMALE);
|
||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Try with custom gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("foo", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
// Try with normal gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("gender", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithCustomParamDraft() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.DRAFT);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat2 = new Patient();
|
||||
pat.setGender(AdministrativeGender.FEMALE);
|
||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
|
||||
// Try with custom gender SP (should find nothing)
|
||||
map = new SearchParameterMap();
|
||||
map.add("foo", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, empty());
|
||||
|
||||
// Try with normal gender SP
|
||||
map = new SearchParameterMap();
|
||||
map.add("gender", new TokenParam(null, "male"));
|
||||
results = myPatientDao.search(map);
|
||||
foundResources = toUnqualifiedVersionlessIdValues(results);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
|
||||
|
@ -12,6 +15,9 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
|
@ -37,7 +43,29 @@ public class SearchParamExtractorDstu3Test {
|
|||
Observation obs = new Observation();
|
||||
obs.addCategory().addCoding().setSystem("SYSTEM").setCode("CODE");
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(ourCtx, ourValidationSupport);
|
||||
ISearchParamRegistry searchParamRegistry = new ISearchParamRegistry() {
|
||||
@Override
|
||||
public Map<String,RuntimeSearchParam> getActiveSearchParams(String theResourceName) {
|
||||
RuntimeResourceDefinition nextResDef = ourCtx.getResourceDefinition(theResourceName);
|
||||
Map<String, RuntimeSearchParam> sps = new HashMap<String, RuntimeSearchParam>();
|
||||
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
|
||||
sps.put(nextSp.getName(), nextSp);
|
||||
}
|
||||
return sps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceRefresh() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<RuntimeSearchParam> getAllSearchParams(String theResourceName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(ourCtx, ourValidationSupport, searchParamRegistry);
|
||||
Set<BaseResourceIndexedSearchParam> tokens = extractor.extractSearchParamTokens(new ResourceTable(), obs);
|
||||
assertEquals(1, tokens.size());
|
||||
ResourceIndexedSearchParamToken token = (ResourceIndexedSearchParamToken) tokens.iterator().next();
|
||||
|
|
|
@ -0,0 +1,319 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Observation;
|
||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.rest.gclient.ReferenceClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void saveCreateSearchParamInvalidWithMissingStatus() throws IOException {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setCode("foo");
|
||||
sp.setXpath("Patient.gender");
|
||||
sp.setXpathUsage(XPathUsageType.NORMAL);
|
||||
sp.setTitle("Foo Param");
|
||||
|
||||
try {
|
||||
ourClient.create().resource(sp).execute();
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("HTTP 422 Unprocessable Entity: Resource.status is missing or invalid: null", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
super.beforeResetConfig();
|
||||
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConformanceOverrideAllowed() {
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||
|
||||
CapabilityStatement conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
Map<String, CapabilityStatementRestResourceSearchParamComponent> map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
CapabilityStatementRestResourceSearchParamComponent param = map.get("foo");
|
||||
assertNull(param);
|
||||
|
||||
param = map.get("gender");
|
||||
assertNotNull(param);
|
||||
|
||||
// Add a custom search parameter
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
// Disable an existing parameter
|
||||
fooSp = new SearchParameter();
|
||||
fooSp.setCode("gender");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("Gender");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
param = map.get("foo");
|
||||
assertEquals("foo", param.getName());
|
||||
|
||||
param = map.get("gender");
|
||||
assertNull(param);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConformanceOverrideNotAllowed() {
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(false);
|
||||
|
||||
CapabilityStatement conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
Map<String, CapabilityStatementRestResourceSearchParamComponent> map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
CapabilityStatementRestResourceSearchParamComponent param = map.get("foo");
|
||||
assertNull(param);
|
||||
|
||||
param = map.get("gender");
|
||||
assertNotNull(param);
|
||||
|
||||
// Add a custom search parameter
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
// Disable an existing parameter
|
||||
fooSp = new SearchParameter();
|
||||
fooSp.setCode("gender");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("Gender");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
conformance = ourClient
|
||||
.fetchConformance()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
map = extractSearchParams(conformance, "Patient");
|
||||
|
||||
param = map.get("foo");
|
||||
assertEquals("foo", param.getName());
|
||||
|
||||
param = map.get("gender");
|
||||
assertNotNull(param);
|
||||
|
||||
}
|
||||
|
||||
private Map<String, CapabilityStatementRestResourceSearchParamComponent> extractSearchParams(CapabilityStatement conformance, String resType) {
|
||||
Map<String, CapabilityStatementRestResourceSearchParamComponent> map = new HashMap<String, CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent>();
|
||||
for (CapabilityStatementRestComponent nextRest : conformance.getRest()) {
|
||||
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) {
|
||||
if (!resType.equals(nextResource.getType())) {
|
||||
continue;
|
||||
}
|
||||
for (CapabilityStatementRestResourceSearchParamComponent nextParam : nextResource.getSearchParam()) {
|
||||
map.put(nextParam.getName(), nextParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchWithCustomParam() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pat2 = new Patient();
|
||||
pat2.setGender(AdministrativeGender.FEMALE);
|
||||
IIdType patId2 = myPatientDao.create(pat2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
Bundle result;
|
||||
|
||||
result = ourClient
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.where(new TokenClientParam("foo").exactly().code("male"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
foundResources = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(foundResources, contains(patId.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatingParamMarksCorrectResourcesForReindexing() {
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.setStatus(ObservationStatus.FINAL);
|
||||
IIdType obsId = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ResourceTable res = myResourceTableDao.findOne(patId.getIdPartAsLong());
|
||||
assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue());
|
||||
res = myResourceTableDao.findOne(obsId.getIdPartAsLong());
|
||||
assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue());
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.TOKEN);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Patient.gender");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
res = myResourceTableDao.findOne(patId.getIdPartAsLong());
|
||||
assertEquals(null, res.getIndexStatus());
|
||||
res = myResourceTableDao.findOne(obsId.getIdPartAsLong());
|
||||
assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, res.getIndexStatus().longValue());
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchQualifiedWithCustomReferenceParam() {
|
||||
|
||||
SearchParameter fooSp = new SearchParameter();
|
||||
fooSp.setCode("foo");
|
||||
fooSp.setType(org.hl7.fhir.dstu3.model.Enumerations.SearchParamType.REFERENCE);
|
||||
fooSp.setTitle("FOO SP");
|
||||
fooSp.setXpath("Observation.subject");
|
||||
fooSp.setXpathUsage(org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType.NORMAL);
|
||||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
IIdType patId = myPatientDao.create(pat, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs1 = new Observation();
|
||||
obs1.getSubject().setReferenceElement(patId);
|
||||
IIdType obsId1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs2 = new Observation();
|
||||
obs2.setStatus(org.hl7.fhir.dstu3.model.Observation.ObservationStatus.FINAL);
|
||||
IIdType obsId2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
List<String> foundResources;
|
||||
Bundle result;
|
||||
|
||||
result = ourClient
|
||||
.search()
|
||||
.forResource(Observation.class)
|
||||
.where(new ReferenceClientParam("foo").hasChainedProperty(Patient.GENDER.exactly().code("male")))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
foundResources = toUnqualifiedVersionlessIdValues(result);
|
||||
assertThat(foundResources, contains(obsId1.getValue()));
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -265,6 +265,24 @@
|
|||
<buildDatatypes>true</buildDatatypes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>target/generated-sources/tinder</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
|
|
|
@ -34,6 +34,8 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.model.api.BaseElement;
|
||||
import ca.uhn.fhir.model.api.ICompositeElement;
|
||||
import ca.uhn.fhir.model.api.IElement;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.Tag;
|
||||
|
@ -92,6 +94,17 @@ public abstract class BaseResource extends BaseElement implements IResource {
|
|||
@Child(name = "text", order = 1, min = 0, max = 1)
|
||||
private NarrativeDt myText;
|
||||
|
||||
/**
|
||||
* NOP implementation of this method.
|
||||
*
|
||||
* @see ICompositeElement#getAllPopulatedChildElementsOfType(Class) for an explanation of why you
|
||||
* don't need to override this method
|
||||
*/
|
||||
@Override
|
||||
public <T extends IElement> List<T> getAllPopulatedChildElementsOfType(Class<T> theType) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContainedDt getContained() {
|
||||
if (myContained == null) {
|
||||
|
|
|
@ -29,6 +29,14 @@ public class XhtmlDtTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseRsquo() {
|
||||
XhtmlDt dt = new XhtmlDt();
|
||||
dt.setValueAsString("It’s January again");
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">It’s January again</div>", dt.getValueAsString());
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">It’s January again</div>", new XhtmlDt().setValue(dt.getValue()).getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundtrip() {
|
||||
String div = "<div xmlns=\"http://www.w3.org/1999/xhtml\"><pre>\r\n<<a title=\"Prospective warnings of potential issues when providing care to the patient.\" class=\"dict\" href=\"alert-definitions.html#Alert\"><b>Alert</b></a> xmlns="http://hl7.org/fhir"> <span style=\"float: right\"><a title=\"Documentation for this format\" href=\"formats.html\"><img alt=\"doco\" src=\"help.png\"/></a></span>\r\n <!-- from <a href=\"resources.html\">Resource</a>: <a href=\"extensibility.html\">extension</a>, <a href=\"extensibility.html#modifierExtension\">modifierExtension</a>, language, <a href=\"narrative.html#Narrative\">text</a>, and <a href=\"references.html#contained\">contained</a> -->\r\n <<a title=\"Identifier assigned to the alert for external use (outside the FHIR environment).\" class=\"dict\" href=\"alert-definitions.html#Alert.identifier\"><b>identifier</b></a>><span style=\"color: Gray\"><!--</span> <span style=\"color: brown\"><b>0..*</b></span> <span style=\"color: darkgreen\"><a href=\"datatypes.html#Identifier\">Identifier</a></span> <span style=\"color: navy\">Business identifier</span><span style=\"color: Gray\"> --></span></identifier>\r\n <<a title=\"Allows an alert to be divided into different categories like clinical, administrative etc.\" class=\"dict\" href=\"alert-definitions.html#Alert.category\"><b>category</b></a>><span style=\"color: Gray\"><!--</span> <span style=\"color: brown\"><b>0..1</b></span> <span style=\"color: darkgreen\"><a href=\"datatypes.html#CodeableConcept\">CodeableConcept</a></span> <span style=\"color: navy\">Clinical, administrative, etc.</span><span style=\"color: Gray\"> --></span></category>\r\n <<a title=\"Supports basic workflow.\" class=\"dict\" href=\"alert-definitions.html#Alert.status\"><b>status</b></a> value="[<span style=\"color: darkgreen\"><a href=\"datatypes.html#code\">code</a></span>]"/><span style=\"color: Gray\"><!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: navy\"><a style=\"color: navy\" href=\"alert-status.html\">active | inactive | entered in error</a></span><span style=\"color: Gray\"> --></span>\r\n <<a title=\"The person who this alert concerns.\" class=\"dict\" href=\"alert-definitions.html#Alert.subject\"><b>subject</b></a>><span style=\"color: Gray\"><!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: darkgreen\"><a href=\"references.html#Resource\">Resource</a>(<a href=\"patient.html#Patient\">Patient</a>)</span> <span style=\"color: navy\">Who is alert about?</span><span style=\"color: Gray\"> --></span></subject>\r\n <<a title=\"The person or device that created the alert.\" class=\"dict\" href=\"alert-definitions.html#Alert.author\"><b>author</b></a>><span style=\"color: Gray\"><!--</span> <span style=\"color: brown\"><b>0..1</b></span> <span style=\"color: darkgreen\"><a href=\"references.html#Resource\">Resource</a>(<a href=\"practitioner.html#Practitioner\">Practitioner</a>|<a href=\"patient.html#Patient\">Patient</a>|<a href=\"device.html#Device\">Device</a>)</span> <span style=\"color: navy\">Alert creator</span><span style=\"color: Gray\"> --></span></author>\r\n <<a title=\"The textual component of the alert to display to the user.\" class=\"dict\" href=\"alert-definitions.html#Alert.note\"><b>note</b></a> value="[<span style=\"color: darkgreen\"><a href=\"datatypes.html#string\">string</a></span>]"/><span style=\"color: Gray\"><!--</span> <span style=\"color: brown\"><b>1..1</b></span> <span style=\"color: navy\">Text of alert</span><span style=\"color: Gray\"> --></span>\r\n</Alert>\r\n</pre></div>";
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheHttpResponse;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.HttpRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.HttpVersion;
|
||||
import org.apache.http.entity.BasicHttpEntity;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.message.BasicHttpRequest;
|
||||
import org.apache.http.message.BasicHttpResponse;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Spy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
|
||||
public class CapturingInterceptorTest {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
|
||||
@Test
|
||||
public void testRequest() {
|
||||
IHttpRequest expectedRequest = mock(IHttpRequest.class);
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptRequest(expectedRequest);
|
||||
|
||||
assertEquals(expectedRequest, interceptor.getLastRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponse() throws Exception {
|
||||
IHttpResponse expectedResponse = mock(IHttpResponse.class);
|
||||
doNothing().when(expectedResponse).bufferEntity();
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptResponse(expectedResponse);
|
||||
|
||||
assertEquals(expectedResponse, interceptor.getLastResponse());
|
||||
verify(expectedResponse).bufferEntity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseException() throws Exception {
|
||||
IHttpResponse response = mock(IHttpResponse.class);
|
||||
IOException expectedCause = new IOException();
|
||||
doThrow(expectedCause).when(response).bufferEntity();
|
||||
|
||||
thrown.expect(InternalErrorException.class);
|
||||
thrown.expectMessage("Unable to buffer the entity for capturing");
|
||||
thrown.expectCause(equalTo(expectedCause));
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptResponse(response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseBufferApache() throws Exception{
|
||||
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
|
||||
response.setEntity(new InputStreamEntity(IOUtils.toInputStream("Some content", Charset.defaultCharset())));
|
||||
IHttpResponse expectedResponse = spy(new ApacheHttpResponse(response));
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptResponse(expectedResponse);
|
||||
IHttpResponse actualResponse = interceptor.getLastResponse();
|
||||
|
||||
assertEquals(expectedResponse, actualResponse);
|
||||
assertThat("Some content", equalTo(IOUtils.toString(actualResponse.createReader())));
|
||||
verify(expectedResponse).bufferEntity();
|
||||
|
||||
//A second call should not throw an exception (InpuStreamEntity is not repeatable)
|
||||
IOUtils.toString(actualResponse.createReader());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseRepeatable() throws Exception{
|
||||
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
|
||||
response.setEntity(new StringEntity("Some content"));
|
||||
IHttpResponse expectedResponse = spy(new ApacheHttpResponse(response));
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptResponse(expectedResponse);
|
||||
IHttpResponse actualResponse = interceptor.getLastResponse();
|
||||
|
||||
assertEquals(expectedResponse, actualResponse);
|
||||
assertThat("Some content", equalTo(IOUtils.toString(actualResponse.createReader())));
|
||||
verify(expectedResponse, times(0)).bufferEntity();
|
||||
|
||||
//A second call should not throw an exception (StringEntity is repeatable)
|
||||
IOUtils.toString(actualResponse.createReader());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseBufferOther() throws Exception {
|
||||
Object response = mock(Object.class);
|
||||
IHttpResponse expectedResponse = mock(IHttpResponse.class);
|
||||
when(expectedResponse.getResponse()).thenReturn(response);
|
||||
doNothing().when(expectedResponse).bufferEntity();
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptResponse(expectedResponse);
|
||||
IHttpResponse actualResponse = interceptor.getLastResponse();
|
||||
|
||||
assertEquals(expectedResponse, actualResponse);
|
||||
verify(expectedResponse).bufferEntity();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear(){
|
||||
IHttpRequest expectedRequest = mock(IHttpRequest.class);
|
||||
IHttpResponse expectedResponse = mock(IHttpResponse.class);
|
||||
Object response = mock(Object.class);
|
||||
when(expectedResponse.getResponse()).thenReturn(response);
|
||||
|
||||
CapturingInterceptor interceptor = new CapturingInterceptor();
|
||||
interceptor.interceptResponse(expectedResponse);
|
||||
interceptor.interceptRequest(expectedRequest);
|
||||
|
||||
assertEquals(expectedRequest, interceptor.getLastRequest());
|
||||
assertEquals(expectedResponse, interceptor.getLastResponse());
|
||||
|
||||
interceptor.clear();
|
||||
|
||||
assertNull(interceptor.getLastRequest());
|
||||
assertNull(interceptor.getLastResponse());
|
||||
}
|
||||
|
||||
}
|
|
@ -59,6 +59,30 @@ public class QuantityParamTest {
|
|||
assertEquals("5.4||", p.getValueAsQueryToken(ourCtx));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoSystem() {
|
||||
// http://hl7.org/fhir/2017Jan/search.html#quantity
|
||||
// sample url: [baseurl]/Observation?value-quantity=5.5||mg
|
||||
String query = "5.5||mg";
|
||||
QuantityParam param = new QuantityParam();
|
||||
param.setValueAsQueryToken(null, "value-quantity", null, query);
|
||||
// Check parts. The 'mg' part should be put in the units not the system
|
||||
// System.out.println(param);
|
||||
assertEquals(null, param.getPrefix());
|
||||
assertEquals("5.5", param.getValue().toPlainString());
|
||||
assertEquals(null, param.getSystem());
|
||||
assertEquals("mg", param.getUnits());
|
||||
|
||||
// Make sure we don't break on this one...
|
||||
query = "5.5| |mg";
|
||||
param = new QuantityParam();
|
||||
param.setValueAsQueryToken(null, "value-quantity", null, query);
|
||||
// System.out.println(param);
|
||||
assertEquals(null, param.getPrefix());
|
||||
assertEquals("5.5", param.getValue().toPlainString());
|
||||
assertEquals(null, param.getSystem());
|
||||
assertEquals("mg", param.getUnits());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.junit.Test;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||
|
@ -175,8 +176,8 @@ public class DynamicSearchTest {
|
|||
@Override
|
||||
public List<RuntimeSearchParam> getSearchParameters() {
|
||||
ArrayList<RuntimeSearchParam> retVal = new ArrayList<RuntimeSearchParam>();
|
||||
retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING, null, null));
|
||||
retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE, null, null));
|
||||
retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", RestSearchParameterTypeEnum.STRING, null, null, RuntimeSearchParamStatusEnum.ACTIVE));
|
||||
retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", RestSearchParameterTypeEnum.DATE, null, null, RuntimeSearchParamStatusEnum.ACTIVE));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,17 @@ package ca.uhn.fhir.rest.server;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -54,7 +59,7 @@ public class ResourceMethodTest {
|
|||
inputParams.add("lastName");
|
||||
inputParams.add("mrn");
|
||||
|
||||
RequestDetails params = ServletRequestDetails.withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams);
|
||||
RequestDetails params = withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams);
|
||||
boolean actual = rm.incomingServerRequestMatchesMethod(params);
|
||||
assertTrue( actual); // True
|
||||
}
|
||||
|
@ -75,7 +80,7 @@ public class ResourceMethodTest {
|
|||
inputParams.add("mrn");
|
||||
inputParams.add("foo");
|
||||
|
||||
assertEquals(false, rm.incomingServerRequestMatchesMethod(ServletRequestDetails.withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // False
|
||||
assertEquals(false, rm.incomingServerRequestMatchesMethod(withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // False
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -92,7 +97,7 @@ public class ResourceMethodTest {
|
|||
inputParams.add("firstName");
|
||||
inputParams.add("mrn");
|
||||
|
||||
assertEquals(true, rm.incomingServerRequestMatchesMethod(ServletRequestDetails.withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // True
|
||||
assertEquals(true, rm.incomingServerRequestMatchesMethod(withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // True
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -109,7 +114,7 @@ public class ResourceMethodTest {
|
|||
inputParams.add("firstName");
|
||||
inputParams.add("lastName");
|
||||
|
||||
assertEquals(false, rm.incomingServerRequestMatchesMethod(ServletRequestDetails.withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // False
|
||||
assertEquals(false, rm.incomingServerRequestMatchesMethod(withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // False
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -124,7 +129,7 @@ public class ResourceMethodTest {
|
|||
|
||||
Set<String> inputParams = new HashSet<String>();
|
||||
inputParams.add("mrn");
|
||||
assertEquals(true, rm.incomingServerRequestMatchesMethod(ServletRequestDetails.withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // True
|
||||
assertEquals(true, rm.incomingServerRequestMatchesMethod(withResourceAndParams("Patient", RequestTypeEnum.GET, inputParams))); // True
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
|
@ -142,4 +147,18 @@ public class ResourceMethodTest {
|
|||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
public static RequestDetails withResourceAndParams(String theResourceName, RequestTypeEnum theRequestType, Set<String> theParamNames) {
|
||||
ServletRequestDetails retVal = new ServletRequestDetails();
|
||||
retVal.setResourceName(theResourceName);
|
||||
retVal.setRequestType(theRequestType);
|
||||
Map<String, String[]> paramNames = new HashMap<String, String[]>();
|
||||
for (String next : theParamNames) {
|
||||
paramNames.put(next, new String[0]);
|
||||
}
|
||||
retVal.setParameters(paramNames);
|
||||
retVal.setServletRequest(mock(HttpServletRequest.class));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class SearchPostDstu2_1Test {
|
|||
ourLastSortSpec = null;
|
||||
ourLastName = null;
|
||||
|
||||
for (IServerInterceptor next : new ArrayList<>(ourServlet.getInterceptors())) {
|
||||
for (IServerInterceptor next : new ArrayList<IServerInterceptor>(ourServlet.getInterceptors())) {
|
||||
ourServlet.unregisterInterceptor(next);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ public class ServerMimetypeDstu2_1Test {
|
|||
|
||||
|
||||
private List<String> toStrings(List<CodeType> theFormat) {
|
||||
ArrayList<String> retVal = new ArrayList<>();
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (CodeType next : theFormat) {
|
||||
retVal.add(next.asStringValue());
|
||||
}
|
||||
|
|
|
@ -96,8 +96,11 @@ public class ValidateDstu2_1Test {
|
|||
params.addParameter().setName("resource").setResource(patient);
|
||||
params.addParameter().setName("mode").setValue(new CodeType(" "));
|
||||
|
||||
|
||||
String encodedResource = ourCtx.newXmlParser().encodeResourceToString(params);
|
||||
|
||||
HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/$validate");
|
||||
httpPost.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(params), ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
httpPost.setEntity(new StringEntity(encodedResource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
|
||||
HttpResponse status = ourClient.execute(httpPost);
|
||||
String resp = IOUtils.toString(status.getEntity().getContent());
|
||||
|
|
|
@ -27,10 +27,7 @@
|
|||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
The JPA project uses a newer API but we'll try to hold to this version
|
||||
as much as possible. See #283.
|
||||
-->
|
||||
<!-- The JPA project uses a newer API but we'll try to hold to this version as much as possible. See #283. -->
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
|
@ -89,13 +86,7 @@
|
|||
<dependency>
|
||||
<groupId>com.phloc</groupId>
|
||||
<artifactId>phloc-schematron</artifactId>
|
||||
<scope>test</scope><!--
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>Saxon-HE</artifactId>
|
||||
<groupId>net.sf.saxon</groupId>
|
||||
</exclusion>
|
||||
</exclusions>-->
|
||||
<scope>test</scope><!-- <exclusions> <exclusion> <artifactId>Saxon-HE</artifactId> <groupId>net.sf.saxon</groupId> </exclusion> </exclusions> -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.phloc</groupId>
|
||||
|
@ -119,11 +110,7 @@
|
|||
<exclusion>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<groupId>commons-lang</groupId>
|
||||
</exclusion><!--
|
||||
<exclusion>
|
||||
<artifactId>ezmorph</artifactId>
|
||||
<groupId>net.sf.ezmorph</groupId>
|
||||
</exclusion>-->
|
||||
</exclusion><!-- <exclusion> <artifactId>ezmorph</artifactId> <groupId>net.sf.ezmorph</groupId> </exclusion> -->
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -140,11 +127,7 @@
|
|||
<exclusion>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<groupId>commons-lang</groupId>
|
||||
</exclusion><!--
|
||||
<exclusion>
|
||||
<artifactId>ezmorph</artifactId>
|
||||
<groupId>net.sf.ezmorph</groupId>
|
||||
</exclusion>-->
|
||||
</exclusion><!-- <exclusion> <artifactId>ezmorph</artifactId> <groupId>net.sf.ezmorph</groupId> </exclusion> -->
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -252,9 +235,7 @@
|
|||
<baseResourceName>deviceusestatement</baseResourceName>
|
||||
<baseResourceName>diagnosticorder</baseResourceName>
|
||||
<baseResourceName>diagnosticreport</baseResourceName>
|
||||
<!-- This is not a real resource
|
||||
<baseResourceName>documentation</baseResourceName>
|
||||
-->
|
||||
<!-- This is not a real resource <baseResourceName>documentation</baseResourceName> -->
|
||||
<baseResourceName>documentmanifest</baseResourceName>
|
||||
<baseResourceName>documentreference</baseResourceName>
|
||||
<baseResourceName>eligibilityrequest</baseResourceName>
|
||||
|
@ -332,6 +313,24 @@
|
|||
</configuration> </execution> -->
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>target/generated-sources/tinder</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
|
|
|
@ -3,10 +3,12 @@ package ca.uhn.fhir.model;
|
|||
import static org.junit.Assert.*;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.ExplanationOfBenefit;
|
||||
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.primitive.XhtmlDt;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class XhtmlNodeTest {
|
||||
|
@ -20,6 +22,15 @@ public class XhtmlNodeTest {
|
|||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
|
||||
@Test
|
||||
public void testParseRsquo() {
|
||||
XhtmlNode dt = new XhtmlNode();
|
||||
dt.setValueAsString("It’s January again");
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">It’s January again</div>", dt.getValueAsString());
|
||||
assertEquals("<div xmlns=\"http://www.w3.org/1999/xhtml\">It’s January again</div>", new XhtmlNode().setValue(dt.getValue()).getValueAsString());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #443
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.dstu3.model.HumanName;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||
import ca.uhn.fhir.rest.annotation.RawParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
public class SearchDefaultMethodDstu3Test {
|
||||
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchDefaultMethodDstu3Test.class);
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static String ourLastMethod;
|
||||
private static StringAndListParam ourLastParam1;
|
||||
private static StringAndListParam ourLastParam2;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourLastParam1 = null;
|
||||
ourLastParam2 = null;
|
||||
ourLastAdditionalParams = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNoParams() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(ourLastMethod, either(equalTo("search01")).or(equalTo("search02")));
|
||||
assertEquals(null, ourLastParam1);
|
||||
assertEquals(null, ourLastParam2);
|
||||
assertEquals(null, ourLastAdditionalParams);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchOneOptionalParam() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=val1");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens(), hasSize(1));
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val1", ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
assertEquals(null, ourLastParam2);
|
||||
assertEquals(null, ourLastAdditionalParams);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchTwoOptionalParams() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=val1¶m2=val2");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens(), hasSize(1));
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val1", ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
|
||||
assertThat(ourLastParam2.getValuesAsQueryTokens(), hasSize(1));
|
||||
assertThat(ourLastParam2.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val2", ourLastParam2.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
|
||||
assertEquals(null, ourLastAdditionalParams);
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchTwoOptionalParamsAndExtraParam() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=val1¶m2=val2¶m3=val3&_pretty=true");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("search03", ourLastMethod);
|
||||
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens(), hasSize(1));
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val1", ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
|
||||
assertThat(ourLastParam2.getValuesAsQueryTokens(), hasSize(1));
|
||||
assertThat(ourLastParam2.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val2", ourLastParam2.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
|
||||
ourLog.info(ourLastAdditionalParams.toString());
|
||||
assertEquals(1, ourLastAdditionalParams.size());
|
||||
assertEquals("val3", ourLastAdditionalParams.get("param3").get(0));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchTwoOptionalParamsWithQualifierAndExtraParam() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=val1¶m2=val2¶m2:exact=val2e¶m3=val3&_pretty=true");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("search03", ourLastMethod);
|
||||
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens(), hasSize(1));
|
||||
assertThat(ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val1", ourLastParam1.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
|
||||
assertThat(ourLastParam2.getValuesAsQueryTokens(), hasSize(2));
|
||||
assertThat(ourLastParam2.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens(), hasSize(1));
|
||||
assertEquals("val2", ourLastParam2.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
assertEquals("val2e", ourLastParam2.getValuesAsQueryTokens().get(1).getValuesAsQueryTokens().get(0).getValue());
|
||||
|
||||
ourLog.info(ourLastAdditionalParams.toString());
|
||||
assertEquals(1, ourLastAdditionalParams.size());
|
||||
assertEquals("val3", ourLastAdditionalParams.get("param3").get(0));
|
||||
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourPort = PortUtil.findFreePort();
|
||||
ourServer = new Server(ourPort);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
ourServer.start();
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
private static Map<String, List<String>> ourLastAdditionalParams;
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public List<Patient> search01(
|
||||
@OptionalParam(name = "param1") StringAndListParam theParam1) {
|
||||
ourLastMethod = "search01";
|
||||
ourLastParam1 = theParam1;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
retVal.add((Patient) new Patient().addName(new HumanName().setFamily("FAMILY")).setId("1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Search()
|
||||
public List<Patient> search02(
|
||||
@OptionalParam(name = "param1") StringAndListParam theParam1,
|
||||
@OptionalParam(name = "param2") StringAndListParam theParam2) {
|
||||
ourLastMethod = "search02";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
retVal.add((Patient) new Patient().addName(new HumanName().setFamily("FAMILY")).setId("1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Search(allowUnknownParams = true)
|
||||
public List<Patient> search03(
|
||||
@OptionalParam(name = "param1") StringAndListParam theParam1,
|
||||
@OptionalParam(name = "param2") StringAndListParam theParam2,
|
||||
@RawParam() Map<String, List<String>> theAdditionalParams) {
|
||||
ourLastMethod = "search03";
|
||||
ourLastParam1 = theParam1;
|
||||
ourLastParam2 = theParam2;
|
||||
ourLastAdditionalParams = theAdditionalParams;
|
||||
ArrayList<Patient> retVal = new ArrayList<Patient>();
|
||||
retVal.add((Patient) new Patient().addName(new HumanName().setFamily("FAMILY")).setId("1"));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -82,7 +82,7 @@ public class SearchPostDstu3Test {
|
|||
ourLastSortSpec = null;
|
||||
ourLastName = null;
|
||||
|
||||
for (IServerInterceptor next : new ArrayList<>(ourServlet.getInterceptors())) {
|
||||
for (IServerInterceptor next : new ArrayList<IServerInterceptor>(ourServlet.getInterceptors())) {
|
||||
ourServlet.unregisterInterceptor(next);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public class ServerMimetypeDstu3Test {
|
|||
|
||||
|
||||
private List<String> toStrings(List<CodeType> theFormat) {
|
||||
ArrayList<String> retVal = new ArrayList<>();
|
||||
ArrayList<String> retVal = new ArrayList<String>();
|
||||
for (CodeType next : theFormat) {
|
||||
retVal.add(next.asStringValue());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
|
||||
org.eclipse.jdt.core.compiler.compliance=1.6
|
||||
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.6
|
|
@ -39,7 +39,7 @@ public class ${className}ResourceProvider extends
|
|||
return ${className}.class;
|
||||
}
|
||||
|
||||
@Search()
|
||||
@Search(allowUnknownParams=true)
|
||||
public ca.uhn.fhir.rest.server.IBundleProvider search(
|
||||
javax.servlet.http.HttpServletRequest theServletRequest,
|
||||
|
||||
|
@ -99,6 +99,9 @@ public class ${className}ResourceProvider extends
|
|||
#end
|
||||
#end
|
||||
|
||||
@RawParam
|
||||
Map<String, List<String>> theAdditionalRawParams,
|
||||
|
||||
#if ( $version != 'dstu' )
|
||||
@IncludeParam(reverse=true)
|
||||
Set<Include> theRevIncludes,
|
||||
|
@ -151,6 +154,8 @@ public class ${className}ResourceProvider extends
|
|||
paramMap.setCount(theCount);
|
||||
paramMap.setRequestDetails(theRequestDetails);
|
||||
|
||||
getDao().translateRawParameters(theAdditionalRawParams, paramMap);
|
||||
|
||||
ca.uhn.fhir.rest.server.IBundleProvider retVal = getDao().search(paramMap);
|
||||
return retVal;
|
||||
} finally {
|
||||
|
|
|
@ -21,9 +21,7 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
|
||||
@Configuration
|
||||
public abstract class BaseJavaConfig${versionCapitalized} extends ca.uhn.fhir.jpa.config${package_suffix}.Base${versionCapitalized}Config {
|
||||
|
@ -49,12 +47,23 @@ public abstract class BaseJavaConfig${versionCapitalized} extends ca.uhn.fhir.jp
|
|||
#foreach ( $res in $resources )
|
||||
@Bean(name="my${res.name}Dao${versionCapitalized}", autowire=Autowire.BY_NAME)
|
||||
@Lazy
|
||||
public IFhirResourceDao<${resourcePackage}.${res.declaringClassNameComplete}> dao${res.declaringClassNameComplete}${versionCapitalized}() {
|
||||
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}> retVal;
|
||||
#if ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Bundle' || ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'ValueSet' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'SearchParameter' || ${res.name} == 'CodeSystem'))
|
||||
retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized}();
|
||||
public
|
||||
#if ( ${versionCapitalized} == 'Dstu2' && ${res.name} == 'ValueSet' )
|
||||
IFhirResourceDaoValueSet<ca.uhn.fhir.model.dstu2.resource.ValueSet, ca.uhn.fhir.model.dstu2.composite.CodingDt, ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt>
|
||||
#elseif ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'ValueSet' )
|
||||
IFhirResourceDaoValueSet<org.hl7.fhir.dstu3.model.ValueSet, org.hl7.fhir.dstu3.model.Coding, org.hl7.fhir.dstu3.model.CodeableConcept>
|
||||
#elseif ( ${versionCapitalized} == 'Dstu3' && ${res.name} == 'CodeSystem' )
|
||||
IFhirResourceDaoCodeSystem<org.hl7.fhir.dstu3.model.CodeSystem, org.hl7.fhir.dstu3.model.Coding, org.hl7.fhir.dstu3.model.CodeableConcept>
|
||||
#elseif ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'SearchParameter'))
|
||||
IFhirResourceDao${res.name}<${resourcePackage}.${res.declaringClassNameComplete}>
|
||||
#else
|
||||
retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}>();
|
||||
IFhirResourceDao<${resourcePackage}.${res.declaringClassNameComplete}>
|
||||
#end
|
||||
dao${res.declaringClassNameComplete}${versionCapitalized}() {
|
||||
#if ( ${versionCapitalized} != 'Dstu1' && ( ${res.name} == 'Bundle' || ${res.name} == 'Encounter' || ${res.name} == 'Everything' || ${res.name} == 'Patient' || ${res.name} == 'Subscription' || ${res.name} == 'ValueSet' || ${res.name} == 'QuestionnaireResponse' || ${res.name} == 'SearchParameter' || ${res.name} == 'CodeSystem'))
|
||||
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized} retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${res.name}${versionCapitalized}();
|
||||
#else
|
||||
ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}> retVal = new ca.uhn.fhir.jpa.dao${package_suffix}.FhirResourceDao${versionCapitalized}<${resourcePackage}.${res.declaringClassNameComplete}>();
|
||||
#end
|
||||
retVal.setResourceType(${resourcePackage}.${res.declaringClassNameComplete}.class);
|
||||
retVal.setContext(fhirContext${versionCapitalized}());
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<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">
|
||||
<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>
|
||||
|
@ -30,10 +29,8 @@
|
|||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Because Tinder is a part of the HAPI FHIR build process (it generates
|
||||
a bunch of the actual HAPI structure code), but also uses HAPI FHIR in order
|
||||
to run (e.g. to load ValueSet resources), we keep the dependencies for the
|
||||
structures a version behind the main library. This is weird, but it works. -->
|
||||
<!-- Because Tinder is a part of the HAPI FHIR build process (it generates a bunch of the actual HAPI structure code), but also uses HAPI FHIR in order to run (e.g. to load ValueSet resources), we keep
|
||||
the dependencies for the structures a version behind the main library. This is weird, but it works. -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||
|
@ -76,17 +73,11 @@
|
|||
|
||||
<build>
|
||||
<plugins>
|
||||
<!-- <plugin> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-tinder-plugin</artifactId>
|
||||
<version>1.0-SNAPSHOT</version> <executions> <execution> <id>structs</id>
|
||||
<goals> <goal>generate-structures</goal> </goals> <configuration> <package>ca.uhn.tindertest</package>
|
||||
<baseResourceNames> <baseResourceName>patient</baseResourceName> <baseResourceName>valueset</baseResourceName>
|
||||
<baseResourceName>organization</baseResourceName> <baseResourceName>device</baseResourceName>
|
||||
<baseResourceName>location</baseResourceName> <baseResourceName>practitioner</baseResourceName>
|
||||
</baseResourceNames> </configuration> </execution> <execution> <id>client</id>
|
||||
<goals> <goal>generate-client</goal> </goals> <configuration> <clientClassName>ca.uhn.hitest.HiTest</clientClassName>
|
||||
<serverBaseHref>http://fhir.healthintersections.com.au/open</serverBaseHref>
|
||||
<generateSearchForAllParams>true</generateSearchForAllParams> </configuration>
|
||||
</execution> </executions> </plugin> -->
|
||||
<!-- <plugin> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-tinder-plugin</artifactId> <version>1.0-SNAPSHOT</version> <executions> <execution> <id>structs</id> <goals> <goal>generate-structures</goal>
|
||||
</goals> <configuration> <package>ca.uhn.tindertest</package> <baseResourceNames> <baseResourceName>patient</baseResourceName> <baseResourceName>valueset</baseResourceName> <baseResourceName>organization</baseResourceName>
|
||||
<baseResourceName>device</baseResourceName> <baseResourceName>location</baseResourceName> <baseResourceName>practitioner</baseResourceName> </baseResourceNames> </configuration> </execution> <execution>
|
||||
<id>client</id> <goals> <goal>generate-client</goal> </goals> <configuration> <clientClassName>ca.uhn.hitest.HiTest</clientClassName> <serverBaseHref>http://fhir.healthintersections.com.au/open</serverBaseHref>
|
||||
<generateSearchForAllParams>true</generateSearchForAllParams> </configuration> </execution> </executions> </plugin> -->
|
||||
|
||||
<plugin>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
|
@ -268,11 +259,8 @@
|
|||
</includeResources>
|
||||
</configuration>
|
||||
</execution>
|
||||
<!-- <execution> <id>client</id> <goals> <goal>generate-client</goal>
|
||||
</goals> <configuration> <clientClassName>ca.uhn.hitest.HiTest</clientClassName>
|
||||
<serverBaseHref>http://fhir.healthintersections.com.au/open</serverBaseHref>
|
||||
<generateSearchForAllParams>true</generateSearchForAllParams> </configuration>
|
||||
</execution> -->
|
||||
<!-- <execution> <id>client</id> <goals> <goal>generate-client</goal> </goals> <configuration> <clientClassName>ca.uhn.hitest.HiTest</clientClassName> <serverBaseHref>http://fhir.healthintersections.com.au/open</serverBaseHref>
|
||||
<generateSearchForAllParams>true</generateSearchForAllParams> </configuration> </execution> -->
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
|
@ -286,77 +274,65 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<target>
|
||||
<taskdef name="hapi-tinder"
|
||||
classname="ca.uhn.fhir.tinder.ant.TinderGeneratorTask"
|
||||
classpathref="maven.plugin.classpath" />
|
||||
<taskdef name="hapi-tinder" classname="ca.uhn.fhir.tinder.ant.TinderGeneratorTask" classpathref="maven.plugin.classpath" />
|
||||
|
||||
<hapi-tinder
|
||||
templateFile="${project.basedir}/src/test/resources/templates/resource_test.vm"
|
||||
generateResources="true"
|
||||
targetSourceDirectory="${project.build.directory}/generated-sources/tinder"
|
||||
targetPackage="ca.uhn.test.ant.multi" filenameSuffix="ResourceTest.java"
|
||||
projectHome="${project.basedir}/.." version="dstu2"
|
||||
includeResources="patient,organization" />
|
||||
<hapi-tinder templateFile="${project.basedir}/src/test/resources/templates/resource_test.vm" generateResources="true" targetSourceDirectory="${project.build.directory}/generated-sources/tinder"
|
||||
targetPackage="ca.uhn.test.ant.multi" filenameSuffix="ResourceTest.java" projectHome="${project.basedir}/.." version="dstu2" includeResources="patient,organization" />
|
||||
|
||||
<hapi-tinder
|
||||
templateFile="${project.basedir}/src/test/resources/templates/resource_test_beans_java.vm"
|
||||
generateResources="true"
|
||||
targetSourceDirectory="${project.build.directory}/generated-sources/tinder"
|
||||
targetFile="TestConfigDstu2.java" targetPackage="ca.uhn.test.ant.single"
|
||||
packageBase="ca.uhn.test.ant.multi" projectHome="${project.basedir}/.."
|
||||
version="dstu2" includeResources="patient,organization" />
|
||||
<hapi-tinder templateFile="${project.basedir}/src/test/resources/templates/resource_test_beans_java.vm" generateResources="true" targetSourceDirectory="${project.build.directory}/generated-sources/tinder"
|
||||
targetFile="TestConfigDstu2.java" targetPackage="ca.uhn.test.ant.single" packageBase="ca.uhn.test.ant.multi" projectHome="${project.basedir}/.." version="dstu2" includeResources="patient,organization" />
|
||||
|
||||
</target>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-tinder-plugin</artifactId>
|
||||
|
@ -371,11 +347,28 @@
|
|||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>target/generated-sources/tinder</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings
|
||||
only. It has no influence on the Maven build itself. -->
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
|
@ -428,6 +421,14 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${basedir}/target/generated-resources/tinder</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
53
pom.xml
53
pom.xml
|
@ -288,6 +288,19 @@
|
|||
<id>rqg0717</id>
|
||||
<name>James Ren</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>Robbert1</id>
|
||||
<name>Robbert van Waveren</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>daliboz</id>
|
||||
<name>Jenny Syed</name>
|
||||
<organization>Cerner</organization>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>sekaijin</id>
|
||||
<name>sekaijin</name>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
|
@ -311,18 +324,18 @@
|
|||
<derby_version>10.13.1.1</derby_version>
|
||||
<jersey_version>2.24</jersey_version>
|
||||
<jetty_version>9.3.14.v20161028</jetty_version>
|
||||
<!-- Note on Hibernate versions: Hibernate 4.3+ uses JPA 2.1, which is too new for a number of platforms including JBoss EAP 6.x and Glassfish 3.0. Upgrade this version with caution! Also note that if
|
||||
you change this, you may get a failure in hibernate4-maven-plugin. See the note in hapi-fhir-jpaserver-base/pom.xml's configuration for that plugin... -->
|
||||
<!-- 5.2.0 has issues with hibernate-search 5.5.3 -->
|
||||
<hibernate_version>5.1.0.Final</hibernate_version>
|
||||
<hibernate_validator_version>5.2.4.Final</hibernate_validator_version>
|
||||
<hibernate_version>5.2.7.Final</hibernate_version>
|
||||
<hibernate_validator_version>5.3.4.Final</hibernate_validator_version>
|
||||
<!-- Update lucene version when you update hibernate-search version -->
|
||||
<hibernate_search_version>5.7.0.CR1</hibernate_search_version>
|
||||
<lucene_version>5.5.2</lucene_version>
|
||||
<maven_assembly_plugin_version>2.5.3</maven_assembly_plugin_version>
|
||||
<maven_license_plugin_version>1.8</maven_license_plugin_version>
|
||||
<maven_source_plugin_version>2.4</maven_source_plugin_version>
|
||||
<phloc_schematron_version>2.7.1</phloc_schematron_version>
|
||||
<phloc_commons_version>4.4.6</phloc_commons_version>
|
||||
<spring_version>4.3.1.RELEASE</spring_version>
|
||||
<thymeleaf-version>3.0.1.RELEASE</thymeleaf-version>
|
||||
<spring_version>4.3.6.RELEASE</spring_version>
|
||||
<thymeleaf-version>3.0.2.RELEASE</thymeleaf-version>
|
||||
<xmlunit_version>1.6</xmlunit_version>
|
||||
|
||||
<!-- We are aiming to still work on a very old version of SLF4j even though we depend on the newest, just to be nice to users of the API. This version is tested in the hapi-fhir-cobertura. -->
|
||||
|
@ -516,12 +529,12 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-highlighter</artifactId>
|
||||
<version>5.3.1</version>
|
||||
<version>${lucene_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.lucene</groupId>
|
||||
<artifactId>lucene-analyzers-phonetic</artifactId>
|
||||
<version>5.3.1</version>
|
||||
<version>${lucene_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.maven.doxia</groupId>
|
||||
|
@ -676,7 +689,7 @@
|
|||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
<version>5.5.4.Final</version>
|
||||
<version>${hibernate_search_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.javassist</groupId>
|
||||
|
@ -821,7 +834,6 @@
|
|||
-->
|
||||
<testSource>1.8</testSource>
|
||||
<testTarget>1.8</testTarget>
|
||||
<compilerId>javac-with-errorprone</compilerId>
|
||||
<forceJavacCompilerUse>true</forceJavacCompilerUse>
|
||||
<encoding>UTF-8</encoding>
|
||||
</configuration>
|
||||
|
@ -1055,6 +1067,7 @@
|
|||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
<!--
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>
|
||||
|
@ -1094,6 +1107,7 @@
|
|||
<ignore></ignore>
|
||||
</action>
|
||||
</pluginExecution>
|
||||
-->
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
|
@ -1643,7 +1657,8 @@
|
|||
<module>hapi-fhir-cli</module>
|
||||
<module>hapi-fhir-dist</module>
|
||||
<module>examples</module>
|
||||
<module>hapi-fhir-base-example-embedded-ws</module>
|
||||
<module>example-projects/hapi-fhir-base-example-embedded-ws</module>
|
||||
<module>example-projects/hapi-fhir-standalone-overlay-example</module>
|
||||
<module>hapi-fhir-jacoco</module>
|
||||
</modules>
|
||||
</profile>
|
||||
|
@ -1661,6 +1676,20 @@
|
|||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>ERRORPRONE</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerId>javac-with-errorprone</compilerId>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<modules>
|
||||
|
|
|
@ -6,6 +6,124 @@
|
|||
<title>HAPI FHIR Changelog</title>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="2.3" date="TBD">
|
||||
<action type="add">
|
||||
Bump the version of a few dependencies to the
|
||||
latest versions (dependent HAPI modules listed in brackets):
|
||||
<![CDATA[
|
||||
<ul>
|
||||
<li>Hibernate (JPA): 5.1.0 -> 5.2.7</li>
|
||||
<li>Hibernate Search (JPA): 5.5.4 ->p; 5.7.0.CR1</li>
|
||||
<li>Hibernate Validator (JPA): 5.2.4 ->p; 5.3.4</li>
|
||||
<li>Spring (JPA): 4.3.1 -> 4.3.6</li>
|
||||
</ul>
|
||||
]]>
|
||||
</action>
|
||||
<action type="add">
|
||||
The JPA server now supports custom search parameters in DSTU3
|
||||
mode. This allows users to create search parameters which contain
|
||||
custom paths, or even override and disable existing search
|
||||
parameters.
|
||||
<action type="fix">
|
||||
CLI example uploader couldn't find STU3 examples after CI server
|
||||
was moved to build.fhir.org
|
||||
</action>
|
||||
<action type="fix">
|
||||
Fix issue in JPA subscription module that prevented purging stale
|
||||
subscriptions when many were present on Postgres
|
||||
</action>
|
||||
<action type="fix" issue="532">
|
||||
Server interceptor methods were being called twice unnecessarily
|
||||
by the JPA server, and the DaoConfig interceptor registration
|
||||
framework was not actually useful. Thanks to GitHub user
|
||||
@mattiuusitalo for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="503">
|
||||
AuthorizationInterceptor on JPA server did not correctly
|
||||
apply rules on deleting resources in a specific compartment
|
||||
because the resource metadata was stripped by the JPA server
|
||||
before the interceptor could see it. Thanks to
|
||||
Eeva Turkka for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="519">
|
||||
JPA server exported CapabilityStatement includes
|
||||
double entries for the _id parameter and uses the
|
||||
wrong type (string instead of token). Thanks to
|
||||
Robert Lichtenberger for reporting!
|
||||
</action>
|
||||
<action type="add" issue="504">
|
||||
Custom resource types which extend Binary must not
|
||||
have declared extensions since this is invalid in
|
||||
FHIR (and HAPI would just ignore them anyhow). Thanks
|
||||
to Thomas S Berg for reporting!
|
||||
</action>
|
||||
<action type="add">
|
||||
Standard HAPI zip/tar distributions did not include the project
|
||||
sources and JavaDoc JARs. Thanks to Keith Boone for pointing
|
||||
this out!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server AuthorizationInterceptor always rejects history operation
|
||||
at the type level even if rules should allow it.
|
||||
</action>
|
||||
<action type="fix">
|
||||
JPA server terminology service was not correctly validating or expanding codes
|
||||
in SNOMED CT or LOINC code systems. Thanks to David Hay for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="539">
|
||||
Attempting to search for an invalid resource type (e.g. GET base/FooResource) should
|
||||
return an HTTP 404 and not a 400, per the HTTP spec. Thanks to
|
||||
GitHub user @CarthageKing for the pull request!
|
||||
</action>
|
||||
<action type="fix" issue="544">
|
||||
When parsing a Bundle containing placeholder fullUrls and references
|
||||
(e.g. "urn:uuid:0000-0000") the resource reference targets did not get
|
||||
populated with the given resources. Note that as a part of this
|
||||
change, <![CDATA[<code>IdType</code> and <code>IdDt</code>]]> have been modified
|
||||
so that when parsing a placeholder ID, the complete placeholder including the
|
||||
"urn:uuid:" or "urn:oid:" prefix will be placed into the ID part. Previously,
|
||||
the prefix was treated as the base URL, which led to strange behaviour
|
||||
like the placeholder being treated as a real IDs. Thanks to GitHub
|
||||
user @jodue for reporting!
|
||||
</action>
|
||||
<action type="add">
|
||||
Declared extensions with multiple type() options listed in the @Child
|
||||
annotation caused a crash on startup. Now this is supported.
|
||||
</action>
|
||||
<action type="add">
|
||||
STU3 XHTML parser for narrative choked if the narrative contained
|
||||
an <![CDATA[<code>&rsquot;</code>]]> entity string.
|
||||
</action>
|
||||
<action type="fix" issue="538">
|
||||
When parsing a quantity parameter on the server with a
|
||||
value and units but no system (e.g.
|
||||
<![CDATA[<code>GET [base]/Observation?value=5.4||mg</code>]]>)
|
||||
the unit was incorrectly treated as the system. Thanks to
|
||||
@CarthageKing for the pull request!
|
||||
</action>
|
||||
<action type="533">
|
||||
Correct a typo in the JPA ValueSet ResourceProvider which prevented
|
||||
successful operation under Spring 4.3. Thanks to
|
||||
Robbert van Waveren for the pull request!
|
||||
</action>
|
||||
<action type="remove">
|
||||
Deprecate the method
|
||||
<![CDATA[<code>ICompositeElement#getAllPopulatedChildElementsOfType(Class)</code>]]>
|
||||
as it is no longer used by HAPI and is just an annoying step
|
||||
in creating custom structures. Thanks to Allan Bro Hansen
|
||||
for pointing this out.
|
||||
</action>
|
||||
<action type="fix" issue="547">
|
||||
CapturingInterceptor did not buffer the response meaning
|
||||
that in many circumstances it did not actually capture
|
||||
the response. Thanks to Jenny Syed of Cerner for
|
||||
the pull request and contribution!
|
||||
</action>
|
||||
<action type="fix" issue="548">
|
||||
Clean up dependencies and remove Eclipse project files from git. Thanks to
|
||||
@sekaijin for the pull request!
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.2" date="2016-12-20">
|
||||
<action type="add">
|
||||
Bump the version of a few dependencies to the
|
||||
|
@ -237,6 +355,35 @@
|
|||
Declared extensions with multiple type() options listed in the @Child
|
||||
annotation caused a crash on startup. Now this is supported.
|
||||
</action>
|
||||
<action type="add">
|
||||
STU3 XHTML parser for narrative choked if the narrative contained
|
||||
an <![CDATA[<code>&rsquot;</code>]]> entity string.
|
||||
</action>
|
||||
<action type="fix" issue="538">
|
||||
When parsing a quantity parameter on the server with a
|
||||
value and units but no system (e.g.
|
||||
<![CDATA[<code>GET [base]/Observation?value=5.4||mg</code>]]>)
|
||||
the unit was incorrectly treated as the system. Thanks to
|
||||
@CarthageKing for the pull request!
|
||||
</action>
|
||||
<action type="533">
|
||||
Correct a typo in the JPA ValueSet ResourceProvider which prevented
|
||||
successful operation under Spring 4.3. Thanks to
|
||||
Robbert van Waveren for the pull request!
|
||||
</action>
|
||||
<action type="remove">
|
||||
Deprecate the method
|
||||
<![CDATA[<code>ICompositeElement#getAllPopulatedChildElementsOfType(Class)</code>]]>
|
||||
as it is no longer used by HAPI and is just an annoying step
|
||||
in creating custom structures. Thanks to Allan Bro Hansen
|
||||
for pointing this out.
|
||||
</action>
|
||||
<action type="fix" issue="547">
|
||||
CapturingInterceptor did not buffer the response meaning
|
||||
that in many circumstances it did not actually capture
|
||||
the response. Thanks to Jenny Syed of Cerner for
|
||||
the pull request and contribution!
|
||||
</action>
|
||||
</release>
|
||||
<release version="2.1" date="2016-11-11">
|
||||
<action type="add">
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue