add server using jaxrs
This commit is contained in:
parent
9664174b6a
commit
b4df6f9612
|
@ -0,0 +1,5 @@
|
||||||
|
package ca.uhn.fhir.rest.method;
|
||||||
|
|
||||||
|
public interface IRestfulHeader {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2015 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 interface IRestfulServer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain providers should generally use this context if one is needed, as opposed to
|
||||||
|
* creating their own.
|
||||||
|
*/
|
||||||
|
public FhirContext getFhirContext();
|
||||||
|
|
||||||
|
public List<IServerInterceptor> getInterceptors();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
public interface IRestfulServerDefaults {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should the server "pretty print" responses by default (requesting clients can always override this default by supplying an <code>Accept</code> header in the request, or a <code>_pretty</code>
|
||||||
|
* parameter in the request URL.
|
||||||
|
* <p>
|
||||||
|
* The default is <code>false</code>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return Returns the default pretty print setting
|
||||||
|
*/
|
||||||
|
public boolean isDefaultPrettyPrint();
|
||||||
|
|
||||||
|
}
|
|
@ -41,7 +41,6 @@ import java.util.concurrent.locks.Lock;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.UnavailableException;
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
@ -76,7 +75,7 @@ import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import ca.uhn.fhir.util.VersionUtil;
|
import ca.uhn.fhir.util.VersionUtil;
|
||||||
|
|
||||||
public class RestfulServer extends HttpServlet {
|
public class RestfulServer extends HttpServlet implements IRestfulServerDefaults, IRestfulServer {
|
||||||
|
|
||||||
private static final ExceptionHandlingInterceptor DEFAULT_EXCEPTION_HANDLER = new ExceptionHandlingInterceptor();
|
private static final ExceptionHandlingInterceptor DEFAULT_EXCEPTION_HANDLER = new ExceptionHandlingInterceptor();
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
@ -1086,6 +1085,7 @@ public class RestfulServer extends HttpServlet {
|
||||||
*
|
*
|
||||||
* @return Returns the default pretty print setting
|
* @return Returns the default pretty print setting
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public boolean isDefaultPrettyPrint() {
|
public boolean isDefaultPrettyPrint() {
|
||||||
return myDefaultPrettyPrint;
|
return myDefaultPrettyPrint;
|
||||||
}
|
}
|
||||||
|
|
|
@ -510,7 +510,7 @@ public class RestfulServerUtils {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean prettyPrintResponse(RestfulServer theServer, RequestDetails theRequest) {
|
public static boolean prettyPrintResponse(IRestfulServerDefaults theServer, RequestDetails theRequest) {
|
||||||
Map<String, String[]> requestParams = theRequest.getParameters();
|
Map<String, String[]> requestParams = theRequest.getParameters();
|
||||||
String[] pretty = requestParams.get(Constants.PARAM_PRETTY);
|
String[] pretty = requestParams.get(Constants.PARAM_PRETTY);
|
||||||
boolean prettyPrint;
|
boolean prettyPrint;
|
||||||
|
|
|
@ -0,0 +1,215 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
|
|
||||||
|
public class RestulfulServerConfiguration {
|
||||||
|
|
||||||
|
private List<ResourceBinding> resourceBindings;
|
||||||
|
private List<BaseMethodBinding<?>> serverBindings;
|
||||||
|
private String implementationDescription;
|
||||||
|
private String serverVersion;
|
||||||
|
private String serverName;
|
||||||
|
private FhirContext fhirContext;
|
||||||
|
private ServletContext servletContext;
|
||||||
|
private IServerAddressStrategy serverAddressStrategy;
|
||||||
|
private String conformanceDate;
|
||||||
|
|
||||||
|
public RestulfulServerConfiguration() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public RestulfulServerConfiguration(RestfulServer theRestfulServer) {
|
||||||
|
this.resourceBindings = new LinkedList<ResourceBinding>(theRestfulServer.getResourceBindings());
|
||||||
|
this.serverBindings = theRestfulServer.getServerBindings();
|
||||||
|
this.implementationDescription = theRestfulServer.getImplementationDescription();
|
||||||
|
this.serverVersion = theRestfulServer.getServerVersion();
|
||||||
|
this.serverName = theRestfulServer.getServerName();
|
||||||
|
this.fhirContext = theRestfulServer.getFhirContext();
|
||||||
|
this.serverAddressStrategy= theRestfulServer.getServerAddressStrategy();
|
||||||
|
this.servletContext = theRestfulServer.getServletContext();
|
||||||
|
if (servletContext != null) {
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
inputStream = getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
|
||||||
|
if (inputStream != null) {
|
||||||
|
Manifest manifest = new Manifest(inputStream);
|
||||||
|
this.conformanceDate = manifest.getMainAttributes().getValue("Build-Time");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (inputStream != null) {
|
||||||
|
IOUtils.closeQuietly(inputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the resourceBindings
|
||||||
|
* @return the resourceBindings
|
||||||
|
*/
|
||||||
|
public List<ResourceBinding> getResourceBindings() {
|
||||||
|
return resourceBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the resourceBindings
|
||||||
|
* @param resourceBindings the resourceBindings to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setResourceBindings(List<ResourceBinding> resourceBindings) {
|
||||||
|
this.resourceBindings = resourceBindings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serverBindings
|
||||||
|
* @return the serverBindings
|
||||||
|
*/
|
||||||
|
public List<BaseMethodBinding<?>> getServerBindings() {
|
||||||
|
return serverBindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the serverBindings
|
||||||
|
* @param serverBindings the serverBindings to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setServerBindings(List<BaseMethodBinding<?>> serverBindings) {
|
||||||
|
this.serverBindings = serverBindings;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the implementationDescription
|
||||||
|
* @return the implementationDescription
|
||||||
|
*/
|
||||||
|
public String getImplementationDescription() {
|
||||||
|
return implementationDescription;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the implementationDescription
|
||||||
|
* @param implementationDescription the implementationDescription to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setImplementationDescription(String implementationDescription) {
|
||||||
|
this.implementationDescription = implementationDescription;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serverVersion
|
||||||
|
* @return the serverVersion
|
||||||
|
*/
|
||||||
|
public String getServerVersion() {
|
||||||
|
return serverVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the serverVersion
|
||||||
|
* @param serverVersion the serverVersion to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setServerVersion(String serverVersion) {
|
||||||
|
this.serverVersion = serverVersion;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serverName
|
||||||
|
* @return the serverName
|
||||||
|
*/
|
||||||
|
public String getServerName() {
|
||||||
|
return serverName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the serverName
|
||||||
|
* @param serverName the serverName to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setServerName(String serverName) {
|
||||||
|
this.serverName = serverName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the servletContext
|
||||||
|
* @return the servletContext
|
||||||
|
*/
|
||||||
|
public ServletContext getServletContext() {
|
||||||
|
return servletContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the servletContext
|
||||||
|
* @param servletContext the servletContext to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setServletContext(ServletContext servletContext) {
|
||||||
|
this.servletContext = servletContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain providers should generally use this context if one is needed, as opposed to
|
||||||
|
* creating their own.
|
||||||
|
*/
|
||||||
|
public FhirContext getFhirContext() {
|
||||||
|
return this.fhirContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the fhirContext
|
||||||
|
* @param fhirContext the fhirContext to set
|
||||||
|
*/
|
||||||
|
public RestulfulServerConfiguration setFhirContext(FhirContext fhirContext) {
|
||||||
|
this.fhirContext = fhirContext;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the serverAddressStrategy
|
||||||
|
* @return the serverAddressStrategy
|
||||||
|
*/
|
||||||
|
public IServerAddressStrategy getServerAddressStrategy() {
|
||||||
|
return serverAddressStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the serverAddressStrategy
|
||||||
|
* @param serverAddressStrategy the serverAddressStrategy to set
|
||||||
|
*/
|
||||||
|
public void setServerAddressStrategy(IServerAddressStrategy serverAddressStrategy) {
|
||||||
|
this.serverAddressStrategy = serverAddressStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the conformanceDate
|
||||||
|
* @return the conformanceDate
|
||||||
|
*/
|
||||||
|
public String getConformanceDate() {
|
||||||
|
return conformanceDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the conformanceDate
|
||||||
|
* @param conformanceDate the conformanceDate to set
|
||||||
|
*/
|
||||||
|
public void setConformanceDate(String conformanceDate) {
|
||||||
|
this.conformanceDate = conformanceDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerBaseForRequest(HttpServletRequest theRequest) {
|
||||||
|
return getServerAddressStrategy().determineServerBase(getServletContext(), theRequest);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,274 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>maven.java.net</id>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
<releases>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</releases>
|
||||||
|
<url>https://maven.java.net/service/local/repositories/snapshots/content/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>HAPI FHIR JAX-RS Server</name>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- HAPI DEPENDENCIES -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-base</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
<exclusions>
|
||||||
|
<exclusion>
|
||||||
|
<artifactId>commons-logging</artifactId>
|
||||||
|
<groupId>commons-logging</groupId>
|
||||||
|
</exclusion>
|
||||||
|
</exclusions>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- UNKNOWN -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>jcl-over-slf4j</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.thymeleaf</groupId>
|
||||||
|
<artifactId>thymeleaf</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.phloc</groupId>
|
||||||
|
<artifactId>phloc-schematron</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.phloc</groupId>
|
||||||
|
<artifactId>phloc-commons</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- PREVIOUS TESTING
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-servlets</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-servlet</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-server</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-util</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
<!-- own api -->
|
||||||
|
<!--dependency>
|
||||||
|
<groupId>org.jboss.resteasy</groupId>
|
||||||
|
<artifactId>resteasy-jaxrs</artifactId>
|
||||||
|
<version>2.2.1.GA</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency-->
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.ws.rs</groupId>
|
||||||
|
<artifactId>jsr311-api</artifactId>
|
||||||
|
<version>1.1.1</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.ejb</groupId>
|
||||||
|
<artifactId>ejb-api</artifactId>
|
||||||
|
<version>3.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Jetty -->
|
||||||
|
<!-- http://stackoverflow.com/questions/10048004/integrating-jetty-with-jax-rs-jersey -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-server</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-util</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-webapp</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Jersey (JAX-RS) -->
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey.contribs</groupId>
|
||||||
|
<artifactId>jersey-spring</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.ws.rs</groupId>
|
||||||
|
<artifactId>jsr311-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.jersey</groupId>
|
||||||
|
<artifactId>jersey-test-framework</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.grizzly</groupId>
|
||||||
|
<artifactId>grizzly-servlet-webserver</artifactId>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<build>
|
||||||
|
<pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-site-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<skipDeploy>true</skipDeploy>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</pluginManagement>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-tinder-plugin</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>build_dstu1</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate-jparest-server</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<version>dstu</version>
|
||||||
|
<packageBase>ca.uhn.fhir.jpa.rp.dstu</packageBase>
|
||||||
|
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu1.xml</targetResourceSpringBeansFile>
|
||||||
|
<baseResourceNames/>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>build_dstu2</id>
|
||||||
|
<goals>
|
||||||
|
<goal>generate-jparest-server</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<version>dstu2</version>
|
||||||
|
<packageBase>ca.uhn.fhir.jpa.rp.dstu2</packageBase>
|
||||||
|
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu2.xml</targetResourceSpringBeansFile>
|
||||||
|
<baseResourceNames/>
|
||||||
|
<excludeResourceNames>
|
||||||
|
<excludeResourceName>OperationDefinition</excludeResourceName>
|
||||||
|
<excludeResourceName>OperationOutcome</excludeResourceName>
|
||||||
|
</excludeResourceNames>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</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>
|
||||||
|
</resources>
|
||||||
|
</build>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-jxr-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,152 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.OPTIONS;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||||
|
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||||
|
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
|
||||||
|
import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider;
|
||||||
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conformance Rest Service
|
||||||
|
* @author Peter Van Houte
|
||||||
|
*/
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public abstract class AbstractConformanceRestServer extends AbstractJaxRsRestServer implements IConformanceRestServer {
|
||||||
|
|
||||||
|
public static final String PATH = "/";
|
||||||
|
private static final org.slf4j.Logger ourLog = LoggerFactory.getLogger(AbstractConformanceRestServer.class);
|
||||||
|
|
||||||
|
private ResourceBinding myServerBinding = new ResourceBinding();
|
||||||
|
private ConcurrentHashMap<String, ResourceBinding> myResourceNameToBinding = new ConcurrentHashMap<String, ResourceBinding>();
|
||||||
|
private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration();
|
||||||
|
|
||||||
|
private Conformance myConformance;
|
||||||
|
|
||||||
|
protected AbstractConformanceRestServer(String implementationDescription, String serverName, String serverVersion) {
|
||||||
|
serverConfiguration.setFhirContext(getFhirContext());
|
||||||
|
serverConfiguration.setImplementationDescription(implementationDescription);
|
||||||
|
serverConfiguration.setServerName(serverName);
|
||||||
|
serverConfiguration.setServerVersion(serverVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUpPostConstruct()
|
||||||
|
throws Exception {
|
||||||
|
List<BaseMethodBinding<?>> serverBindings = new ArrayList<BaseMethodBinding<?>>();
|
||||||
|
for (ResourceBinding baseMethodBinding : myResourceNameToBinding.values()) {
|
||||||
|
serverBindings.addAll(baseMethodBinding.getMethodBindings());
|
||||||
|
}
|
||||||
|
serverConfiguration.setServerBindings(serverBindings);
|
||||||
|
serverConfiguration.setResourceBindings(new LinkedList<ResourceBinding>(myResourceNameToBinding.values()));
|
||||||
|
HardcodedServerAddressStrategy hardcodedServerAddressStrategy = new HardcodedServerAddressStrategy();
|
||||||
|
hardcodedServerAddressStrategy.setValue(getBaseUri());
|
||||||
|
serverConfiguration.setServerAddressStrategy(hardcodedServerAddressStrategy);
|
||||||
|
ServerConformanceProvider serverConformanceProvider = new ServerConformanceProvider(serverConfiguration);
|
||||||
|
serverConformanceProvider.initializeOperations();
|
||||||
|
myConformance = serverConformanceProvider.getServerConformance(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@OPTIONS
|
||||||
|
@Path("/metadata")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Response conformance(String string) {
|
||||||
|
String conformanceString = getParser().encodeResourceToString(myConformance);
|
||||||
|
ResponseBuilder entity = Response.status(Constants.STATUS_HTTP_200_OK).entity(conformanceString);
|
||||||
|
entity.header("Access-Control-Allow-Origin", "*");
|
||||||
|
return entity.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int findResourceMethods(Object theProvider, Class<?> clazz) throws ConfigurationException {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (Method m : ReflectionUtil.getDeclaredMethods(clazz)) {
|
||||||
|
BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, getFhirContext(), theProvider);
|
||||||
|
if (foundMethodBinding == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
// if (foundMethodBinding instanceof ConformanceMethodBinding) {
|
||||||
|
// myServerConformanceMethod = foundMethodBinding;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (!Modifier.isPublic(m.getModifiers())) {
|
||||||
|
throw new ConfigurationException("Method '" + m.getName() + "' is not public, FHIR RESTful methods must be public");
|
||||||
|
} else {
|
||||||
|
if (Modifier.isStatic(m.getModifiers())) {
|
||||||
|
throw new ConfigurationException("Method '" + m.getName() + "' is static, FHIR RESTful methods must not be static");
|
||||||
|
} else {
|
||||||
|
ourLog.debug("Scanning public method: {}#{}", theProvider.getClass(), m.getName());
|
||||||
|
|
||||||
|
String resourceName = foundMethodBinding.getResourceName();
|
||||||
|
ResourceBinding resourceBinding;
|
||||||
|
if (resourceName == null) {
|
||||||
|
resourceBinding = myServerBinding;
|
||||||
|
} else {
|
||||||
|
RuntimeResourceDefinition definition = getFhirContext().getResourceDefinition(resourceName);
|
||||||
|
if (myResourceNameToBinding.containsKey(definition.getName())) {
|
||||||
|
resourceBinding = myResourceNameToBinding.get(definition.getName());
|
||||||
|
} else {
|
||||||
|
resourceBinding = new ResourceBinding();
|
||||||
|
resourceBinding.setResourceName(resourceName);
|
||||||
|
myResourceNameToBinding.put(resourceName, resourceBinding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Class<?>> allowableParams = foundMethodBinding.getAllowableParamAnnotations();
|
||||||
|
if (allowableParams != null) {
|
||||||
|
for (Annotation[] nextParamAnnotations : m.getParameterAnnotations()) {
|
||||||
|
for (Annotation annotation : nextParamAnnotations) {
|
||||||
|
Package pack = annotation.annotationType().getPackage();
|
||||||
|
if (pack.equals(IdParam.class.getPackage())) {
|
||||||
|
if (!allowableParams.contains(annotation.annotationType())) {
|
||||||
|
throw new ConfigurationException("Method[" + m.toString() + "] is not allowed to have a parameter annotated with " + annotation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceBinding.addMethod(foundMethodBinding);
|
||||||
|
ourLog.debug(" * Method: {}#{} is a handler", theProvider.getClass(), m.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return Conformance.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Jax Rs Rest Server
|
||||||
|
* @author axmpm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||||
|
public abstract class AbstractJaxRsRestServer {
|
||||||
|
|
||||||
|
private static Logger ourLog = LoggerFactory.getLogger(AbstractJaxRsRestServer.class);
|
||||||
|
public static FhirContext CTX = FhirContext.forDstu2();
|
||||||
|
|
||||||
|
@Context
|
||||||
|
protected UriInfo info;
|
||||||
|
@Context
|
||||||
|
HttpHeaders headers;
|
||||||
|
|
||||||
|
private IParser jsonParser = getFhirContext().newJsonParser();
|
||||||
|
private IParser xmlParser = getFhirContext().newXmlParser();
|
||||||
|
private String baseUri;
|
||||||
|
|
||||||
|
public static FhirContext getFhirContext() {
|
||||||
|
return CTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* param and query methods
|
||||||
|
*/
|
||||||
|
protected HashMap<String, String[]> getQueryMap() {
|
||||||
|
MultivaluedMap<String, String> queryParameters = info.getQueryParameters();
|
||||||
|
HashMap<String, String[]> params = new HashMap<String, String[]>();
|
||||||
|
for (String key : queryParameters.keySet()) {
|
||||||
|
params.put(key, queryParameters.get(key).toArray(new String[] {}));
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getParam(String string) {
|
||||||
|
for (Entry<String, List<String>> entry : info.getQueryParameters().entrySet()) {
|
||||||
|
if (string.equalsIgnoreCase(entry.getKey())) {
|
||||||
|
return entry.getValue().iterator().next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer getIntParam(String string) {
|
||||||
|
String param = getParam(string);
|
||||||
|
return param == null ? 0 : Integer.valueOf(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getBaseUri() {
|
||||||
|
if(this.baseUri == null) {
|
||||||
|
this.baseUri = info.getBaseUri().toASCIIString();
|
||||||
|
}
|
||||||
|
ourLog.debug("BaseUri is equal to %s", baseUri);
|
||||||
|
return this.baseUri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PARSING METHODS
|
||||||
|
*/
|
||||||
|
public IParser getParser() {
|
||||||
|
IParser parser = MediaType.APPLICATION_XML.equals(getParserType()) ? xmlParser : jsonParser;
|
||||||
|
return parser.setPrettyPrint(getPrettyPrint());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getPrettyPrint() {
|
||||||
|
String printPretty = getParam("_pretty");
|
||||||
|
return printPretty == null || printPretty.trim().length() == 0 ? true : Boolean.valueOf(printPretty);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getParserType() {
|
||||||
|
if ((headers != null && headers.getMediaType() != null && headers.getMediaType().getSubtype() != null
|
||||||
|
&& headers.getMediaType().getSubtype().contains("xml")) || getDefaultResponseEncoding() == EncodingEnum.XML
|
||||||
|
|| "xml".equals(getParam("_format"))) {
|
||||||
|
return MediaType.APPLICATION_XML;
|
||||||
|
} else {
|
||||||
|
return MediaType.APPLICATION_JSON;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Response createResponse(IBaseResource resource) {
|
||||||
|
Bundle resultingBundle = new Bundle();
|
||||||
|
resultingBundle.addEntry().setResource((IResource) resource);
|
||||||
|
return ok(encodeResponse(resultingBundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response ok(String entity) {
|
||||||
|
return Response.status(Constants.STATUS_HTTP_200_OK).header("Content-Type", getParserType()).entity(entity).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String encodeResponse(Bundle resource) {
|
||||||
|
return resource == null ? "null" : getParser().encodeBundleToString(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DEFAULT VALUES
|
||||||
|
*/
|
||||||
|
public EncodingEnum getDefaultResponseEncoding() {
|
||||||
|
return EncodingEnum.JSON;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,230 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.interceptor.Interceptors;
|
||||||
|
import javax.ws.rs.DELETE;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.PUT;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.PathParam;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.ExceptionInterceptor;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.util.MethodBindings;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.util.RestfulServerDefaults;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
|
import ca.uhn.fhir.model.api.BundleEntry;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.method.CreateMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.OperationMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
|
||||||
|
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
|
||||||
|
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fhir Physician Rest Service
|
||||||
|
* @author axmpm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({ "unused"})
|
||||||
|
@Produces({MediaType.APPLICATION_JSON,MediaType.APPLICATION_XML})
|
||||||
|
public abstract class AbstractResourceRestServer<R extends IResource> extends AbstractJaxRsRestServer implements IResourceProvider {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(AbstractResourceRestServer.class);
|
||||||
|
|
||||||
|
private ResourceBinding myServerBinding = new ResourceBinding();
|
||||||
|
private IRestfulServerDefaults serverDefaults = new RestfulServerDefaults();
|
||||||
|
private MethodBindings bindings = new MethodBindings();
|
||||||
|
|
||||||
|
public AbstractResourceRestServer(Class<?> subclass) {
|
||||||
|
bindings.findMethods(this, subclass, getFhirContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
Response search() throws Exception {
|
||||||
|
return execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response customOperation(final IBaseResource resource, RequestTypeEnum requestType)
|
||||||
|
throws Exception, IllegalAccessException, InvocationTargetException {
|
||||||
|
OperationMethodBinding method = bindings.getBinding(OperationMethodBinding.class);
|
||||||
|
final RequestDetails theRequest = createRequestDetails(resource, requestType);
|
||||||
|
final Object[] paramsServer = bindings.createParams(resource, method, theRequest);
|
||||||
|
Parameters result = (Parameters) method.getMethod().invoke(this, paramsServer);
|
||||||
|
return ok(getParser().encodeResourceToString(result));
|
||||||
|
}
|
||||||
|
|
||||||
|
Response create(final Map<String, String[]> params, R resource) throws Exception {
|
||||||
|
CreateMethodBinding method = bindings.getBinding(CreateMethodBinding.class);
|
||||||
|
final RequestDetails theRequest = createRequestDetails(resource, null);
|
||||||
|
final Object[] paramsServer = bindings.createParams(resource, method, theRequest);
|
||||||
|
MethodOutcome result = (MethodOutcome) method.getMethod().invoke(this, paramsServer);
|
||||||
|
return createResponse(result.getResource());
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response create(final String resourceString)
|
||||||
|
throws Exception {
|
||||||
|
return create(getQueryMap(), parseResource(resourceString));
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
@Path("/_search")
|
||||||
|
public Response searchWithPost() throws Exception {
|
||||||
|
return search();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response find(@PathParam("id") final String id) {
|
||||||
|
final R resource = find(new IdDt(id));
|
||||||
|
return createSingleResponse(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PUT
|
||||||
|
@Path("/{id}")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response update(@PathParam("id") final String id, final String resourceString)
|
||||||
|
throws Exception {
|
||||||
|
final R resource = parseResource(resourceString);
|
||||||
|
// final MethodOutcome update = update(new IdDt(resource.getId()), practitioner);
|
||||||
|
// return createResponse(update.getResource());
|
||||||
|
return createResponse(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@DELETE
|
||||||
|
@Path("/{id}")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response delete(@PathParam("id") final String id)
|
||||||
|
throws Exception {
|
||||||
|
// final MethodOutcome delete = delete(new IdDt(id));
|
||||||
|
// return createResponse(delete.getResource());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}/_history/{version}")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response findHistory(@PathParam("id") final String id, @PathParam("version") final String version) {
|
||||||
|
final IdDt dt = new IdDt(getBaseUri(), getResourceType().getSimpleName(), id, version);
|
||||||
|
final R resource = findHistory(dt);
|
||||||
|
return createSingleResponse(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}/{compartment}")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response findCompartment(@PathParam("id") final String id, @PathParam("compartment") final String compartment) {
|
||||||
|
final IdDt dt = new IdDt(getBaseUri(), getResourceType().getSimpleName(), id);
|
||||||
|
final R resource = find(new IdDt(id));
|
||||||
|
return createResponse(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PARSING METHODS
|
||||||
|
*/
|
||||||
|
private Response createSingleResponse(final R resource) {
|
||||||
|
return ok(getParser().encodeResourceToString(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
Response createResponse(final IBaseResource resource) {
|
||||||
|
final Bundle resultingBundle = new Bundle();
|
||||||
|
resultingBundle.addEntry().setResource((IResource) resource);
|
||||||
|
return ok(encodeToString(resultingBundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
Response createResponse(final List<R> resources) {
|
||||||
|
final Bundle resultingBundle = new Bundle();
|
||||||
|
for (final R resource : resources) {
|
||||||
|
addBundleEntry(resultingBundle, resource);
|
||||||
|
}
|
||||||
|
return ok(encodeToString(resultingBundle));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Response ok(String entity) {
|
||||||
|
return Response.status(Constants.STATUS_HTTP_200_OK).header("Content-Type", getParserType()).entity(entity).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String encodeToString(final Bundle resource) {
|
||||||
|
return resource != null ? getParser().encodeBundleToString(resource) : "null";
|
||||||
|
}
|
||||||
|
|
||||||
|
private R parseResource(final String resource) {
|
||||||
|
return getParser().parseResource(getResourceType(), resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
private void addBundleEntry(final Bundle resultingBundle, final R resource) {
|
||||||
|
final BundleEntry entry = resultingBundle.addEntry();
|
||||||
|
entry.setResource(resource);
|
||||||
|
if (resource != null && resource.getId() != null) {
|
||||||
|
entry.setId(resource.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private RequestDetails createRequestDetails(final IBaseResource resource, RequestTypeEnum requestType) {
|
||||||
|
final RequestDetails theRequest = new RequestDetails() {
|
||||||
|
// @Override
|
||||||
|
// public String getHeader(String headerIfNoneExist) {
|
||||||
|
// List<String> requestHeader = headers.getRequestHeader(headerIfNoneExist);
|
||||||
|
// return (requestHeader == null || requestHeader.size() == 0) ? null : requestHeader.get(0);
|
||||||
|
// }
|
||||||
|
};
|
||||||
|
theRequest.setFhirServerBase(getBaseUri());
|
||||||
|
// theRequest.setServer(this);
|
||||||
|
theRequest.setParameters(getQueryMap());
|
||||||
|
// theRequest.setRequestContent(resource);
|
||||||
|
theRequest.setRequestType(requestType);
|
||||||
|
return theRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response execute() {
|
||||||
|
SearchMethodBinding method = bindings.getBinding(SearchMethodBinding.class);
|
||||||
|
final RequestDetails theRequest = createRequestDetails(null, null);
|
||||||
|
final Object[] paramsServer = bindings.createParams(null, method, theRequest);
|
||||||
|
Object result = null; //method.invokeServer(null, paramsServer);
|
||||||
|
final IBundleProvider bundle = (IBundleProvider) result;
|
||||||
|
IVersionSpecificBundleFactory bundleFactory = getFhirContext().newBundleFactory();
|
||||||
|
// bundleFactory.initializeBundleFromBundleProvider(this, bundle, EncodingEnum.JSON, info.getAbsolutePath().toASCIIString(),
|
||||||
|
// info.getAbsolutePath().toASCIIString(), getPrettyPrint(), getIntParam("_getpagesoffset"), getIntParam("_count"), null,
|
||||||
|
// BundleTypeEnum.SEARCHSET, Collections.emptySet());
|
||||||
|
IBaseResource resource = bundleFactory.getResourceBundle();
|
||||||
|
return ok(getParser().encodeResourceToString(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
public R find(final IdDt theId) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public R findHistory(final IdDt theId) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract Class<R> getResourceType();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
|
public interface IConformanceRestServer extends IResourceProvider {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server;
|
||||||
|
|
||||||
|
import javax.ejb.Local;
|
||||||
|
import javax.ejb.Stateless;
|
||||||
|
import javax.interceptor.Interceptors;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.ExceptionInterceptor;
|
||||||
|
import ca.uhn.fhir.model.api.Bundle;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Transaction;
|
||||||
|
import ca.uhn.fhir.rest.annotation.TransactionParam;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conformance Rest Service
|
||||||
|
* @author Peter Van Houte
|
||||||
|
*/
|
||||||
|
@Local
|
||||||
|
@Path(StaticJaxRsServer.PATH)
|
||||||
|
@Stateless
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public class StaticJaxRsServer {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = LoggerFactory.getLogger(StaticJaxRsServer.class);
|
||||||
|
static final String PATH = "/";
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
public Response transaction(final String resource) {
|
||||||
|
ourLog.debug("calling transaction method");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transaction
|
||||||
|
public Bundle transaction(@TransactionParam Bundle theResources) {
|
||||||
|
ourLog.debug("transaction implemented");
|
||||||
|
return theResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,169 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.interceptor;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import javax.interceptor.AroundInvoke;
|
||||||
|
import javax.interceptor.InvocationContext;
|
||||||
|
import javax.ws.rs.core.Context;
|
||||||
|
import javax.ws.rs.core.HttpHeaders;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
import javax.ws.rs.core.Response.ResponseBuilder;
|
||||||
|
import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsRestServer;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||||
|
|
||||||
|
public class ExceptionInterceptor {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = LoggerFactory.getLogger(ExceptionInterceptor.class);
|
||||||
|
private Class<?>[] myReturnStackTracesForExceptionTypes;
|
||||||
|
|
||||||
|
@Context
|
||||||
|
private UriInfo info;
|
||||||
|
@Context
|
||||||
|
private HttpHeaders headers;
|
||||||
|
|
||||||
|
FhirContext fhirContext = AbstractJaxRsRestServer.getFhirContext();
|
||||||
|
|
||||||
|
@AroundInvoke
|
||||||
|
public Object intercept(final InvocationContext ctx) throws Exception {
|
||||||
|
try {
|
||||||
|
if(!ourLog.isDebugEnabled() || ctx.getMethod().getName().contains("getResourceType")) {
|
||||||
|
return ctx.proceed();
|
||||||
|
} else {
|
||||||
|
ourLog.debug("METHOD_CALL : " + ctx.getMethod().getName() + " [ " + Arrays.asList(ctx.getParameters()) + "] ");
|
||||||
|
Object proceed = ctx.proceed();
|
||||||
|
ourLog.debug("RESULT : " + proceed.toString());
|
||||||
|
return proceed;
|
||||||
|
}
|
||||||
|
} catch(final Exception theException) {
|
||||||
|
return handleException(theException);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response handleException(final Throwable theException)
|
||||||
|
{
|
||||||
|
IBaseOperationOutcome oo = null;
|
||||||
|
int statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
if (theException instanceof BaseServerResponseException) {
|
||||||
|
oo = ((BaseServerResponseException) theException).getOperationOutcome();
|
||||||
|
statusCode = ((BaseServerResponseException) theException).getStatusCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate an OperationOutcome to return, unless the exception throw by the resource provider had one
|
||||||
|
*/
|
||||||
|
if (oo == null) {
|
||||||
|
try {
|
||||||
|
final RuntimeResourceDefinition ooDef = fhirContext.getResourceDefinition("OperationOutcome");
|
||||||
|
oo = (IBaseOperationOutcome) ooDef.getImplementingClass().newInstance();
|
||||||
|
|
||||||
|
if (theException instanceof InternalErrorException) {
|
||||||
|
ourLog.error("Failure during REST processing", theException);
|
||||||
|
populateDetails(fhirContext, theException, oo);
|
||||||
|
} else if (theException instanceof BaseServerResponseException) {
|
||||||
|
ourLog.warn("Failure during REST processing: {}", theException);
|
||||||
|
final BaseServerResponseException baseServerResponseException = (BaseServerResponseException) theException;
|
||||||
|
statusCode = baseServerResponseException.getStatusCode();
|
||||||
|
populateDetails(fhirContext, theException, oo);
|
||||||
|
if (baseServerResponseException.getAdditionalMessages() != null) {
|
||||||
|
for (final String next : baseServerResponseException.getAdditionalMessages()) {
|
||||||
|
OperationOutcomeUtil.addIssue(fhirContext, oo, "error", next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ourLog.error("Failure during REST processing: " + theException.toString(), theException);
|
||||||
|
populateDetails(fhirContext, theException, oo);
|
||||||
|
statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
} catch (final Exception e1) {
|
||||||
|
ourLog.error("Failed to instantiate OperationOutcome resource instance", e1);
|
||||||
|
final ResponseBuilder result = Response.status(Constants.STATUS_HTTP_500_INTERNAL_ERROR);
|
||||||
|
result.header(Constants.HEADER_CONTENT_TYPE, Constants.CT_TEXT_WITH_UTF8);
|
||||||
|
result.header(Constants.HEADER_CONTENT_ENCODING, Constants.CHARSET_NAME_UTF8);
|
||||||
|
result.entity(theException.getMessage());
|
||||||
|
return result.build();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ourLog.error("Unknown error during processing", theException);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add headers associated with the specific error code
|
||||||
|
if (theException instanceof BaseServerResponseException) {
|
||||||
|
final Map<String, String[]> additional = ((BaseServerResponseException) theException).getAssociatedHeaders();
|
||||||
|
if (additional != null) {
|
||||||
|
for (final Entry<String, String[]> next : additional.entrySet()) {
|
||||||
|
if (isNotBlank(next.getKey()) && next.getValue() != null) {
|
||||||
|
final String nextKey = next.getKey();
|
||||||
|
for (final String nextValue : next.getValue()) {
|
||||||
|
addHeader(nextKey, nextValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean requestIsBrowser = false; // RestfulServer.requestIsBrowser(theRequest);
|
||||||
|
final String fhirServerBase = ""; // theRequestDetails.getFhirServerBase();
|
||||||
|
|
||||||
|
// theResponse.setStatus(statusCode);
|
||||||
|
// theRequestDetails.getServer().addHeadersToResponse(theResponse);
|
||||||
|
// theResponse.setContentType("text/plain");
|
||||||
|
// theResponse.setCharacterEncoding("UTF-8");
|
||||||
|
// theResponse.getWriter().append(theException.getMessage());
|
||||||
|
// theResponse.getWriter().close();
|
||||||
|
|
||||||
|
final ResponseBuilder result = Response.status(statusCode);
|
||||||
|
//final String resName = ctx.getResourceDefinition(oo).getName();
|
||||||
|
result.header(Constants.HEADER_CONTENT_TYPE, Constants.CT_TEXT_WITH_UTF8);
|
||||||
|
result.entity(theException.getMessage());
|
||||||
|
return result.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addHeader(final String nextKey, final String nextValue) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateDetails(final FhirContext theCtx, final Throwable theException, final IBaseOperationOutcome theOo) {
|
||||||
|
if (myReturnStackTracesForExceptionTypes != null) {
|
||||||
|
for (final Class<?> next : myReturnStackTracesForExceptionTypes) {
|
||||||
|
if (next.isAssignableFrom(theException.getClass())) {
|
||||||
|
final String detailsValue = theException.getMessage() + "\n\n" + ExceptionUtils.getStackTrace(theException);
|
||||||
|
OperationOutcomeUtil.addIssue(theCtx, theOo, "error", detailsValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OperationOutcomeUtil.addIssue(theCtx, theOo, "error", theException.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If any server methods throw an exception which extends any of the given exception types, the exception stack trace
|
||||||
|
* will be returned to the user. This can be useful for helping to diagnose issues, but may not be desirable for
|
||||||
|
* production situations.
|
||||||
|
*
|
||||||
|
* @param theExceptionTypes
|
||||||
|
* The exception types for which to return the stack trace to the user.
|
||||||
|
* @return Returns an instance of this interceptor, to allow for easy method chaining.
|
||||||
|
*/
|
||||||
|
public ExceptionInterceptor setReturnStackTracesForExceptionTypes(final Class<?>... theExceptionTypes) {
|
||||||
|
myReturnStackTracesForExceptionTypes = theExceptionTypes;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.util;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
import java.util.zip.GZIPOutputStream;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
|
|
||||||
|
public class GZipUtil {
|
||||||
|
|
||||||
|
public static String decompress(byte[] theResource) {
|
||||||
|
GZIPInputStream is;
|
||||||
|
try {
|
||||||
|
is = new GZIPInputStream(new ByteArrayInputStream(theResource));
|
||||||
|
return IOUtils.toString(is, "UTF-8");
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new DataFormatException("Failed to decompress contents", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] compress(String theEncoded) {
|
||||||
|
try {
|
||||||
|
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||||
|
GZIPOutputStream gos = new GZIPOutputStream(os);
|
||||||
|
IOUtils.write(theEncoded, gos, "UTF-8");
|
||||||
|
gos.close();
|
||||||
|
os.close();
|
||||||
|
byte[] retVal = os.toByteArray();
|
||||||
|
return retVal;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new DataFormatException("Compress contents", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.util;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.AbstractResourceRestServer;
|
||||||
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.CreateMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.DeleteMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.IParameter;
|
||||||
|
import ca.uhn.fhir.rest.method.OperationMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.method.SearchMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.method.UpdateMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||||
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
public class MethodBindings {
|
||||||
|
|
||||||
|
/** BaseOutcomeReturningMethodBinding */
|
||||||
|
private ConcurrentHashMap<String, CreateMethodBinding> createMethods = new ConcurrentHashMap<String, CreateMethodBinding>();
|
||||||
|
private ConcurrentHashMap<String, UpdateMethodBinding> updateMethods = new ConcurrentHashMap<String, UpdateMethodBinding>();
|
||||||
|
private ConcurrentHashMap<String, DeleteMethodBinding> delete = new ConcurrentHashMap<String, DeleteMethodBinding>();
|
||||||
|
|
||||||
|
/** BaseResourceReturingMethodBinding */
|
||||||
|
private ConcurrentHashMap<String, SearchMethodBinding> searchMethods = new ConcurrentHashMap<String, SearchMethodBinding>();
|
||||||
|
private ConcurrentHashMap<String, OperationMethodBinding> operationMethods = new ConcurrentHashMap<String, OperationMethodBinding>();
|
||||||
|
|
||||||
|
public <T extends AbstractResourceRestServer<?>> void findMethods(T theProvider, Class<?> subclass, FhirContext fhirContext) {
|
||||||
|
for (final Method m : ReflectionUtil.getDeclaredMethods(subclass)) {
|
||||||
|
final BaseMethodBinding<?> foundMethodBinding = BaseMethodBinding.bindMethod(m, fhirContext, theProvider);
|
||||||
|
if(foundMethodBinding == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ConcurrentHashMap map = getMap(foundMethodBinding.getClass());
|
||||||
|
if (map.contains(theProvider.getResourceType().getName())) {
|
||||||
|
throw new IllegalArgumentException("Multiple Search Method Bindings Found : " + foundMethodBinding.getMethod() + " -- "
|
||||||
|
+ foundMethodBinding.getMethod());
|
||||||
|
} else {
|
||||||
|
map.put(theProvider.getResourceType().getName(), foundMethodBinding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> ConcurrentHashMap<String, T> getMap(Class<T> class1) {
|
||||||
|
if(class1.isAssignableFrom(CreateMethodBinding.class)) return (ConcurrentHashMap<String, T>) createMethods;
|
||||||
|
if(class1.isAssignableFrom(UpdateMethodBinding.class)) return (ConcurrentHashMap<String, T>) updateMethods;
|
||||||
|
if(class1.isAssignableFrom(DeleteMethodBinding.class)) return (ConcurrentHashMap<String, T>) delete;
|
||||||
|
if(class1.isAssignableFrom(SearchMethodBinding.class)) return (ConcurrentHashMap<String, T>) searchMethods;
|
||||||
|
if(class1.isAssignableFrom(OperationMethodBinding.class)) return (ConcurrentHashMap<String, T>) operationMethods;
|
||||||
|
return new ConcurrentHashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object[] createParams(IBaseResource resource, final BaseMethodBinding<?> method, final RequestDetails theRequest) {
|
||||||
|
final Object[] paramsServer = new Object[method.getParameters().size()];
|
||||||
|
for (int i = 0; i < method.getParameters().size(); i++) {
|
||||||
|
final IParameter param = method.getParameters().get(i);
|
||||||
|
if(param instanceof ResourceParameter) {
|
||||||
|
paramsServer[i] = resource;
|
||||||
|
} else {
|
||||||
|
paramsServer[i] = param.translateQueryParametersIntoServerArgument(theRequest, null, method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paramsServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getBinding(Class<T> clazz) {
|
||||||
|
ConcurrentHashMap map = getMap((Class<? extends BaseMethodBinding>) clazz);
|
||||||
|
if(map.values().size() == 0) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
return (T) map.values().iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.util;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.AddProfileTagEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.BundleInclusionRule;
|
||||||
|
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
|
||||||
|
|
||||||
|
public class RestfulServerDefaults implements IRestfulServerDefaults {
|
||||||
|
|
||||||
|
public boolean isUseBrowserFriendlyContentTypes() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ETagSupportEnum getETagSupport() {
|
||||||
|
return ETagSupportEnum.DISABLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AddProfileTagEnum getAddProfileTag() {
|
||||||
|
return AddProfileTagEnum.NEVER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDefaultPrettyPrint() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IPagingProvider getPagingProvider() {
|
||||||
|
//Integer count = getIntParam("_count");
|
||||||
|
Integer count = 0;
|
||||||
|
return count == 0 ? null : new FifoMemoryPagingProvider(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BundleInclusionRule getBundleInclusionRule() {
|
||||||
|
return BundleInclusionRule.BASED_ON_INCLUDES;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,287 @@
|
||||||
|
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertNotNull;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.model.api.BundleEntry;
|
||||||
|
import ca.uhn.fhir.model.dstu2.composite.HumanNameDt;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.DateDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||||
|
import ca.uhn.fhir.rest.method.SearchStyleEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
|
@Ignore
|
||||||
|
public class DemoTest {
|
||||||
|
|
||||||
|
private static final String serverBase = "http://localhost:8580/hapi-fhir-jaxrsserver-example/jaxrs-demo/";
|
||||||
|
private static IGenericClient client;
|
||||||
|
|
||||||
|
//START SNIPPET: client
|
||||||
|
@BeforeClass
|
||||||
|
public static void setUpOnce() {
|
||||||
|
final FhirContext ctx = FhirContext.forDstu2();
|
||||||
|
client = ctx.newRestfulGenericClient(serverBase);
|
||||||
|
client.setEncoding(EncodingEnum.JSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
//END SNIPPET: client
|
||||||
|
|
||||||
|
/** Search/Query - Type */
|
||||||
|
@Test
|
||||||
|
public void findUsingGenericClientBySearch() {
|
||||||
|
// Perform a search
|
||||||
|
final ca.uhn.fhir.model.api.Bundle results = client.search().forResource(Patient.class)
|
||||||
|
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")).execute();
|
||||||
|
System.out.println(results.getEntries().get(0));
|
||||||
|
assertEquals(results.getEntries().size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search - Multi-valued Parameters (ANY/OR) */
|
||||||
|
@Test
|
||||||
|
public void findUsingGenericClientBySearchWithMultiValues() {
|
||||||
|
final ca.uhn.fhir.model.api.Bundle response = client.search().forResource(Patient.class)
|
||||||
|
.where(Patient.ADDRESS.matches().values("Toronto")).and(Patient.ADDRESS.matches().values("Ontario"))
|
||||||
|
.and(Patient.ADDRESS.matches().values("Canada"))
|
||||||
|
.where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SHORTNAME", "TOYS")).execute();
|
||||||
|
System.out.println(response.getEntries().get(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search - Paging */
|
||||||
|
@Test
|
||||||
|
public void findWithPaging() {
|
||||||
|
// Perform a search
|
||||||
|
for(int i = 0 ; i < 10 ; i++) {
|
||||||
|
testCreatePatient();
|
||||||
|
}
|
||||||
|
final Bundle results = client.search().forResource(Patient.class).limitTo(8).returnBundle(Bundle.class).execute();
|
||||||
|
System.out.println(results.getEntry().size());
|
||||||
|
|
||||||
|
if (results.getLink(Bundle.LINK_NEXT) != null) {
|
||||||
|
|
||||||
|
// load next page
|
||||||
|
final Bundle nextPage = client.loadPage().next(results).execute();
|
||||||
|
System.out.println(nextPage.getEntry().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search using other query options */
|
||||||
|
public void testOther() {
|
||||||
|
//missing
|
||||||
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Test
|
||||||
|
public void testSearchPost() {
|
||||||
|
Bundle response = client.search()
|
||||||
|
.forResource("Patient")
|
||||||
|
.usingStyle(SearchStyleEnum.POST)
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
assertTrue(response.getEntry().size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search - Compartments */
|
||||||
|
@Test
|
||||||
|
public void testSearchCompartements() {
|
||||||
|
Bundle response = client.search()
|
||||||
|
.forResource(Patient.class)
|
||||||
|
.withIdAndCompartment("1", "condition")
|
||||||
|
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
|
||||||
|
.execute();
|
||||||
|
assertTrue(response.getEntry().size() > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Search - Subsetting (_summary and _elements) */
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void testSummary() {
|
||||||
|
Object response = client.search()
|
||||||
|
.forResource(Patient.class)
|
||||||
|
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatePatient() {
|
||||||
|
final Patient existing = new Patient();
|
||||||
|
existing.setId((IdDt) null);
|
||||||
|
existing.getNameFirstRep().addFamily("Created Patient 54");
|
||||||
|
client.setEncoding(EncodingEnum.XML);
|
||||||
|
final MethodOutcome results = client.create().resource(existing).execute();
|
||||||
|
System.out.println(results.getId());
|
||||||
|
final Bundle bundle = (Bundle) results.getResource();
|
||||||
|
final Patient patient = (Patient) bundle.getEntryFirstRep().getResource();
|
||||||
|
System.out.println(patient);
|
||||||
|
assertNotNull(client.read(patient.getId()));
|
||||||
|
client.setEncoding(EncodingEnum.JSON);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Conditional Creates */
|
||||||
|
@Test
|
||||||
|
public void testConditionalCreate() {
|
||||||
|
final Patient existing = new Patient();
|
||||||
|
existing.setId((IdDt) null);
|
||||||
|
existing.getNameFirstRep().addFamily("Created Patient 54");
|
||||||
|
client.setEncoding(EncodingEnum.XML);
|
||||||
|
final MethodOutcome results = client.create().resource(existing).execute();
|
||||||
|
System.out.println(results.getId());
|
||||||
|
final Bundle bundle = (Bundle) results.getResource();
|
||||||
|
final Patient patient = (Patient) bundle.getEntryFirstRep().getResource();
|
||||||
|
|
||||||
|
client.create()
|
||||||
|
.resource(patient)
|
||||||
|
.conditional()
|
||||||
|
.where(Patient.IDENTIFIER.exactly().identifier(patient.getIdentifierFirstRep()))
|
||||||
|
.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Find By Id */
|
||||||
|
@Test
|
||||||
|
public void findUsingGenericClientById() {
|
||||||
|
final Patient results = client.read(Patient.class, "1");
|
||||||
|
assertTrue(results.getIdentifier().toString().contains("THOR"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateById() {
|
||||||
|
final Patient existing = client.read(Patient.class, "1");
|
||||||
|
final List<HumanNameDt> name = existing.getName();
|
||||||
|
name.get(0).addSuffix("The Second");
|
||||||
|
existing.setName(name);
|
||||||
|
client.setEncoding(EncodingEnum.XML);
|
||||||
|
final MethodOutcome results = client.update("1", existing);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletePatient() {
|
||||||
|
final Patient existing = new Patient();
|
||||||
|
existing.getNameFirstRep().addFamily("Created Patient XYZ");
|
||||||
|
final MethodOutcome results = client.create().resource(existing).execute();
|
||||||
|
System.out.println(results.getId());
|
||||||
|
final Bundle bundle = (Bundle) results.getResource();
|
||||||
|
final Patient patient = (Patient) bundle.getEntryFirstRep().getResource();
|
||||||
|
client.delete(Patient.class, patient.getId());
|
||||||
|
try {
|
||||||
|
assertNotNull(client.read(patient.getId()));
|
||||||
|
}
|
||||||
|
catch (final ResourceNotFoundException e) {
|
||||||
|
assertEquals(e.getStatusCode(), Constants.STATUS_HTTP_404_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Transaction - Server */
|
||||||
|
@Test
|
||||||
|
public void testTransaction() {
|
||||||
|
ca.uhn.fhir.model.api.Bundle bundle = new ca.uhn.fhir.model.api.Bundle();
|
||||||
|
BundleEntry entry = bundle.addEntry();
|
||||||
|
final Patient existing = new Patient();
|
||||||
|
existing.getNameFirstRep().addFamily("Created with bundle");
|
||||||
|
entry.setResource(existing);
|
||||||
|
|
||||||
|
BoundCodeDt<BundleEntryTransactionMethodEnum> theTransactionOperation =
|
||||||
|
new BoundCodeDt(
|
||||||
|
BundleEntryTransactionMethodEnum.VALUESET_BINDER,
|
||||||
|
BundleEntryTransactionMethodEnum.POST);
|
||||||
|
entry.setTransactionMethod(theTransactionOperation);
|
||||||
|
ca.uhn.fhir.model.api.Bundle response = client.transaction().withBundle(bundle).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Conformance - Server */
|
||||||
|
@Test
|
||||||
|
public void testConformance() {
|
||||||
|
final Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
|
||||||
|
System.out.println(conf.getRest().get(0).getResource().get(0).getType());
|
||||||
|
System.out.println(conf.getRest().get(0).getResource().get(1).getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Extended Operations */
|
||||||
|
// Create a client to talk to the HeathIntersections server
|
||||||
|
@Test
|
||||||
|
public void testExtendedOperations() {
|
||||||
|
client.registerInterceptor(new LoggingInterceptor(true));
|
||||||
|
|
||||||
|
// Create the input parameters to pass to the server
|
||||||
|
Parameters inParams = new Parameters();
|
||||||
|
inParams.addParameter().setName("start").setValue(new DateDt("2001-01-01"));
|
||||||
|
inParams.addParameter().setName("end").setValue(new DateDt("2015-03-01"));
|
||||||
|
inParams.addParameter().setName("dummy").setValue(new StringDt("myAwesomeDummyValue"));
|
||||||
|
|
||||||
|
// Invoke $everything on "Patient/1"
|
||||||
|
Parameters outParams = client
|
||||||
|
.operation()
|
||||||
|
.onInstance(new IdDt("Patient", "1"))
|
||||||
|
.named("$last")
|
||||||
|
.withParameters(inParams)
|
||||||
|
//.useHttpGet() // Use HTTP GET instead of POST
|
||||||
|
.execute();
|
||||||
|
String resultValue = outParams.getParameter().get(0).getValue().toString();
|
||||||
|
System.out.println(resultValue);
|
||||||
|
assertEquals("expected but found : "+ resultValue, resultValue.contains("myAwesomeDummyValue"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExtendedOperationsUsingGet() {
|
||||||
|
client.registerInterceptor(new LoggingInterceptor(true));
|
||||||
|
|
||||||
|
// Create the input parameters to pass to the server
|
||||||
|
Parameters inParams = new Parameters();
|
||||||
|
inParams.addParameter().setName("start").setValue(new DateDt("2001-01-01"));
|
||||||
|
inParams.addParameter().setName("end").setValue(new DateDt("2015-03-01"));
|
||||||
|
inParams.addParameter().setName("dummy").setValue(new StringDt("myAwesomeDummyValue"));
|
||||||
|
|
||||||
|
// Invoke $everything on "Patient/1"
|
||||||
|
Parameters outParams = client
|
||||||
|
.operation()
|
||||||
|
.onInstance(new IdDt("Patient", "1"))
|
||||||
|
.named("$last")
|
||||||
|
.withParameters(inParams)
|
||||||
|
.useHttpGet() // Use HTTP GET instead of POST
|
||||||
|
.execute();
|
||||||
|
String resultValue = outParams.getParameter().get(0).getValue().toString();
|
||||||
|
System.out.println(resultValue);
|
||||||
|
assertEquals("expected but found : "+ resultValue, resultValue.contains("myAwesomeDummyValue"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindUnknownPatient() {
|
||||||
|
try {
|
||||||
|
final Patient existing = client.read(Patient.class, "999955541264");
|
||||||
|
}
|
||||||
|
catch (final ResourceNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
assertEquals(e.getStatusCode(), 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVRead() {
|
||||||
|
final Patient patient = client.vread(Patient.class, "1", "1");
|
||||||
|
System.out.println(patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<!-- Note: HAPI projects use the "hapi-fhir" POM as their base to provide easy management. You do not need to use this in your own projects, so the "parent" tag and it's contents below may be removed
|
||||||
|
if you are using this file as a basis for your own project. -->
|
||||||
|
<parent>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
<relativePath>../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>hapi-fhir-jaxrsserver-example</artifactId>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<name>HAPI FHIR JPA Server - Example</name>
|
||||||
|
|
||||||
|
<repositories>
|
||||||
|
<repository>
|
||||||
|
<id>oss-snapshots</id>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</snapshots>
|
||||||
|
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
|
||||||
|
</repository>
|
||||||
|
</repositories>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
|
||||||
|
<!-- This dependency includes the core HAPI-FHIR classes -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
|
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||||
|
<version>1.3-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
<build>
|
||||||
|
|
||||||
|
<!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver-example.war -->
|
||||||
|
<finalName>hapi-fhir-jaxrsserver-example</finalName>
|
||||||
|
<!-- This is to run the integration tests -->
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<redirectTestOutputToFile>true</redirectTestOutputToFile>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>integration-test</goal>
|
||||||
|
<goal>verify</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>unpack</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>unpack</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<artifactItems>
|
||||||
|
<artifactItem>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>${project.artifactId}</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<type>war</type>
|
||||||
|
<includes>*.war</includes>
|
||||||
|
</artifactItem>
|
||||||
|
</artifactItems>
|
||||||
|
<outputDirectory>C:\Agfa\ORBIS-AS\server\orbis-as-08.05.07.00.0009200-UK\standalone\deployments</outputDirectory>
|
||||||
|
<stripVersion>true</stripVersion>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,41 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.example;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.ejb.EJB;
|
||||||
|
import javax.ejb.Local;
|
||||||
|
import javax.ejb.Stateless;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conformance Rest Service
|
||||||
|
* @author Peter Van Houte
|
||||||
|
*/
|
||||||
|
@Local
|
||||||
|
@Path(ConformanceRestServer.PATH)
|
||||||
|
@Stateless
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public class ConformanceRestServer extends ca.uhn.fhir.jaxrs.server.AbstractConformanceRestServer {
|
||||||
|
|
||||||
|
private static final String SERVER_VERSION = "1.0.0";
|
||||||
|
private static final String SERVER_DESCRIPTION = "Jax-Rs Test Example Description";
|
||||||
|
private static final String SERVER_NAME = "Jax-Rs Test Example";
|
||||||
|
|
||||||
|
@EJB
|
||||||
|
private ConformanceRestServer conformanceRestServer;
|
||||||
|
@EJB
|
||||||
|
private IFhirPatientRestServer patientRestServer;
|
||||||
|
|
||||||
|
public ConformanceRestServer() {
|
||||||
|
super(SERVER_DESCRIPTION, SERVER_NAME, SERVER_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void createMethod()
|
||||||
|
throws Exception {
|
||||||
|
findResourceMethods(conformanceRestServer, ConformanceRestServer.class);
|
||||||
|
findResourceMethods(patientRestServer, FhirPatientRestServer.class);
|
||||||
|
super.setUpPostConstruct();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.example;
|
||||||
|
|
||||||
|
import javax.ws.rs.ApplicationPath;
|
||||||
|
import javax.ws.rs.core.Application;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fhir Patient Demo Application
|
||||||
|
* @author Peter Van Houte
|
||||||
|
*/
|
||||||
|
@ApplicationPath(value=FhirPatientDemoApplication.PATH)
|
||||||
|
public class FhirPatientDemoApplication extends Application {
|
||||||
|
public final static String PATH = "/jaxrs-demo";
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.example;
|
||||||
|
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import javax.ejb.Local;
|
||||||
|
import javax.ejb.Stateless;
|
||||||
|
import javax.interceptor.Interceptors;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.POST;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jaxrs.server.AbstractResourceRestServer;
|
||||||
|
import ca.uhn.fhir.jaxrs.server.interceptor.ExceptionInterceptor;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Create;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Delete;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Read;
|
||||||
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Update;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fhir Physician Rest Service
|
||||||
|
* @author axmpm
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Local(IFhirPatientRestServer.class)
|
||||||
|
@Path(FhirPatientRestServer.PATH)
|
||||||
|
@Stateless
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public class FhirPatientRestServer extends AbstractResourceRestServer<Patient> implements IFhirPatientRestServer {
|
||||||
|
|
||||||
|
static final String PATH = "/Patient";
|
||||||
|
|
||||||
|
private static Long counter = 1L;
|
||||||
|
private static final ConcurrentHashMap<String, List<Patient>> patients = new ConcurrentHashMap<String, List<Patient>>();
|
||||||
|
|
||||||
|
protected FhirPatientRestServer() throws Exception {
|
||||||
|
super(FhirPatientRestServer.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
patients.put(""+counter, createPatient("Agfa"));
|
||||||
|
patients.put(""+(counter), createPatient("Healthcare"));
|
||||||
|
for(int i = 0 ; i<20 ; i++) {
|
||||||
|
patients.put(""+(counter), createPatient("Random Patient " + counter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Patient> createPatient(final String name) {
|
||||||
|
final Patient patient = new Patient();
|
||||||
|
patient.getNameFirstRep().addFamily(name);
|
||||||
|
return createPatient(patient);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Patient> createPatient(final Patient patient) {
|
||||||
|
patient.setId(createId(counter, 1L));
|
||||||
|
final LinkedList<Patient> list = new LinkedList<Patient>();
|
||||||
|
list.add(patient);
|
||||||
|
counter++;
|
||||||
|
return list ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IdDt createId(final Long id, final Long theVersionId) {
|
||||||
|
return new IdDt("Patient", "" + id, "" + theVersionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search
|
||||||
|
@Override
|
||||||
|
public List<Patient> search(@RequiredParam(name = Patient.SP_NAME) final StringParam name) {
|
||||||
|
final List<Patient> result = new LinkedList<Patient>();
|
||||||
|
for (final List<Patient> patientIterator : patients.values()) {
|
||||||
|
Patient single = null;
|
||||||
|
for (Patient patient : patientIterator) {
|
||||||
|
if (name == null || patient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals(name.getValueNotNull())) {
|
||||||
|
single = patient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (single != null) {
|
||||||
|
result.add(single);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Update
|
||||||
|
@Override
|
||||||
|
public MethodOutcome update(@IdParam final IdDt theId, @ResourceParam final Patient patient)
|
||||||
|
throws Exception {
|
||||||
|
final String idPart = theId.getIdPart();
|
||||||
|
if(patients.containsKey(idPart)) {
|
||||||
|
final List<Patient> patientList = patients.get(idPart);
|
||||||
|
final Patient lastPatient = getLast(patientList);
|
||||||
|
patient.setId(createId(theId.getIdPartAsLong(), lastPatient.getId().getVersionIdPartAsLong()+1));
|
||||||
|
patientList.add(patient);
|
||||||
|
final MethodOutcome result = new MethodOutcome().setCreated(false);
|
||||||
|
result.setResource(patient);
|
||||||
|
result.setId(patient.getId());
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
throw new ResourceNotFoundException(theId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Read
|
||||||
|
public Patient find(@IdParam final IdDt theId) {
|
||||||
|
if(patients.containsKey(theId.getIdPart())) {
|
||||||
|
return getLast(patients.get(theId.getIdPart()));
|
||||||
|
} else {
|
||||||
|
throw new ResourceNotFoundException(theId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private Patient getLast(final List<Patient> list) {
|
||||||
|
return list.get(list.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Read(version = false)
|
||||||
|
public Patient findHistory(@IdParam final IdDt theId) {
|
||||||
|
if (patients.containsKey(theId.getIdPart())) {
|
||||||
|
final List<Patient> list = patients.get(theId.getIdPart());
|
||||||
|
for (final Patient patient : list) {
|
||||||
|
if (patient.getId().getVersionIdPartAsLong().equals(theId.getVersionIdPartAsLong())) {
|
||||||
|
return patient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ResourceNotFoundException(theId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Create
|
||||||
|
@Override
|
||||||
|
public MethodOutcome create(@ResourceParam final Patient patient, @ConditionalUrlParam String theConditional)
|
||||||
|
throws Exception {
|
||||||
|
patients.put(""+counter, createPatient(patient));
|
||||||
|
final MethodOutcome result = new MethodOutcome().setCreated(true);
|
||||||
|
result.setResource(patient);
|
||||||
|
result.setId(patient.getId());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete
|
||||||
|
@Override
|
||||||
|
public MethodOutcome delete(@IdParam final IdDt theId) {
|
||||||
|
final Patient deletedPatient = find(theId);
|
||||||
|
patients.remove(deletedPatient.getId().getIdPart());
|
||||||
|
final MethodOutcome result = new MethodOutcome().setCreated(true);
|
||||||
|
result.setResource(deletedPatient);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/{id}/$last")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
@Override
|
||||||
|
public Response operationLastGet(final String resource)
|
||||||
|
throws Exception {
|
||||||
|
return customOperation(null, RequestTypeEnum.GET);
|
||||||
|
}
|
||||||
|
|
||||||
|
@POST
|
||||||
|
@Path("/{id}/$last")
|
||||||
|
@Interceptors(ExceptionInterceptor.class)
|
||||||
|
@Override
|
||||||
|
public Response operationLast(final String resource)
|
||||||
|
throws Exception {
|
||||||
|
return customOperation(getParser().parseResource(resource), RequestTypeEnum.POST);
|
||||||
|
}
|
||||||
|
|
||||||
|
// @ca.uhn.fhir.rest.annotation.Validate
|
||||||
|
// public MethodOutcome validate(
|
||||||
|
// @ResourceParam T theResource,
|
||||||
|
// @ResourceParam String theRawResource,
|
||||||
|
// @ResourceParam EncodingEnum theEncoding,
|
||||||
|
// @ca.uhn.fhir.rest.annotation.Validate.Mode ValidationModeEnum theMode,
|
||||||
|
// @ca.uhn.fhir.rest.annotation.Validate.Profile String theProfile) {
|
||||||
|
// return validate(theResource, null, theRawResource, theEncoding, theMode, theProfile);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@Operation(name="last", idempotent=true, returnParameters= {
|
||||||
|
@OperationParam(name="return", type=StringDt.class)
|
||||||
|
})
|
||||||
|
@Override
|
||||||
|
public Parameters last(@OperationParam(name = "dummy") StringDt dummyInput) {
|
||||||
|
System.out.println("inputparameter");
|
||||||
|
Parameters parameters = new Parameters();
|
||||||
|
Patient patient = find(new IdDt(counter.intValue()-1));
|
||||||
|
parameters
|
||||||
|
.addParameter()
|
||||||
|
.setName("return")
|
||||||
|
.setResource(patient)
|
||||||
|
.setValue(new StringDt((counter-1)+"" + "inputVariable [ " + dummyInput.getValue()+ "]"));
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Patient> getResourceType() {
|
||||||
|
return Patient.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package ca.uhn.fhir.jaxrs.server.example;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||||
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
|
||||||
|
public interface IFhirPatientRestServer extends IResourceProvider {
|
||||||
|
|
||||||
|
List<Patient> search(StringParam name);
|
||||||
|
|
||||||
|
MethodOutcome update(IdDt theId, Patient patient)
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
|
Patient find(IdDt theId);
|
||||||
|
|
||||||
|
Patient findHistory(IdDt theId);
|
||||||
|
|
||||||
|
MethodOutcome create(Patient patient, String theConditional)
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
|
MethodOutcome delete(IdDt theId);
|
||||||
|
|
||||||
|
Response operationLastGet(String resource)
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
|
Response operationLast(String resource)
|
||||||
|
throws Exception;
|
||||||
|
|
||||||
|
Parameters last(StringDt dummyInput);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||||
|
|
||||||
|
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||||
|
<!--
|
||||||
|
<filter>
|
||||||
|
<filter-name>CORS Filter</filter-name>
|
||||||
|
<filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
|
||||||
|
<param-name>cors.allowed.origins</param-name>
|
||||||
|
<param-value>*</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
|
||||||
|
<param-name>cors.allowed.methods</param-name>
|
||||||
|
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list of allowed headers when making a non simple CORS request.</description>
|
||||||
|
<param-name>cors.allowed.headers</param-name>
|
||||||
|
<param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
|
||||||
|
<param-name>cors.exposed.headers</param-name>
|
||||||
|
<param-value>Location,Content-Location</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A flag that suggests if CORS is supported with cookies</description>
|
||||||
|
<param-name>cors.support.credentials</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>A flag to control logging</description>
|
||||||
|
<param-name>cors.logging.enabled</param-name>
|
||||||
|
<param-value>true</param-value>
|
||||||
|
</init-param>
|
||||||
|
<init-param>
|
||||||
|
<description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
|
||||||
|
<param-name>cors.preflight.maxage</param-name>
|
||||||
|
<param-value>300</param-value>
|
||||||
|
</init-param>
|
||||||
|
</filter>
|
||||||
|
<filter-mapping>
|
||||||
|
<filter-name>CORS Filter</filter-name>
|
||||||
|
<url-pattern>/*</url-pattern>
|
||||||
|
</filter-mapping>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</web-app>
|
|
@ -22,13 +22,17 @@ package ca.uhn.fhir.rest.server.provider;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.text.DateFormat;
|
import java.util.ArrayList;
|
||||||
import java.text.ParseException;
|
import java.util.Collections;
|
||||||
import java.text.SimpleDateFormat;
|
import java.util.Comparator;
|
||||||
import java.util.*;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
@ -49,6 +53,7 @@ import ca.uhn.fhir.model.primitive.CodeDt;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.StringDt;
|
import ca.uhn.fhir.model.primitive.StringDt;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.annotation.Metadata;
|
import ca.uhn.fhir.rest.annotation.Metadata;
|
||||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||||
import ca.uhn.fhir.rest.method.DynamicSearchMethodBinding;
|
import ca.uhn.fhir.rest.method.DynamicSearchMethodBinding;
|
||||||
|
@ -59,10 +64,9 @@ import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
|
||||||
import ca.uhn.fhir.util.ExtensionConstants;
|
import ca.uhn.fhir.util.ExtensionConstants;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
||||||
*
|
*
|
||||||
|
@ -78,10 +82,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
private boolean myCache = true;
|
private boolean myCache = true;
|
||||||
private volatile Conformance myConformance;
|
private volatile Conformance myConformance;
|
||||||
private String myPublisher = "Not provided";
|
private String myPublisher = "Not provided";
|
||||||
private RestfulServer myRestfulServer;
|
private RestulfulServerConfiguration myRestfulServer;
|
||||||
|
|
||||||
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
||||||
myRestfulServer = theRestfulServer;
|
myRestfulServer = new RestulfulServerConfiguration(theRestfulServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -95,7 +99,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRestfulServer (RestfulServer theRestfulServer) {
|
public void setRestfulServer (RestfulServer theRestfulServer) {
|
||||||
myRestfulServer = theRestfulServer;
|
myRestfulServer = new RestulfulServerConfiguration(theRestfulServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -21,15 +21,21 @@ package ca.uhn.fhir.rest.server.provider.dstu2;
|
||||||
*/
|
*/
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.ArrayList;
|
||||||
import java.io.InputStream;
|
import java.util.Collections;
|
||||||
import java.util.*;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.jar.Manifest;
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
@ -53,6 +59,7 @@ import ca.uhn.fhir.model.dstu2.valueset.TypeRestfulInteractionEnum;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.UnknownContentCodeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.UnknownContentCodeEnum;
|
||||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Initialize;
|
import ca.uhn.fhir.rest.annotation.Initialize;
|
||||||
import ca.uhn.fhir.rest.annotation.Metadata;
|
import ca.uhn.fhir.rest.annotation.Metadata;
|
||||||
|
@ -69,6 +76,7 @@ import ca.uhn.fhir.rest.server.Constants;
|
||||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||||
import ca.uhn.fhir.rest.server.ResourceBinding;
|
import ca.uhn.fhir.rest.server.ResourceBinding;
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
|
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,10 +94,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
|
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
|
||||||
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
|
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
|
||||||
private String myPublisher = "Not provided";
|
private String myPublisher = "Not provided";
|
||||||
private RestfulServer myRestfulServer;
|
private RestulfulServerConfiguration myServerConfiguration;
|
||||||
|
|
||||||
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
public ServerConformanceProvider(RestfulServer theRestfulServer) {
|
||||||
myRestfulServer = theRestfulServer;
|
this.myServerConfiguration = new RestulfulServerConfiguration(theRestfulServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) {
|
||||||
|
this.myServerConfiguration = theServerConfiguration;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -103,7 +115,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setRestfulServer (RestfulServer theRestfulServer) {
|
public void setRestfulServer (RestfulServer theRestfulServer) {
|
||||||
myRestfulServer = theRestfulServer;
|
myServerConfiguration = new RestulfulServerConfiguration(theRestfulServer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkBindingForSystemOps(Rest rest, Set<SystemRestfulInteractionEnum> systemOps, BaseMethodBinding<?> nextMethodBinding) {
|
private void checkBindingForSystemOps(Rest rest, Set<SystemRestfulInteractionEnum> systemOps, BaseMethodBinding<?> nextMethodBinding) {
|
||||||
|
@ -124,7 +136,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
|
|
||||||
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
|
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
|
||||||
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
|
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
|
||||||
for (ResourceBinding next : myRestfulServer.getResourceBindings()) {
|
for (ResourceBinding next : myServerConfiguration.getResourceBindings()) {
|
||||||
String resourceName = next.getResourceName();
|
String resourceName = next.getResourceName();
|
||||||
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
|
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
|
||||||
if (resourceToMethods.containsKey(resourceName) == false) {
|
if (resourceToMethods.containsKey(resourceName) == false) {
|
||||||
|
@ -133,7 +145,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
resourceToMethods.get(resourceName).add(nextMethodBinding);
|
resourceToMethods.get(resourceName).add(nextMethodBinding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (BaseMethodBinding<?> nextMethodBinding : myRestfulServer.getServerBindings()) {
|
for (BaseMethodBinding<?> nextMethodBinding : myServerConfiguration.getServerBindings()) {
|
||||||
String resourceName = "";
|
String resourceName = "";
|
||||||
if (resourceToMethods.containsKey(resourceName) == false) {
|
if (resourceToMethods.containsKey(resourceName) == false) {
|
||||||
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
|
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
|
||||||
|
@ -170,10 +182,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
retVal.setAcceptUnknown(UnknownContentCodeEnum.UNKNOWN_EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
|
retVal.setAcceptUnknown(UnknownContentCodeEnum.UNKNOWN_EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
|
||||||
// needs to be modified to actually allow it
|
// needs to be modified to actually allow it
|
||||||
|
|
||||||
retVal.getImplementation().setDescription(myRestfulServer.getImplementationDescription());
|
retVal.getImplementation().setDescription(myServerConfiguration.getImplementationDescription());
|
||||||
retVal.setKind(ConformanceStatementKindEnum.INSTANCE);
|
retVal.setKind(ConformanceStatementKindEnum.INSTANCE);
|
||||||
retVal.getSoftware().setName(myRestfulServer.getServerName());
|
retVal.getSoftware().setName(myServerConfiguration.getServerName());
|
||||||
retVal.getSoftware().setVersion(myRestfulServer.getServerVersion());
|
retVal.getSoftware().setVersion(myServerConfiguration.getServerVersion());
|
||||||
retVal.addFormat(Constants.CT_FHIR_XML);
|
retVal.addFormat(Constants.CT_FHIR_XML);
|
||||||
retVal.addFormat(Constants.CT_FHIR_JSON);
|
retVal.addFormat(Constants.CT_FHIR_JSON);
|
||||||
|
|
||||||
|
@ -190,9 +202,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
Set<TypeRestfulInteractionEnum> resourceOps = new HashSet<TypeRestfulInteractionEnum>();
|
Set<TypeRestfulInteractionEnum> resourceOps = new HashSet<TypeRestfulInteractionEnum>();
|
||||||
RestResource resource = rest.addResource();
|
RestResource resource = rest.addResource();
|
||||||
String resourceName = nextEntry.getKey();
|
String resourceName = nextEntry.getKey();
|
||||||
RuntimeResourceDefinition def = myRestfulServer.getFhirContext().getResourceDefinition(resourceName);
|
RuntimeResourceDefinition def = myServerConfiguration.getFhirContext().getResourceDefinition(resourceName);
|
||||||
resource.getTypeElement().setValue(def.getName());
|
resource.getTypeElement().setValue(def.getName());
|
||||||
resource.getProfile().setReference(new IdDt(def.getResourceProfile(myRestfulServer.getServerBaseForRequest(theRequest))));
|
resource.getProfile().setReference(new IdDt(def.getResourceProfile(myServerConfiguration.getServerBaseForRequest(theRequest))));
|
||||||
|
|
||||||
TreeSet<String> includes = new TreeSet<String>();
|
TreeSet<String> includes = new TreeSet<String>();
|
||||||
|
|
||||||
|
@ -297,7 +309,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
}
|
}
|
||||||
|
|
||||||
private DateTimeDt conformanceDate() {
|
private DateTimeDt conformanceDate() {
|
||||||
String buildDate = getBuildDateFromManifest();
|
String buildDate = myServerConfiguration.getConformanceDate();
|
||||||
if (buildDate != null) {
|
if (buildDate != null) {
|
||||||
try {
|
try {
|
||||||
return new DateTimeDt(buildDate);
|
return new DateTimeDt(buildDate);
|
||||||
|
@ -308,21 +320,6 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
return DateTimeDt.withCurrentTime();
|
return DateTimeDt.withCurrentTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getBuildDateFromManifest() {
|
|
||||||
if (myRestfulServer != null && myRestfulServer.getServletContext() != null) {
|
|
||||||
InputStream inputStream = myRestfulServer.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
|
|
||||||
if (inputStream != null) {
|
|
||||||
try {
|
|
||||||
Manifest manifest = new Manifest(inputStream);
|
|
||||||
return manifest.getMainAttributes().getValue("Build-Time");
|
|
||||||
} catch (IOException e) {
|
|
||||||
// fall through
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
|
private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
|
||||||
includes.addAll(searchMethodBinding.getIncludes());
|
includes.addAll(searchMethodBinding.getIncludes());
|
||||||
|
|
||||||
|
@ -427,7 +424,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
|
||||||
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
|
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
|
||||||
}
|
}
|
||||||
for (Class<? extends IResource> nextTarget : nextParameter.getDeclaredTypes()) {
|
for (Class<? extends IResource> nextTarget : nextParameter.getDeclaredTypes()) {
|
||||||
RuntimeResourceDefinition targetDef = myRestfulServer.getFhirContext().getResourceDefinition(nextTarget);
|
RuntimeResourceDefinition targetDef = myServerConfiguration.getFhirContext().getResourceDefinition(nextTarget);
|
||||||
if (targetDef != null) {
|
if (targetDef != null) {
|
||||||
ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName());
|
ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName());
|
||||||
if (code != null) {
|
if (code != null) {
|
||||||
|
|
Loading…
Reference in New Issue