[(master)] Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
46fcceb9c6
|
@ -141,6 +141,8 @@ local.properties
|
|||
**/.target
|
||||
**/.project
|
||||
**/.classpath
|
||||
**/.factorypath
|
||||
**/.springBeans
|
||||
|
||||
|
||||
# PDT-specific
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
version: 1.0.{build}
|
||||
image: Visual Studio 2017
|
||||
cache:
|
||||
- C:\maven\
|
||||
- C:\Users\appveyor\.m2
|
||||
build_script:
|
||||
- cmd: mvn -P MINPARALLEL,ALLMODULES install
|
|
@ -92,6 +92,12 @@
|
|||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
|
|
|
@ -116,10 +116,10 @@
|
|||
<artifactId>spring-jcl</artifactId>
|
||||
</dependency>
|
||||
</ignoredDependencies>
|
||||
<ignoredResources>
|
||||
<ignoredResource>changelog.txt</ignoredResource>
|
||||
<ignoredResourcePatterns>
|
||||
<ignoredResourcePattern>changelog.txt</ignoredResourcePattern>
|
||||
<ignoredResource>javac.bat</ignoredResource>
|
||||
</ignoredResources>
|
||||
</ignoredResourcePatterns>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
|
|
@ -43,7 +43,7 @@ public abstract class BaseParser implements IParser {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseParser.class);
|
||||
|
||||
private ContainedResources myContainedResources;
|
||||
|
||||
private boolean myEncodeElementsAppliesToChildResourcesOnly;
|
||||
private FhirContext myContext;
|
||||
private Set<String> myDontEncodeElements;
|
||||
private boolean myDontEncodeElementsIncludesStars;
|
||||
|
@ -556,6 +556,16 @@ public abstract class BaseParser implements IParser {
|
|||
&& theIncludedResource == false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEncodeElementsAppliesToChildResourcesOnly() {
|
||||
return myEncodeElementsAppliesToChildResourcesOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEncodeElementsAppliesToChildResourcesOnly(boolean theEncodeElementsAppliesToChildResourcesOnly) {
|
||||
myEncodeElementsAppliesToChildResourcesOnly = theEncodeElementsAppliesToChildResourcesOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOmitResourceId() {
|
||||
return myOmitResourceId;
|
||||
|
@ -1051,7 +1061,13 @@ public abstract class BaseParser implements IParser {
|
|||
}
|
||||
|
||||
private boolean checkIfParentShouldBeEncodedAndBuildPath(StringBuilder thePathBuilder, boolean theStarPass) {
|
||||
return checkIfPathMatchesForEncoding(thePathBuilder, theStarPass, myEncodeElementsAppliesToResourceTypes, myEncodeElements, true);
|
||||
Set<String> encodeElements = myEncodeElements;
|
||||
if (encodeElements != null && encodeElements.isEmpty() == false) {
|
||||
if (isEncodeElementsAppliesToChildResourcesOnly() && !mySubResource) {
|
||||
encodeElements = null;
|
||||
}
|
||||
}
|
||||
return checkIfPathMatchesForEncoding(thePathBuilder, theStarPass, myEncodeElementsAppliesToResourceTypes, encodeElements, true);
|
||||
}
|
||||
|
||||
private boolean checkIfParentShouldNotBeEncodedAndBuildPath(StringBuilder thePathBuilder, boolean theStarPass) {
|
||||
|
@ -1070,6 +1086,9 @@ public abstract class BaseParser implements IParser {
|
|||
} else {
|
||||
thePathBuilder.append(myResDef.getName());
|
||||
}
|
||||
if (theElements == null) {
|
||||
return true;
|
||||
}
|
||||
if (theElements.contains(thePathBuilder.toString())) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -206,6 +206,22 @@ public interface IParser {
|
|||
*/
|
||||
void setEncodeElements(Set<String> theEncodeElements);
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is false), the values supplied
|
||||
* to {@link #setEncodeElements(Set)} will not be applied to the root
|
||||
* resource (typically a Bundle), but will be applied to any sub-resources
|
||||
* contained within it (i.e. search result resources in that bundle)
|
||||
*/
|
||||
void setEncodeElementsAppliesToChildResourcesOnly(boolean theEncodeElementsAppliesToChildResourcesOnly);
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is false), the values supplied
|
||||
* to {@link #setEncodeElements(Set)} will not be applied to the root
|
||||
* resource (typically a Bundle), but will be applied to any sub-resources
|
||||
* contained within it (i.e. search result resources in that bundle)
|
||||
*/
|
||||
boolean isEncodeElementsAppliesToChildResourcesOnly();
|
||||
|
||||
/**
|
||||
* If provided, tells the parse which resource types to apply {@link #setEncodeElements(Set) encode elements} to. Any
|
||||
* resource types not specified here will be encoded completely, with no elements excluded.
|
||||
|
|
|
@ -19,12 +19,13 @@ public class BinaryUtil {
|
|||
public static IBaseReference getSecurityContext(FhirContext theCtx, IBaseBinary theBinary) {
|
||||
RuntimeResourceDefinition def = theCtx.getResourceDefinition("Binary");
|
||||
BaseRuntimeChildDefinition child = def.getChildByName("securityContext");
|
||||
|
||||
List<IBase> values = child.getAccessor().getValues(theBinary);
|
||||
IBaseReference retVal = null;
|
||||
if (child != null) {
|
||||
List<IBase> values = child.getAccessor().getValues(theBinary);
|
||||
if (values.size() > 0) {
|
||||
retVal = (IBaseReference) values.get(0);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,12 +21,14 @@ package ca.uhn.fhir.util;
|
|||
*/
|
||||
|
||||
import java.net.ServerSocket;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
/**
|
||||
* Provides server ports
|
||||
*/
|
||||
@CoverageIgnore
|
||||
public class PortUtil {
|
||||
private static LinkedHashSet<Integer> ourPorts = new LinkedHashSet<>();
|
||||
|
||||
/*
|
||||
* Non instantiable
|
||||
|
@ -41,9 +43,13 @@ public class PortUtil {
|
|||
public static int findFreePort() {
|
||||
ServerSocket server;
|
||||
try {
|
||||
int port;
|
||||
do {
|
||||
server = new ServerSocket(0);
|
||||
int port = server.getLocalPort();
|
||||
port = server.getLocalPort();
|
||||
server.close();
|
||||
} while (!ourPorts.add(port));
|
||||
|
||||
Thread.sleep(500);
|
||||
return port;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -30,8 +30,10 @@ import org.slf4j.LoggerFactory;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
|
@ -123,6 +125,27 @@ public class TestUtil {
|
|||
ourLog.info("Tests are using time zone: {}", TimeZone.getDefault().getID());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b>
|
||||
* <p>
|
||||
* Wait for an atomicinteger to hit a given site and fail if it never does
|
||||
*/
|
||||
public static void waitForSize(int theTarget, AtomicInteger theInteger) {
|
||||
long start = System.currentTimeMillis();
|
||||
while (theInteger.get() != theTarget && (System.currentTimeMillis() - start) <= 15000) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException theE) {
|
||||
throw new Error(theE);
|
||||
}
|
||||
}
|
||||
if ((System.currentTimeMillis() - start) >= 15000) {
|
||||
throw new IllegalStateException("Size " + theInteger.get() + " is != target " + theTarget);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <b>THIS IS FOR UNIT TESTS ONLY - DO NOT CALL THIS METHOD FROM USER CODE</b>
|
||||
* <p>
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.demo;
|
|||
|
||||
import java.util.Properties;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
@ -23,6 +24,7 @@ public class FhirDbConfig {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This interceptor adds arbitrary header values to requests made by the client.
|
||||
*/
|
||||
public class AdditionalRequestHeadersInterceptor implements IClientInterceptor {
|
||||
private final Map<String, List<String>> additionalHttpHeaders = new HashMap<>();
|
||||
|
||||
public AdditionalRequestHeadersInterceptor() {
|
||||
this(new HashMap<String, List<String>>());
|
||||
}
|
||||
|
||||
public AdditionalRequestHeadersInterceptor(Map<String, List<String>> additionalHttpHeaders) {
|
||||
super();
|
||||
if (additionalHttpHeaders != null) {
|
||||
this.additionalHttpHeaders.putAll(additionalHttpHeaders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given header value.
|
||||
* Note that {@code headerName} and {@code headerValue} cannot be null.
|
||||
* @param headerName the name of the header
|
||||
* @param headerValue the value to add for the header
|
||||
* @throws NullPointerException if either parameter is {@code null}
|
||||
*/
|
||||
public void addHeaderValue(String headerName, String headerValue) {
|
||||
Objects.requireNonNull(headerName, "headerName cannot be null");
|
||||
Objects.requireNonNull(headerValue, "headerValue cannot be null");
|
||||
|
||||
getHeaderValues(headerName).add(headerValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the list of header values for the given header.
|
||||
* Note that {@code headerName} and {@code headerValues} cannot be null.
|
||||
* @param headerName the name of the header
|
||||
* @param headerValues the list of values to add for the header
|
||||
* @throws NullPointerException if either parameter is {@code null}
|
||||
*/
|
||||
public void addAllHeaderValues(String headerName, List<String> headerValues) {
|
||||
Objects.requireNonNull(headerName, "headerName cannot be null");
|
||||
Objects.requireNonNull(headerValues, "headerValues cannot be null");
|
||||
|
||||
getHeaderValues(headerName).addAll(headerValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the header values list for a given header.
|
||||
* If the header doesn't have any values, an empty list will be returned.
|
||||
* @param headerName the name of the header
|
||||
* @return the list of values for the header
|
||||
*/
|
||||
private List<String> getHeaderValues(String headerName) {
|
||||
if (additionalHttpHeaders.get(headerName) == null) {
|
||||
additionalHttpHeaders.put(headerName, new ArrayList<String>());
|
||||
}
|
||||
return additionalHttpHeaders.get(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the additional header values to the HTTP request.
|
||||
* @param theRequest the HTTP request
|
||||
*/
|
||||
@Override
|
||||
public void interceptRequest(IHttpRequest theRequest) {
|
||||
for (Map.Entry<String, List<String>> header : additionalHttpHeaders.entrySet()) {
|
||||
for (String headerValue : header.getValue()) {
|
||||
if (headerValue != null) {
|
||||
theRequest.addHeader(header.getKey(), headerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing since this interceptor is not concerned with the response.
|
||||
* @param theResponse the HTTP response
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public void interceptResponse(IHttpResponse theResponse) throws IOException {
|
||||
// Do nothing. This interceptor is not concerned with the response.
|
||||
}
|
||||
}
|
|
@ -32,6 +32,8 @@ import org.apache.commons.lang3.Validate;
|
|||
/**
|
||||
* This interceptor adds an arbitrary header to requests made by this client. Both the
|
||||
* header name and the header value are specified by the calling code.
|
||||
*
|
||||
* @see AdditionalRequestHeadersInterceptor for a more advanced version of this interceptor which can add multiple headers
|
||||
*/
|
||||
public class SimpleRequestHeaderInterceptor implements IClientInterceptor {
|
||||
|
||||
|
|
|
@ -26,20 +26,8 @@ import ca.uhn.fhir.rest.api.Constants;
|
|||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.apache.lucene.analysis.core.LowerCaseFilterFactory;
|
||||
import org.apache.lucene.analysis.core.StopFilterFactory;
|
||||
import org.apache.lucene.analysis.miscellaneous.WordDelimiterFilterFactory;
|
||||
import org.apache.lucene.analysis.ngram.EdgeNGramFilterFactory;
|
||||
import org.apache.lucene.analysis.ngram.NGramFilterFactory;
|
||||
import org.apache.lucene.analysis.pattern.PatternTokenizerFactory;
|
||||
import org.apache.lucene.analysis.phonetic.PhoneticFilterFactory;
|
||||
import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory;
|
||||
import org.apache.lucene.analysis.standard.StandardFilterFactory;
|
||||
import org.apache.lucene.analysis.standard.StandardTokenizerFactory;
|
||||
import org.hibernate.annotations.ColumnDefault;
|
||||
import org.hibernate.annotations.OptimisticLock;
|
||||
import org.hibernate.search.annotations.*;
|
||||
import org.hibernate.search.annotations.Parameter;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Index;
|
||||
|
@ -61,53 +49,6 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
|
|||
@Index(name = "IDX_RES_TYPE", columnList = "RES_TYPE"),
|
||||
@Index(name = "IDX_INDEXSTATUS", columnList = "SP_INDEX_STATUS")
|
||||
})
|
||||
@AnalyzerDefs({
|
||||
@AnalyzerDef(name = "autocompleteEdgeAnalyzer",
|
||||
tokenizer = @TokenizerDef(factory = PatternTokenizerFactory.class, params = {
|
||||
@Parameter(name = "pattern", value = "(.*)"),
|
||||
@Parameter(name = "group", value = "1")
|
||||
}),
|
||||
filters = {
|
||||
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
|
||||
@TokenFilterDef(factory = StopFilterFactory.class),
|
||||
@TokenFilterDef(factory = EdgeNGramFilterFactory.class, params = {
|
||||
@Parameter(name = "minGramSize", value = "3"),
|
||||
@Parameter(name = "maxGramSize", value = "50")
|
||||
}),
|
||||
}),
|
||||
@AnalyzerDef(name = "autocompletePhoneticAnalyzer",
|
||||
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
|
||||
filters = {
|
||||
@TokenFilterDef(factory = StandardFilterFactory.class),
|
||||
@TokenFilterDef(factory = StopFilterFactory.class),
|
||||
@TokenFilterDef(factory = PhoneticFilterFactory.class, params = {
|
||||
@Parameter(name = "encoder", value = "DoubleMetaphone")
|
||||
}),
|
||||
@TokenFilterDef(factory = SnowballPorterFilterFactory.class, params = {
|
||||
@Parameter(name = "language", value = "English")
|
||||
})
|
||||
}),
|
||||
@AnalyzerDef(name = "autocompleteNGramAnalyzer",
|
||||
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
|
||||
filters = {
|
||||
@TokenFilterDef(factory = WordDelimiterFilterFactory.class),
|
||||
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
|
||||
@TokenFilterDef(factory = NGramFilterFactory.class, params = {
|
||||
@Parameter(name = "minGramSize", value = "3"),
|
||||
@Parameter(name = "maxGramSize", value = "20")
|
||||
}),
|
||||
}),
|
||||
@AnalyzerDef(name = "standardAnalyzer",
|
||||
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
|
||||
filters = {
|
||||
@TokenFilterDef(factory = LowerCaseFilterFactory.class),
|
||||
}),
|
||||
@AnalyzerDef(name = "exactAnalyzer",
|
||||
tokenizer = @TokenizerDef(factory = StandardTokenizerFactory.class),
|
||||
filters = {
|
||||
})
|
||||
}
|
||||
)
|
||||
//@formatter:on
|
||||
public class ResourceTable extends BaseHasResource implements Serializable {
|
||||
static final int RESTYPE_LEN = 30;
|
||||
|
|
|
@ -52,16 +52,12 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
|
|||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
|
||||
import org.hibernate.search.annotations.Analyze;
|
||||
import org.hibernate.search.annotations.Analyzer;
|
||||
import org.hibernate.search.annotations.AnalyzerDef;
|
||||
import org.hibernate.search.annotations.AnalyzerDefs;
|
||||
import org.hibernate.search.annotations.Field;
|
||||
import org.hibernate.search.annotations.Fields;
|
||||
import org.hibernate.search.annotations.Indexed;
|
||||
import org.hibernate.search.annotations.Store;
|
||||
import org.hibernate.search.annotations.TokenizerDef;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||
import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
|
||||
|
@ -73,12 +69,6 @@ import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
|
|||
}, indexes= {
|
||||
@Index(name = "IDX_CONCEPT_INDEXSTATUS", columnList="INDEX_STATUS")
|
||||
})
|
||||
@AnalyzerDefs({
|
||||
@AnalyzerDef(name = "conceptParentPidsAnalyzer",
|
||||
tokenizer = @TokenizerDef(factory = WhitespaceTokenizerFactory.class),
|
||||
filters = {
|
||||
})
|
||||
})
|
||||
public class TermConcept implements Serializable {
|
||||
private static final int MAX_DESC_LENGTH = 400;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TermConcept.class);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package ca.uhn.fhir.jpa.search;
|
||||
|
||||
import org.apache.lucene.analysis.core.LowerCaseFilterFactory;
|
||||
import org.apache.lucene.analysis.core.StopFilterFactory;
|
||||
import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
|
||||
import org.apache.lucene.analysis.miscellaneous.WordDelimiterFilterFactory;
|
||||
import org.apache.lucene.analysis.ngram.EdgeNGramFilterFactory;
|
||||
import org.apache.lucene.analysis.ngram.NGramFilterFactory;
|
||||
import org.apache.lucene.analysis.pattern.PatternTokenizerFactory;
|
||||
import org.apache.lucene.analysis.phonetic.PhoneticFilterFactory;
|
||||
import org.apache.lucene.analysis.snowball.SnowballPorterFilterFactory;
|
||||
import org.apache.lucene.analysis.standard.StandardFilterFactory;
|
||||
import org.apache.lucene.analysis.standard.StandardTokenizerFactory;
|
||||
import org.hibernate.search.annotations.Factory;
|
||||
import org.hibernate.search.cfg.SearchMapping;
|
||||
|
||||
/**
|
||||
* Factory for defining the analysers.
|
||||
*/
|
||||
public class LuceneSearchMappingFactory {
|
||||
@Factory
|
||||
public SearchMapping getSearchMapping() {
|
||||
SearchMapping mapping = new SearchMapping();
|
||||
|
||||
mapping.analyzerDef("autocompleteEdgeAnalyzer", PatternTokenizerFactory.class)
|
||||
.tokenizerParam("pattern", "(.*)")
|
||||
.tokenizerParam("group", "1")
|
||||
.filter(LowerCaseFilterFactory.class)
|
||||
.filter(StopFilterFactory.class)
|
||||
.filter(EdgeNGramFilterFactory.class)
|
||||
.param("minGramSize", "3")
|
||||
.param("maxGramSize", "50")
|
||||
.analyzerDef("autocompletePhoneticAnalyzer", StandardTokenizerFactory.class)
|
||||
.filter(StandardFilterFactory.class)
|
||||
.filter(StopFilterFactory.class)
|
||||
.filter(PhoneticFilterFactory.class)
|
||||
.param("encoder", "DoubleMetaphone")
|
||||
.filter(SnowballPorterFilterFactory.class)
|
||||
.param("language", "English")
|
||||
.analyzerDef("autocompleteNGramAnalyzer", StandardTokenizerFactory.class)
|
||||
.filter(WordDelimiterFilterFactory.class)
|
||||
.filter(LowerCaseFilterFactory.class)
|
||||
.filter(NGramFilterFactory.class)
|
||||
.param("minGramSize", "3")
|
||||
.param("maxGramSize", "20")
|
||||
.analyzerDef("standardAnalyzer", StandardTokenizerFactory.class)
|
||||
.filter(LowerCaseFilterFactory.class)
|
||||
.analyzerDef("exactAnalyzer", StandardTokenizerFactory.class)
|
||||
.analyzerDef("conceptParentPidsAnalyzer", WhitespaceTokenizerFactory.class);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
}
|
|
@ -19,39 +19,51 @@ package ca.uhn.fhir.jpa.search;
|
|||
* limitations under the License.
|
||||
* #L%family
|
||||
*/
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.method.PageMethodBinding;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.*;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
|
||||
import org.springframework.transaction.*;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.*;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.method.PageMethodBinding;
|
||||
import javax.persistence.EntityManager;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||
public static final int DEFAULT_SYNC_SIZE = 250;
|
||||
|
@ -420,6 +432,19 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A search task is a Callable task that runs in
|
||||
* a thread pool to handle an individual search. One instance
|
||||
* is created for any requested search and runs from the
|
||||
* beginning to the end of the search.
|
||||
*
|
||||
* Understand:
|
||||
* This class executes in its own thread separate from the
|
||||
* web server client thread that made the request. We do that
|
||||
* so that we can return to the client as soon as possible,
|
||||
* but keep the search going in the background (and have
|
||||
* the next page of results ready to go when the client asks).
|
||||
*/
|
||||
public class SearchTask implements Callable<Void> {
|
||||
|
||||
private final IDao myCallingDao;
|
||||
|
@ -434,6 +459,9 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
private int myCountSaved = 0;
|
||||
private String mySearchUuid;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SearchTask(Search theSearch, IDao theCallingDao, SearchParameterMap theParams, String theResourceType, String theSearchUuid) {
|
||||
mySearch = theSearch;
|
||||
myCallingDao = theCallingDao;
|
||||
|
@ -443,6 +471,11 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
mySearchUuid = theSearchUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by the server HTTP thread, and
|
||||
* will block until at least one page of results have been
|
||||
* fetched from the DB, and will never block after that.
|
||||
*/
|
||||
public Integer awaitInitialSync() {
|
||||
ourLog.trace("Awaiting initial sync");
|
||||
do {
|
||||
|
@ -451,6 +484,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
break;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// Shouldn't happen
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
} while (mySearch.getStatus() == SearchStatusEnum.LOADING);
|
||||
|
@ -459,11 +493,16 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
return mySearch.getTotalCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the method which actually performs the search.
|
||||
* It is called automatically by the thread pool.
|
||||
*/
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
try {
|
||||
// Create an initial search in the DB and give it an ID
|
||||
saveSearch();
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
|
@ -480,7 +519,9 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
} catch (Throwable t) {
|
||||
|
||||
/*
|
||||
* Don't print a stack trace for client errors.. that's just noisy
|
||||
* Don't print a stack trace for client errors (i.e. requests that
|
||||
* aren't valid because the client screwed up).. that's just noise
|
||||
* in the logs and who needs that.
|
||||
*/
|
||||
boolean logged = false;
|
||||
if (t instanceof BaseServerResponseException) {
|
||||
|
@ -535,13 +576,27 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(myResourceType).getImplementingClass();
|
||||
ISearchBuilder sb = myCallingDao.newSearchBuilder();
|
||||
sb.setType(resourceTypeClass, myResourceType);
|
||||
Iterator<Long> theResultIter = sb.createQuery(myParams, mySearchUuid);
|
||||
Iterator<Long> theResultIterator = sb.createQuery(myParams, mySearchUuid);
|
||||
|
||||
while (theResultIter.hasNext()) {
|
||||
myUnsyncedPids.add(theResultIter.next());
|
||||
if (myUnsyncedPids.size() >= mySyncSize) {
|
||||
saveUnsynced(theResultIter);
|
||||
while (theResultIterator.hasNext()) {
|
||||
myUnsyncedPids.add(theResultIterator.next());
|
||||
|
||||
boolean shouldSync = myUnsyncedPids.size() >= mySyncSize;
|
||||
|
||||
if (myDaoConfig.getCountSearchResultsUpTo() != null &&
|
||||
myDaoConfig.getCountSearchResultsUpTo() > 0 &&
|
||||
myDaoConfig.getCountSearchResultsUpTo() < myUnsyncedPids.size()) {
|
||||
shouldSync = false;
|
||||
}
|
||||
|
||||
if (myUnsyncedPids.size() > 50000) {
|
||||
shouldSync = true;
|
||||
}
|
||||
|
||||
if (shouldSync) {
|
||||
saveUnsynced(theResultIterator);
|
||||
}
|
||||
|
||||
if (myLoadingThrottleForUnitTests != null) {
|
||||
try {
|
||||
Thread.sleep(myLoadingThrottleForUnitTests);
|
||||
|
@ -549,9 +604,12 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Check if an abort got requested
|
||||
Validate.isTrue(myAbortRequested == false, "Abort has been requested");
|
||||
|
||||
}
|
||||
saveUnsynced(theResultIter);
|
||||
saveUnsynced(theResultIterator);
|
||||
}
|
||||
|
||||
public CountDownLatch getCompletionLatch() {
|
||||
|
@ -648,11 +706,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
||||
}
|
||||
}
|
||||
mySearch.setNumFound(myCountSaved);
|
||||
doSaveSearch();
|
||||
|
||||
}
|
||||
});
|
||||
mySearch.setNumFound(myCountSaved);
|
||||
|
||||
int numSynced;
|
||||
synchronized (mySyncedPids) {
|
||||
|
@ -664,6 +719,12 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
myDaoConfig.getCountSearchResultsUpTo() <= numSynced) {
|
||||
myInitialCollectionLatch.countDown();
|
||||
}
|
||||
|
||||
doSaveSearch();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.email.SubscriptionEmailInterceptor;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
|
@ -60,6 +60,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
|
||||
return extraProperties;
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.email.IEmailSender;
|
||||
import ca.uhn.fhir.jpa.subscription.email.JavaMailEmailSender;
|
||||
|
@ -141,6 +151,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.listener.ThreadQueryCountHolder;
|
||||
|
@ -125,6 +126,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
|||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
|
||||
extraProperties.put("hibernate.search.model_mapping", ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||
|
|
|
@ -56,6 +56,30 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
|||
myDaoConfig.setTreatReferencesAsLogical(new DaoConfig().getTreatReferencesAsLogical());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #773
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteResourceWithOutboundDeletedResources() {
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(false);
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("ORG");
|
||||
org.setName("ORG");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setId("PAT");
|
||||
pat.setActive(true);
|
||||
pat.setManagingOrganization(new ResourceReferenceDt("Organization/ORG"));
|
||||
myPatientDao.update(pat);
|
||||
|
||||
myOrganizationDao.delete(new IdDt("Organization/ORG"));
|
||||
|
||||
myPatientDao.delete(new IdDt("Patient/PAT"));
|
||||
}
|
||||
|
||||
|
||||
private void assertGone(IIdType theId) {
|
||||
try {
|
||||
assertNotGone(theId);
|
||||
|
|
|
@ -55,6 +55,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
public final void after() {
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
myDaoConfig.setTreatReferencesAsLogical(new DaoConfig().getTreatReferencesAsLogical());
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
|
||||
}
|
||||
|
||||
private void assertGone(IIdType theId) {
|
||||
|
@ -98,6 +99,29 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* See #773
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteResourceWithOutboundDeletedResources() {
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(false);
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("ORG");
|
||||
org.setName("ORG");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setId("PAT");
|
||||
pat.setActive(true);
|
||||
pat.setManagingOrganization(new Reference("Organization/ORG"));
|
||||
myPatientDao.update(pat);
|
||||
|
||||
myOrganizationDao.delete(new IdType("Organization/ORG"));
|
||||
|
||||
myPatientDao.delete(new IdType("Patient/PAT"));
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import ca.uhn.fhir.jpa.provider.r4.ResourceProviderInterceptorR4Test;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Conformance;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
|
@ -61,8 +60,8 @@ public class ResourceProviderInterceptorDstu3Test extends BaseResourceProviderDs
|
|||
public void before() throws Exception {
|
||||
super.before();
|
||||
|
||||
myServerInterceptor = mock(IServerInterceptor.class);
|
||||
myDaoInterceptor = mock(IServerInterceptor.class);
|
||||
myServerInterceptor = mock(IServerInterceptor.class, withSettings().verboseLogging());
|
||||
myDaoInterceptor = mock(IServerInterceptor.class, withSettings().verboseLogging());
|
||||
|
||||
resetServerInterceptor();
|
||||
|
||||
|
@ -125,6 +124,8 @@ public class ResourceProviderInterceptorDstu3Test extends BaseResourceProviderDs
|
|||
public void testCreateResourceInTransaction() throws IOException, ServletException {
|
||||
String methodName = "testCreateResourceInTransaction";
|
||||
|
||||
ourLog.info("** Starting {}", methodName);
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().setFamily(methodName);
|
||||
|
||||
|
@ -140,6 +141,11 @@ public class ResourceProviderInterceptorDstu3Test extends BaseResourceProviderDs
|
|||
|
||||
resetServerInterceptor();
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myDaoInterceptor, times(0)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
verify(myServerInterceptor, times(0)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
|
||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
||||
|
@ -153,8 +159,8 @@ public class ResourceProviderInterceptorDstu3Test extends BaseResourceProviderDs
|
|||
* Server Interceptor
|
||||
*/
|
||||
|
||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
||||
verify(myServerInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
||||
assertEquals(null, ardCaptor.getAllValues().get(0).getResourceType());
|
||||
|
|
|
@ -3149,17 +3149,19 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
.count(1)
|
||||
.execute();
|
||||
|
||||
ourLog.info("** Done searching with count of 1");
|
||||
ourLog.info("** Done searching in {}ms with count of 1", sw.getMillis());
|
||||
|
||||
ourLog.info(myCapturingInterceptor.getLastResponse().getAllHeaders().toString());
|
||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.<String>empty());
|
||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()),Matchers.<String>empty());
|
||||
|
||||
assertThat(sw.getMillis(), lessThan(1000L));
|
||||
String msg = "Total is " + found.getTotalElement().getValue() + " and took " + sw.getMillis() + " millis";
|
||||
|
||||
// If this fails under load, try increasing the throttle above
|
||||
assertEquals(null, found.getTotalElement().getValue());
|
||||
assertEquals(1, found.getEntry().size());
|
||||
assertEquals(msg,null, found.getTotalElement().getValue());
|
||||
assertEquals(msg, 1, found.getEntry().size());
|
||||
assertThat(msg, sw.getMillis(), lessThan(1000L));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -3214,11 +3216,10 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), Matchers.<String>empty());
|
||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE.toLowerCase()),Matchers.<String>empty());
|
||||
|
||||
assertThat(sw.getMillis(), lessThan(1000L));
|
||||
|
||||
// If this fails under load, try increasing the throttle above
|
||||
assertEquals(null, found.getTotalElement().getValue());
|
||||
assertEquals(1, found.getEntry().size());
|
||||
assertThat(sw.getMillis(), lessThan(1000L));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Properties;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
|
@ -80,6 +81,7 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
|
@ -80,6 +79,7 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -84,6 +84,7 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", SearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhirtest.config;
|
|||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
@ -111,6 +112,7 @@ public class TdlDstu2Config extends BaseJavaConfigDstu2 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider" ,"filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
|
||||
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Properties;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.dialect.DerbyTenSevenDialect;
|
||||
|
@ -13,7 +14,6 @@ import org.springframework.beans.factory.annotation.Autowire;
|
|||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
|
@ -94,6 +94,7 @@ public class TdlDstu3Config extends BaseJavaConfigDstu3 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhirtest.config;
|
|||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
|
@ -65,6 +66,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
retVal.setAllowExternalReferences(true);
|
||||
retVal.getTreatBaseUrlsAsLocal().add("http://fhirtest.uhn.ca/baseDstu2");
|
||||
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu2");
|
||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -115,6 +117,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Properties;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.dialect.DerbyTenSevenDialect;
|
||||
|
@ -54,6 +55,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
retVal.setAllowExternalReferences(true);
|
||||
retVal.getTreatBaseUrlsAsLocal().add("http://fhirtest.uhn.ca/baseDstu3");
|
||||
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu3");
|
||||
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
@ -112,6 +114,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -5,11 +5,11 @@ import java.util.Properties;
|
|||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hibernate.dialect.DerbyTenSevenDialect;
|
||||
import org.hibernate.dialect.PostgreSQL94Dialect;
|
||||
import org.hibernate.dialect.PostgreSQL95Dialect;
|
||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
@ -110,6 +110,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
|||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
|
|
|
@ -86,10 +86,41 @@ public class RestfulServerUtils {
|
|||
}
|
||||
}
|
||||
if (elements != null && elements.size() > 0) {
|
||||
Set<String> newElements = new HashSet<String>();
|
||||
Set<String> newElements = new HashSet<>();
|
||||
for (String next : elements) {
|
||||
newElements.add("*." + next);
|
||||
}
|
||||
|
||||
/*
|
||||
* We try to be smart about what the user is asking for
|
||||
* when they include an _elements parameter. If we're responding
|
||||
* to something that returns a Bundle (e.g. a search) we assume
|
||||
* the elements don't apply to the Bundle itself, unless
|
||||
* the client has explicitly scoped the Bundle
|
||||
* (i.e. with Bundle.total or something like that)
|
||||
*/
|
||||
switch (theRequestDetails.getRestOperationType()) {
|
||||
case SEARCH_SYSTEM:
|
||||
case SEARCH_TYPE:
|
||||
case HISTORY_SYSTEM:
|
||||
case HISTORY_TYPE:
|
||||
case HISTORY_INSTANCE:
|
||||
case GET_PAGE:
|
||||
boolean haveExplicitBundleElement = false;
|
||||
for (String next : newElements) {
|
||||
if (next.startsWith("Bundle.")) {
|
||||
haveExplicitBundleElement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!haveExplicitBundleElement) {
|
||||
parser.setEncodeElementsAppliesToChildResourcesOnly(true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
parser.setEncodeElements(newElements);
|
||||
parser.setEncodeElementsAppliesToResourceTypes(elementsAppliesTo);
|
||||
}
|
||||
|
@ -147,6 +178,19 @@ public class RestfulServerUtils {
|
|||
b.append(theBundleType.getCode());
|
||||
}
|
||||
|
||||
String paramName = Constants.PARAM_ELEMENTS;
|
||||
String[] params = theRequestParameters.get(paramName);
|
||||
if (params != null) {
|
||||
for (String nextValue : params) {
|
||||
if (isNotBlank(nextValue)) {
|
||||
b.append('&');
|
||||
b.append(paramName);
|
||||
b.append('=');
|
||||
b.append(UrlUtil.escape(nextValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return b.toString();
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new Error("UTF-8 not supported", e);// should not happen
|
||||
|
@ -587,10 +631,12 @@ public class RestfulServerUtils {
|
|||
response.addHeader(Constants.HEADER_CONTENT_DISPOSITION, "Attachment;");
|
||||
|
||||
IBaseReference securityContext = BinaryUtil.getSecurityContext(theServer.getFhirContext(), bin);
|
||||
if (securityContext != null) {
|
||||
String securityContextRef = securityContext.getReferenceElement().getValue();
|
||||
if (isNotBlank(securityContextRef)) {
|
||||
response.addHeader(Constants.HEADER_X_SECURITY_CONTEXT, securityContextRef);
|
||||
}
|
||||
}
|
||||
|
||||
return response.sendAttachmentResponse(bin, theStausCode, contentType);
|
||||
}
|
||||
|
|
|
@ -332,7 +332,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
}
|
||||
|
||||
bundleFactory.addRootPropertiesToBundle(theResult.getUuid(), serverBase, theLinkSelf, linkPrev, linkNext, theResult.size(), theBundleType, theResult.getPublished());
|
||||
bundleFactory.addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, serverBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
bundleFactory.addResourcesToBundle(new ArrayList<>(resourceList), theBundleType, serverBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
|
||||
if (theServer.getPagingProvider() != null) {
|
||||
int limit;
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-autoconfigure</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Compile dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional dependencies -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client-okhttp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- @ConfigurationProperties annotation processing (metadata for IDEs) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>log4j-over-slf4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,287 @@
|
|||
package ca.uhn.fhir.spring.boot.autoconfigure;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsProvider;
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaProvider;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
||||
import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
|
||||
import okhttp3.OkHttpClient;
|
||||
import org.apache.http.client.HttpClient;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ResourceCondition;
|
||||
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for HAPI FHIR.
|
||||
*
|
||||
* @author Mathieu Ouellet
|
||||
*/
|
||||
@Configuration
|
||||
@AutoConfigureAfter({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
|
||||
@EnableConfigurationProperties(FhirProperties.class)
|
||||
public class FhirAutoConfiguration {
|
||||
|
||||
private final FhirProperties properties;
|
||||
|
||||
public FhirAutoConfiguration(FhirProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public FhirContext fhirContext() {
|
||||
FhirContext fhirContext = new FhirContext(properties.getVersion());
|
||||
return fhirContext;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(AbstractJaxRsProvider.class)
|
||||
@EnableConfigurationProperties(FhirProperties.class)
|
||||
@ConfigurationProperties("hapi.fhir.rest")
|
||||
@SuppressWarnings("serial")
|
||||
static class FhirRestfulServerConfiguration extends RestfulServer {
|
||||
|
||||
private final FhirProperties properties;
|
||||
|
||||
private final FhirContext fhirContext;
|
||||
|
||||
private final List<IResourceProvider> resourceProviders;
|
||||
|
||||
private final IPagingProvider pagingProvider;
|
||||
|
||||
private final List<IServerInterceptor> interceptors;
|
||||
|
||||
private final List<FhirRestfulServerCustomizer> customizers;
|
||||
|
||||
public FhirRestfulServerConfiguration(
|
||||
FhirProperties properties,
|
||||
FhirContext fhirContext,
|
||||
ObjectProvider<List<IResourceProvider>> resourceProviders,
|
||||
ObjectProvider<IPagingProvider> pagingProvider,
|
||||
ObjectProvider<List<IServerInterceptor>> interceptors,
|
||||
ObjectProvider<List<FhirRestfulServerCustomizer>> customizers) {
|
||||
this.properties = properties;
|
||||
this.fhirContext = fhirContext;
|
||||
this.resourceProviders = resourceProviders.getIfAvailable();
|
||||
this.pagingProvider = pagingProvider.getIfAvailable();
|
||||
this.interceptors = interceptors.getIfAvailable();
|
||||
this.customizers = customizers.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean fhirServerRegistrationBean() {
|
||||
ServletRegistrationBean registration = new ServletRegistrationBean(this, this.properties.getServer().getPath());
|
||||
registration.setLoadOnStartup(1);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
setFhirContext(this.fhirContext);
|
||||
setResourceProviders(this.resourceProviders);
|
||||
setPagingProvider(this.pagingProvider);
|
||||
setInterceptors(this.interceptors);
|
||||
|
||||
setServerAddressStrategy(new HardcodedServerAddressStrategy(this.properties.getServer().getPath()));
|
||||
|
||||
customize();
|
||||
}
|
||||
|
||||
private void customize() {
|
||||
if (this.customizers != null) {
|
||||
AnnotationAwareOrderComparator.sort(this.customizers);
|
||||
for (FhirRestfulServerCustomizer customizer : this.customizers) {
|
||||
customizer.customize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(BaseJpaProvider.class)
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
@EnableConfigurationProperties(FhirProperties.class)
|
||||
static class FhirJpaServerConfiguration {
|
||||
|
||||
@Configuration
|
||||
@EntityScan("ca.uhn.fhir.jpa.entity")
|
||||
@EnableJpaRepositories(basePackages = "ca.uhn.fhir.jpa.dao.data")
|
||||
static class FhirJpaDaoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConfigurationProperties("hapi.fhir.jpa")
|
||||
public DaoConfig fhirDaoConfig() {
|
||||
DaoConfig fhirDaoConfig = new DaoConfig();
|
||||
return fhirDaoConfig;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean({ DaoConfig.class, RestfulServer.class })
|
||||
@SuppressWarnings("rawtypes")
|
||||
static class RestfulServerCustomizer implements FhirRestfulServerCustomizer {
|
||||
|
||||
private final BaseJpaSystemProvider systemProviders;
|
||||
|
||||
public RestfulServerCustomizer(ObjectProvider<BaseJpaSystemProvider> systemProviders) {
|
||||
this.systemProviders = systemProviders.getIfAvailable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customize(RestfulServer server) {
|
||||
server.setPlainProviders(systemProviders);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(type = "ca.uhn.fhir.jpa.config.BaseConfig")
|
||||
@ConditionalOnProperty(name = "hapi.fhir.version", havingValue = "DSTU3")
|
||||
static class Dstu3 extends BaseJavaConfigDstu3 {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnMissingBean(type = "ca.uhn.fhir.jpa.config.BaseConfig")
|
||||
@ConditionalOnProperty(name = "hapi.fhir.version", havingValue = "DSTU2")
|
||||
static class Dstu2 extends BaseJavaConfigDstu2 {
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Conditional(FhirValidationConfiguration.SchemaAvailableCondition.class)
|
||||
@ConditionalOnProperty(name = "hapi.fhir.validation.enabled", matchIfMissing = true)
|
||||
static class FhirValidationConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
return new RequestValidatingInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(name = "hapi.fhir.validation.request-only", havingValue = "false")
|
||||
public ResponseValidatingInterceptor responseValidatingInterceptor() {
|
||||
return new ResponseValidatingInterceptor();
|
||||
}
|
||||
|
||||
static class SchemaAvailableCondition extends ResourceCondition {
|
||||
|
||||
SchemaAvailableCondition() {
|
||||
super("ValidationSchema",
|
||||
"hapi.fhir.validation",
|
||||
"schema-location",
|
||||
"classpath:/org/hl7/fhir/instance/model/schema",
|
||||
"classpath:/org/hl7/fhir/dstu2016may/model/schema",
|
||||
"classpath:/org/hl7/fhir/dstu3/model/schema");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnProperty("hapi.fhir.server.url")
|
||||
@EnableConfigurationProperties(FhirProperties.class)
|
||||
static class FhirRestfulClientConfiguration {
|
||||
|
||||
private final FhirProperties properties;
|
||||
|
||||
private final List<IClientInterceptor> clientInterceptors;
|
||||
|
||||
public FhirRestfulClientConfiguration(FhirProperties properties, ObjectProvider<List<IClientInterceptor>> clientInterceptors) {
|
||||
this.properties = properties;
|
||||
this.clientInterceptors = clientInterceptors.getIfAvailable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(IRestfulClientFactory.class)
|
||||
public IGenericClient fhirClient(final IRestfulClientFactory clientFactory) {
|
||||
IGenericClient fhirClient = clientFactory.newGenericClient(this.properties.getServer().getUrl());
|
||||
if (!CollectionUtils.isEmpty(this.clientInterceptors)) {
|
||||
for (IClientInterceptor interceptor : this.clientInterceptors) {
|
||||
fhirClient.registerInterceptor(interceptor);
|
||||
}
|
||||
}
|
||||
return fhirClient;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(HttpClient.class)
|
||||
@ConditionalOnMissingClass("okhttp3.OkHttpClient")
|
||||
static class Apache {
|
||||
|
||||
private final FhirContext context;
|
||||
|
||||
public Apache(FhirContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConfigurationProperties("hapi.fhir.rest.client.apache")
|
||||
public IRestfulClientFactory fhirRestfulClientFactory() {
|
||||
ApacheRestfulClientFactory restfulClientFactory = new ApacheRestfulClientFactory(this.context);
|
||||
return restfulClientFactory;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(OkHttpClient.class)
|
||||
static class OkHttp {
|
||||
|
||||
private final FhirContext context;
|
||||
|
||||
public OkHttp(FhirContext context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConfigurationProperties("hapi.fhir.rest.client.okhttp")
|
||||
public IRestfulClientFactory fhirRestfulClientFactory() {
|
||||
OkHttpRestfulClientFactory restfulClientFactory = new OkHttpRestfulClientFactory(this.context);
|
||||
return restfulClientFactory;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ca.uhn.fhir.spring.boot.autoconfigure;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@ConfigurationProperties(prefix = "hapi.fhir")
|
||||
public class FhirProperties {
|
||||
|
||||
private FhirVersionEnum version = FhirVersionEnum.DSTU2;
|
||||
|
||||
private Server server = new Server();
|
||||
|
||||
private Validation validation = new Validation();
|
||||
|
||||
public FhirVersionEnum getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(FhirVersionEnum version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public void setServer(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public Validation getValidation() {
|
||||
return validation;
|
||||
}
|
||||
|
||||
public void setValidation(Validation validation) {
|
||||
this.validation = validation;
|
||||
}
|
||||
|
||||
public static class Server {
|
||||
|
||||
private String url;
|
||||
|
||||
private String path = "/fhir/*";
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Validation {
|
||||
|
||||
private boolean enabled = true;
|
||||
|
||||
private boolean requestOnly = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public boolean isRequestOnly() {
|
||||
return requestOnly;
|
||||
}
|
||||
|
||||
public void setRequestOnly(boolean requestOnly) {
|
||||
this.requestOnly = requestOnly;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package ca.uhn.fhir.spring.boot.autoconfigure;
|
||||
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface FhirRestfulServerCustomizer {
|
||||
|
||||
/**
|
||||
* Customize the server.
|
||||
* @param server the server to customize
|
||||
*/
|
||||
void customize(RestfulServer server);
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=ca.uhn.fhir.spring.boot.autoconfigure.FhirAutoConfiguration
|
|
@ -0,0 +1,171 @@
|
|||
package ca.uhn.fhir.spring.boot.autoconfigure;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.okhttp.client.OkHttpRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.spring.boot.autoconfigure.FhirAutoConfiguration.FhirJpaServerConfiguration.Dstu3;
|
||||
import org.assertj.core.util.Arrays;
|
||||
import org.junit.After;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
|
||||
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
|
||||
import org.springframework.boot.test.util.EnvironmentTestUtils;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link FhirAutoConfiguration}.
|
||||
*
|
||||
* @author Mathieu Ouellet
|
||||
*/
|
||||
public class FhirAutoConfigurationTest {
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withFhirContext() throws Exception {
|
||||
load();
|
||||
assertThat(this.context.getBeansOfType(FhirContext.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withFhirVersion() throws Exception {
|
||||
load("hapi.fhir.version:DSTU3");
|
||||
assertThat(this.context.getBean(FhirContext.class).getVersion()).isEqualTo(FhirVersionEnum.DSTU3.getVersionImplementation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withRestfulServer() {
|
||||
load("hapi.fhir.server.path:/hapi-fhir/*");
|
||||
assertThat(this.context.getBeansOfType(ServletRegistrationBean.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(RestfulServer.class)).hasSize(1);
|
||||
assertThat(this.context.getBean(ServletRegistrationBean.class).getUrlMappings()).contains("/hapi-fhir/*");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withJpaServer() {
|
||||
load(
|
||||
Arrays.array(
|
||||
EmbeddedDataSourceConfiguration.class,
|
||||
HibernateJpaAutoConfiguration.class,
|
||||
PropertyPlaceholderAutoConfiguration.class,
|
||||
FhirAutoConfiguration.class),
|
||||
"hapi.fhir.version:DSTU3",
|
||||
"spring.jpa.properties.hibernate.search.default.indexBase:target/lucenefiles",
|
||||
"spring.jpa.properties.hibernate.search.model_mapping:ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory");
|
||||
assertThat(this.context.getBeansOfType(DaoConfig.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(Dstu3.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withNoValidation() {
|
||||
load("hapi.fhir.validation.enabled:false");
|
||||
this.thrown.expect(NoSuchBeanDefinitionException.class);
|
||||
this.context.getBean(RequestValidatingInterceptor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withValidation() {
|
||||
load();
|
||||
assertThat(this.context.getBeansOfType(IServerInterceptor.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withValidations() {
|
||||
load("hapi.fhir.validation.request-only=false");
|
||||
assertThat(this.context.getBeansOfType(IServerInterceptor.class)).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withCustomValidationSchemaLocation() {
|
||||
load("hapi.fhir.validation.schema-location:custom-schema-location");
|
||||
assertThat(this.context.getBeansOfType(IServerInterceptor.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withApacheHttpClient() {
|
||||
load(new HidePackagesClassLoader("okhttp3"), "hapi.fhir.server.url:http://localhost:8080");
|
||||
assertThat(this.context.getBeansOfType(ApacheRestfulClientFactory.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(OkHttpRestfulClientFactory.class)).hasSize(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void withOkHttpClient() {
|
||||
load("hapi.fhir.server.url:http://localhost:8080");
|
||||
assertThat(this.context.getBeansOfType(OkHttpRestfulClientFactory.class)).hasSize(1);
|
||||
assertThat(this.context.getBeansOfType(ApacheRestfulClientFactory.class)).hasSize(0);
|
||||
}
|
||||
|
||||
private void load(String... environment) {
|
||||
load(new Class<?>[] { FhirAutoConfiguration.class }, null, environment);
|
||||
}
|
||||
|
||||
private void load(ClassLoader classLoader, String... environment) {
|
||||
load(new Class<?>[] { FhirAutoConfiguration.class }, classLoader, environment);
|
||||
}
|
||||
|
||||
private void load(Class<?>[] configs, String... environment) {
|
||||
load(configs, null, environment);
|
||||
}
|
||||
|
||||
private void load(Class<?>[] configs, ClassLoader classLoader, String... environment) {
|
||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
EnvironmentTestUtils.addEnvironment(applicationContext, environment);
|
||||
if (classLoader != null) {
|
||||
applicationContext.setClassLoader(classLoader);
|
||||
}
|
||||
if (configs != null) {
|
||||
applicationContext.register(configs);
|
||||
}
|
||||
applicationContext.refresh();
|
||||
this.context = applicationContext;
|
||||
}
|
||||
|
||||
private static final class HidePackagesClassLoader extends URLClassLoader {
|
||||
|
||||
private final String[] hiddenPackages;
|
||||
|
||||
private HidePackagesClassLoader(String... hiddenPackages) {
|
||||
super(new URL[0], FhirAutoConfigurationTest.class.getClassLoader());
|
||||
this.hiddenPackages = hiddenPackages;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
for (String hiddenPackage : this.hiddenPackages) {
|
||||
if (name.startsWith(hiddenPackage)) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
}
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
spring:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
properties:
|
||||
hibernate.jdbc.batch_size: 20
|
||||
hibernate.cache.use_query_cache: false
|
||||
hibernate.cache.use_second_level_cache: false
|
||||
hibernate.cache.use_structured_entries: false
|
||||
hibernate.cache.use_minimal_puts: false
|
||||
hibernate.search.default.directory_provider: filesystem
|
||||
hibernate.search.default.indexBase: target/lucenefiles
|
||||
hibernate.search.lucene_version: LUCENE_CURRENT
|
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<configuration>
|
||||
<include resource="org/springframework/boot/logging/logback/base.xml"/>
|
||||
</configuration>
|
|
@ -0,0 +1,64 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Optional -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
|
@ -0,0 +1,37 @@
|
|||
package sample.fhir.client;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleApacheRestfulClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleApacheRestfulClientApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoggingInterceptor loggingInterceptor() {
|
||||
return new LoggingInterceptor(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandLineRunner runner(final IGenericClient fhirClient) {
|
||||
return new CommandLineRunner() {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
fhirClient.capabilities()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
server:
|
||||
port: 8888
|
||||
hapi:
|
||||
fhir:
|
||||
version: dstu3
|
||||
server:
|
||||
url: http://localhost:8080/fhir
|
||||
management:
|
||||
security:
|
||||
enabled: false
|
||||
logging:
|
||||
level:
|
||||
ca.uhn.fhir.jaxrs: debug
|
|
@ -0,0 +1,64 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client-okhttp</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Optional -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
|
@ -0,0 +1,37 @@
|
|||
package sample.fhir.client;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement;
|
||||
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleOkHttpRestfulClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleOkHttpRestfulClientApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoggingInterceptor loggingInterceptor() {
|
||||
return new LoggingInterceptor(true);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CommandLineRunner runner(final IGenericClient fhirClient) {
|
||||
return new CommandLineRunner() {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
fhirClient.capabilities()
|
||||
.ofType(CapabilityStatement.class)
|
||||
.execute();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
server:
|
||||
port: 8888
|
||||
hapi:
|
||||
fhir:
|
||||
version: dstu3
|
||||
server:
|
||||
url: http://localhost:8080/fhir
|
||||
management:
|
||||
security:
|
||||
enabled: false
|
||||
logging:
|
||||
level:
|
||||
ca.uhn.fhir.jaxrs: debug
|
|
@ -0,0 +1,67 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jersey</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Optional -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,20 @@
|
|||
package sample.fhir.server.jersey;
|
||||
|
||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleJerseyRestfulServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleJerseyRestfulServerApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoggingInterceptor loggingInterceptor() {
|
||||
return new LoggingInterceptor();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package sample.fhir.server.jersey.provider;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.dstu3.model.HumanName;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class PatientResourceProvider extends AbstractJaxRsResourceProvider<Patient> {
|
||||
|
||||
private static Long counter = 1L;
|
||||
|
||||
private static final ConcurrentHashMap<String, Patient> patients = new ConcurrentHashMap<>();
|
||||
|
||||
static {
|
||||
patients.put(String.valueOf(counter), createPatient("Van Houte"));
|
||||
patients.put(String.valueOf(counter), createPatient("Agnew"));
|
||||
for (int i = 0; i < 20; i++) {
|
||||
patients.put(String.valueOf(counter), createPatient("Random Patient " + counter));
|
||||
}
|
||||
}
|
||||
|
||||
public PatientResourceProvider(FhirContext fhirContext) {
|
||||
super(fhirContext);
|
||||
}
|
||||
|
||||
@Read
|
||||
public Patient find(@IdParam final IdType theId) {
|
||||
if (patients.containsKey(theId.getIdPart())) {
|
||||
return patients.get(theId.getIdPart());
|
||||
} else {
|
||||
throw new ResourceNotFoundException(theId);
|
||||
}
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome createPatient(@ResourceParam Patient patient) {
|
||||
|
||||
patient.setId(createId(counter, 1L));
|
||||
patients.put(String.valueOf(counter), patient);
|
||||
|
||||
return new MethodOutcome(patient.getIdElement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Patient> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
private static IdType createId(final Long id, final Long theVersionId) {
|
||||
return new IdType("Patient", "" + id, "" + theVersionId);
|
||||
}
|
||||
|
||||
private static Patient createPatient(final String name) {
|
||||
final Patient patient = new Patient();
|
||||
patient.getName().add(new HumanName().setFamily(name));
|
||||
patient.setId(createId(counter, 1L));
|
||||
counter++;
|
||||
return patient;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
hapi:
|
||||
fhir:
|
||||
version: dstu3
|
||||
server:
|
||||
path: /fhir/*
|
||||
rest:
|
||||
server-name: hapi-fhir-spring-boot-sample-server-jersey
|
||||
server-version: 1.0.0
|
||||
implementation-description: Spring Boot Jersey Server Sample
|
||||
default-response-encoding: json
|
||||
e-tag-support: enabled
|
||||
default-pretty-print: true
|
||||
validation:
|
||||
enabled: true
|
||||
request-only: true
|
||||
management:
|
||||
security:
|
||||
enabled: false
|
||||
logging:
|
||||
level:
|
||||
ca.uhn.fhir.jaxrs: debug
|
|
@ -0,0 +1,41 @@
|
|||
package sample.fhir.server.jersey;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class SampleJerseyRestfulServerApplicationTest {
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
public void metadata() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity(
|
||||
"/fhir/metadata",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"status\": \"active\"");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void patientResource() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity(
|
||||
"/fhir/Patient/1",
|
||||
String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("\"family\": \"Van Houte\"");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jpa</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jersey</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
</dependency>
|
||||
<!-- Optional -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,12 @@
|
|||
package sample.fhir.server.jpa;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleJpaRestfulServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleJpaRestfulServerApplication.class, args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
spring:
|
||||
jpa:
|
||||
hibernate:
|
||||
ddl-auto: create-drop
|
||||
properties:
|
||||
hibernate.jdbc.batch_size: 20
|
||||
hibernate.cache.use_query_cache: false
|
||||
hibernate.cache.use_second_level_cache: false
|
||||
hibernate.cache.use_structured_entries: false
|
||||
hibernate.cache.use_minimal_puts: false
|
||||
hibernate.search.default.directory_provider: filesystem
|
||||
hibernate.search.default.indexBase: target/lucenefiles
|
||||
hibernate.search.lucene_version: LUCENE_CURRENT
|
||||
hibernate.search.model_mapping: ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory
|
||||
|
||||
h2:
|
||||
console:
|
||||
enabled: true
|
||||
hapi:
|
||||
fhir:
|
||||
version: dstu3
|
||||
server:
|
||||
path: /fhir/*
|
||||
rest:
|
||||
server-name: hapi-fhir-spring-boot-sample-server-jpa
|
||||
server-version: 1.0.0
|
||||
implementation-description: Spring Boot Jpa Server Sample
|
||||
default-response-encoding: json
|
||||
e-tag-support: enabled
|
||||
default-pretty-print: true
|
||||
validation:
|
||||
enabled: true
|
||||
request-only: true
|
||||
jpa:
|
||||
scheduling-disabled: true
|
||||
subscription-enabled: false
|
||||
management:
|
||||
security:
|
||||
enabled: false
|
|
@ -0,0 +1,41 @@
|
|||
package sample.fhir.server.jpa;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.embedded.LocalServerPort;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
public class SampleJpaRestfulServerApplicationTest {
|
||||
|
||||
@Autowired
|
||||
FhirContext fhirContext;
|
||||
|
||||
@LocalServerPort
|
||||
int port;
|
||||
|
||||
@Test
|
||||
public void createAndRead() {
|
||||
IGenericClient client = fhirContext.newRestfulGenericClient("http://localhost:" + port + "/fhir");
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("Test");
|
||||
IIdType id = client.create().resource(patient).execute().getId();
|
||||
|
||||
System.out.println(id);
|
||||
|
||||
Patient result = client.read().resource(Patient.class).withId(id).execute();
|
||||
|
||||
System.out.println(result);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>hapi-fhir-spring-boot-sample-client-apache</module>
|
||||
<module>hapi-fhir-spring-boot-sample-client-okhttp</module>
|
||||
<module>hapi-fhir-spring-boot-sample-server-jersey</module>
|
||||
<module>hapi-fhir-spring-boot-sample-server-jpa</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,27 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-starter</artifactId>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-autoconfigure</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,21 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.1.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>hapi-fhir-spring-boot-autoconfigure</module>
|
||||
<module>hapi-fhir-spring-boot-starter</module>
|
||||
<module>hapi-fhir-spring-boot-samples</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
|
@ -1499,7 +1499,7 @@ public class JsonParserDstu2_1Test {
|
|||
|
||||
String val = ourCtx.newJsonParser().encodeResourceToString(patient);
|
||||
|
||||
String expected = "{\"resourceType\":\"Binary\",\"id\":\"11\",\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}";
|
||||
String expected = "{\"resourceType\":\"Binary\",\"id\":\"11\",\"meta\":{\"versionId\":\"22\"},\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}";
|
||||
ourLog.info("Expected: {}", expected);
|
||||
ourLog.info("Actual : {}", val);
|
||||
assertEquals(expected, val);
|
||||
|
|
|
@ -70,13 +70,6 @@
|
|||
<skipUpdateLicense>true</skipUpdateLicense>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -1,13 +1,8 @@
|
|||
package ca.uhn.fhir.context;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
|
||||
import ca.uhn.fhir.util.OperationOutcomeUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Reference;
|
||||
|
@ -15,19 +10,21 @@ import org.hl7.fhir.dstu3.model.StructureDefinition;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.rest.client.MyPatientWithExtensions;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class FhirContextDstu3Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirContextDstu3Test.class);
|
||||
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test
|
||||
public void testAutoDetectVersion() {
|
||||
|
@ -35,6 +32,17 @@ public class FhirContextDstu3Test {
|
|||
assertEquals(FhirVersionEnum.DSTU3, ctx.getVersion().getVersion());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomTypeDoesntBecomeDefault() {
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
|
||||
MyPatientWithExtensions pt = new MyPatientWithExtensions();
|
||||
pt.addName().addGiven("FOO");
|
||||
ctx.newXmlParser().encodeResourceToString(pt);
|
||||
|
||||
assertEquals(Patient.class, ctx.getResourceDefinition("Patient").getImplementingClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #344
|
||||
*/
|
||||
|
@ -56,37 +64,6 @@ public class FhirContextDstu3Test {
|
|||
assertEquals(StructureDefinition.class, ourCtx.getResourceDefinition("structuredefinition").getImplementingClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomTypeDoesntBecomeDefault() {
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
|
||||
MyPatientWithExtensions pt = new MyPatientWithExtensions();
|
||||
pt.addName().addGiven("FOO");
|
||||
ctx.newXmlParser().encodeResourceToString(pt);
|
||||
|
||||
assertEquals(Patient.class, ctx.getResourceDefinition("Patient").getImplementingClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryBoundCode() {
|
||||
RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class);
|
||||
String childName = "gender";
|
||||
BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName);
|
||||
ourLog.trace(genderChild.getClass().getName());
|
||||
|
||||
assertEquals(AdministrativeGender.class, genderChild.getBoundEnumType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryNonBoundCode() {
|
||||
RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class);
|
||||
String childName = "name";
|
||||
BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName);
|
||||
ourLog.trace(genderChild.getClass().getName());
|
||||
|
||||
assertEquals(null, genderChild.getBoundEnumType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialisationThreadSafety() {
|
||||
final FhirContext ctx = FhirContext.forDstu3();
|
||||
|
@ -126,4 +103,54 @@ public class FhirContextDstu3Test {
|
|||
|
||||
assertTrue("failed with exception(s): " + exceptions, exceptions.isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #794
|
||||
*/
|
||||
@Test
|
||||
public void testInitializeThreadSafety2() throws InterruptedException {
|
||||
final FhirContext dstu3FhirContext = FhirContext.forDstu3();
|
||||
|
||||
final AtomicInteger count = new AtomicInteger();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
OperationOutcomeUtil.newInstance(dstu3FhirContext);
|
||||
ourLog.info("Have finished {}", count.incrementAndGet());
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
TestUtil.waitForSize(10, count);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryBoundCode() {
|
||||
RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class);
|
||||
String childName = "gender";
|
||||
BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName);
|
||||
ourLog.trace(genderChild.getClass().getName());
|
||||
|
||||
assertEquals(AdministrativeGender.class, genderChild.getBoundEnumType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueryNonBoundCode() {
|
||||
RuntimeResourceDefinition patientType = ourCtx.getResourceDefinition(Patient.class);
|
||||
String childName = "name";
|
||||
BaseRuntimeChildDatatypeDefinition genderChild = (BaseRuntimeChildDatatypeDefinition) patientType.getChildByName(childName);
|
||||
ourLog.trace(genderChild.getClass().getName());
|
||||
|
||||
assertEquals(null, genderChild.getBoundEnumType());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,41 +1,26 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.FooMessageHeaderWithExplicitField.FooMessageSourceComponent;
|
||||
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||
import ca.uhn.fhir.parser.PatientWithCustomCompositeExtension.FooParentExtension;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hamcrest.collection.IsEmptyCollection;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hamcrest.text.StringContainsInOrder;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUse;
|
||||
import org.hl7.fhir.dstu3.model.Address.AddressUseEnumFactory;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.*;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.dstu3.model.ContactPoint.ContactPointSystem;
|
||||
import org.hl7.fhir.dstu3.model.DiagnosticReport.DiagnosticReportStatus;
|
||||
import org.hl7.fhir.dstu3.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||
|
@ -52,27 +37,27 @@ import org.junit.*;
|
|||
import org.mockito.ArgumentCaptor;
|
||||
import org.xmlunit.builder.DiffBuilder;
|
||||
import org.xmlunit.builder.Input;
|
||||
import org.xmlunit.diff.*;
|
||||
import org.xmlunit.diff.ComparisonControllers;
|
||||
import org.xmlunit.diff.DefaultNodeMatcher;
|
||||
import org.xmlunit.diff.Diff;
|
||||
import org.xmlunit.diff.ElementSelectors;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.FooMessageHeaderWithExplicitField.FooMessageSourceComponent;
|
||||
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
|
||||
import ca.uhn.fhir.parser.PatientWithCustomCompositeExtension.FooParentExtension;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||
import ca.uhn.fhir.validation.ValidationContext;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class XmlParserDstu3Test {
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu3Test.class);
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
|
@ -83,21 +68,24 @@ public class XmlParserDstu3Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryWithSecurityContext() {
|
||||
Binary bin = new Binary();
|
||||
bin.setContentType("text/plain");
|
||||
bin.setContent("Now is the time".getBytes());
|
||||
Reference securityContext = new Reference();
|
||||
securityContext.setReference("DiagnosticReport/1");
|
||||
bin.setSecurityContext(securityContext);
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(bin);
|
||||
ourLog.info(encoded);
|
||||
assertThat(encoded, containsString("Binary"));
|
||||
assertThat(encoded, containsString("<contentType value=\"text/plain\"/>"));
|
||||
assertThat(encoded, containsString("<securityContext><reference value=\"DiagnosticReport/1\"/></securityContext>"));
|
||||
assertThat(encoded, containsString("<content value=\"Tm93IGlzIHRoZSB0aW1l\"/>"));
|
||||
}
|
||||
public void testBaseUrlFooResourceCorrectlySerializedInExtensionValueReference() {
|
||||
String refVal = "http://my.org/FooBar";
|
||||
|
||||
Patient fhirPat = new Patient();
|
||||
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
|
||||
String output = parser.encodeResourceToString(fhirPat);
|
||||
System.out.println("output: " + output);
|
||||
|
||||
// Deserialize then check that valueReference value is still correct
|
||||
fhirPat = parser.parseResource(Patient.class, output);
|
||||
|
||||
List<Extension> extlst = fhirPat.getExtensionsByUrl("x1");
|
||||
Assert.assertEquals(1, extlst.size());
|
||||
Assert.assertEquals(refVal, ((Reference) extlst.get(0).getValue()).getReference());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #544
|
||||
|
@ -977,6 +965,22 @@ public class XmlParserDstu3Test {
|
|||
assertEquals("<Binary xmlns=\"http://hl7.org/fhir\"><content value=\"AQIDBA==\"/></Binary>", output);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBinaryWithSecurityContext() {
|
||||
Binary bin = new Binary();
|
||||
bin.setContentType("text/plain");
|
||||
bin.setContent("Now is the time".getBytes());
|
||||
Reference securityContext = new Reference();
|
||||
securityContext.setReference("DiagnosticReport/1");
|
||||
bin.setSecurityContext(securityContext);
|
||||
String encoded = ourCtx.newXmlParser().encodeResourceToString(bin);
|
||||
ourLog.info(encoded);
|
||||
assertThat(encoded, containsString("Binary"));
|
||||
assertThat(encoded, containsString("<contentType value=\"text/plain\"/>"));
|
||||
assertThat(encoded, containsString("<securityContext><reference value=\"DiagnosticReport/1\"/></securityContext>"));
|
||||
assertThat(encoded, containsString("<content value=\"Tm93IGlzIHRoZSB0aW1l\"/>"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeBundleWithContained() {
|
||||
DiagnosticReport rpt = new DiagnosticReport();
|
||||
|
@ -1872,7 +1876,7 @@ public class XmlParserDstu3Test {
|
|||
|
||||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name", "Bundle.entry")));
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Patient.name", "Bundle.entry")));
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
|
@ -1908,6 +1912,31 @@ public class XmlParserDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithEncodeElementsAppliesToChildResourcesOnly() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
patient.getMeta().addProfile("http://profile");
|
||||
patient.addName().setFamily("FAMILY");
|
||||
patient.addAddress().addLine("LINE1");
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setTotal(100);
|
||||
bundle.addEntry().setResource(patient);
|
||||
|
||||
{
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
p.setEncodeElements(new HashSet<>(Arrays.asList("Patient.name")));
|
||||
p.setEncodeElementsAppliesToChildResourcesOnly(true);
|
||||
p.setPrettyPrint(true);
|
||||
String out = p.encodeResourceToString(bundle);
|
||||
ourLog.info(out);
|
||||
assertThat(out, containsString("total"));
|
||||
assertThat(out, containsString("Patient"));
|
||||
assertThat(out, containsString("name"));
|
||||
assertThat(out, not(containsString("address")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeWithNarrative() {
|
||||
Patient p = new Patient();
|
||||
|
@ -2835,7 +2864,7 @@ public class XmlParserDstu3Test {
|
|||
|
||||
/**
|
||||
* See #426
|
||||
*
|
||||
* <p>
|
||||
* Value type of FOO isn't a valid datatype
|
||||
*/
|
||||
@Test
|
||||
|
@ -2934,6 +2963,30 @@ public class XmlParserDstu3Test {
|
|||
assertEquals("value", capt.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMetaUpdatedDate() {
|
||||
|
||||
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <id value=\"e2ee823b-ee4d-472d-b79d-495c23f16b99\"/>\n" +
|
||||
" <meta>\n" +
|
||||
" <lastUpdated value=\"2015-06-22T15:48:57.554-04:00\"/>\n" +
|
||||
" </meta>\n" +
|
||||
" <type value=\"searchset\"/>\n" +
|
||||
" <base value=\"http://localhost:58109/fhir/context\"/>\n" +
|
||||
" <total value=\"0\"/>\n" +
|
||||
" <link>\n" +
|
||||
" <relation value=\"self\"/>\n" +
|
||||
" <url value=\"http://localhost:58109/fhir/context/Patient?_pretty=true\"/>\n" +
|
||||
" </link>\n" +
|
||||
"</Bundle>";
|
||||
|
||||
Bundle b = ourCtx.newXmlParser().parseResource(Bundle.class, input);
|
||||
|
||||
InstantType updated = b.getMeta().getLastUpdatedElement();
|
||||
assertEquals("2015-06-22T15:48:57.554-04:00", updated.getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMetadata() throws Exception {
|
||||
|
||||
|
@ -2987,43 +3040,6 @@ public class XmlParserDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
public static void compareXml(String content, String reEncoded) {
|
||||
Diff d = DiffBuilder.compare(Input.fromString(content))
|
||||
.withTest(Input.fromString(reEncoded))
|
||||
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
|
||||
.checkForSimilar()
|
||||
.ignoreWhitespace() // this is working with newest Saxon 9.8.0-2 (not worked with 9.7.0-15
|
||||
.ignoreComments() // this is not working even with newest Saxon 9.8.0-2
|
||||
.withComparisonController(ComparisonControllers.Default)
|
||||
.build();
|
||||
|
||||
assertTrue(d.toString(), !d.hasDifferences());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMetaUpdatedDate() {
|
||||
|
||||
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <id value=\"e2ee823b-ee4d-472d-b79d-495c23f16b99\"/>\n" +
|
||||
" <meta>\n" +
|
||||
" <lastUpdated value=\"2015-06-22T15:48:57.554-04:00\"/>\n" +
|
||||
" </meta>\n" +
|
||||
" <type value=\"searchset\"/>\n" +
|
||||
" <base value=\"http://localhost:58109/fhir/context\"/>\n" +
|
||||
" <total value=\"0\"/>\n" +
|
||||
" <link>\n" +
|
||||
" <relation value=\"self\"/>\n" +
|
||||
" <url value=\"http://localhost:58109/fhir/context/Patient?_pretty=true\"/>\n" +
|
||||
" </link>\n" +
|
||||
"</Bundle>";
|
||||
|
||||
Bundle b = ourCtx.newXmlParser().parseResource(Bundle.class, input);
|
||||
|
||||
InstantType updated = b.getMeta().getLastUpdatedElement();
|
||||
assertEquals("2015-06-22T15:48:57.554-04:00", updated.getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
// TODO: this should work
|
||||
@Test
|
||||
@Ignore
|
||||
|
@ -3094,40 +3110,6 @@ public class XmlParserDstu3Test {
|
|||
assertEquals("Patient", reincarnatedPatient.getIdElement().getResourceType());
|
||||
}
|
||||
|
||||
/**
|
||||
* See #344
|
||||
*/
|
||||
@Test
|
||||
public void testParserIsCaseSensitive() {
|
||||
Observation obs = new Observation();
|
||||
SampledData data = new SampledData();
|
||||
data.setData("1 2 3");
|
||||
data.setOrigin((SimpleQuantity) new SimpleQuantity().setValue(0L));
|
||||
data.setPeriod(1000L);
|
||||
obs.setValue(data);
|
||||
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true).setParserErrorHandler(new StrictErrorHandler());
|
||||
String encoded = p.encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
p.parseResource(encoded);
|
||||
|
||||
try {
|
||||
p.parseResource(encoded.replace("Observation", "observation"));
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("DataFormatException at [[row,col {unknown-source}]: [1,1]]: Unknown resource type 'observation': Resource names are case sensitive, found similar name: 'Observation'",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
p.parseResource(encoded.replace("valueSampledData", "valueSampleddata"));
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Unknown element 'valueSampleddata' found during parse", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = DataFormatException.class)
|
||||
public void testParseWithInvalidLocalRef() throws IOException {
|
||||
String string = IOUtils.toString(getClass().getResourceAsStream("/bundle_with_invalid_contained_ref.xml"), StandardCharsets.UTF_8);
|
||||
|
@ -3226,6 +3208,40 @@ public class XmlParserDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #344
|
||||
*/
|
||||
@Test
|
||||
public void testParserIsCaseSensitive() {
|
||||
Observation obs = new Observation();
|
||||
SampledData data = new SampledData();
|
||||
data.setData("1 2 3");
|
||||
data.setOrigin((SimpleQuantity) new SimpleQuantity().setValue(0L));
|
||||
data.setPeriod(1000L);
|
||||
obs.setValue(data);
|
||||
|
||||
IParser p = ourCtx.newXmlParser().setPrettyPrint(true).setParserErrorHandler(new StrictErrorHandler());
|
||||
String encoded = p.encodeResourceToString(obs);
|
||||
ourLog.info(encoded);
|
||||
|
||||
p.parseResource(encoded);
|
||||
|
||||
try {
|
||||
p.parseResource(encoded.replace("Observation", "observation"));
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("DataFormatException at [[row,col {unknown-source}]: [1,1]]: Unknown resource type 'observation': Resource names are case sensitive, found similar name: 'Observation'",
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
p.parseResource(encoded.replace("valueSampledData", "valueSampleddata"));
|
||||
fail();
|
||||
} catch (DataFormatException e) {
|
||||
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Unknown element 'valueSampleddata' found during parse", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See #551
|
||||
*/
|
||||
|
@ -3245,7 +3261,7 @@ public class XmlParserDstu3Test {
|
|||
|
||||
/**
|
||||
* See #339
|
||||
*
|
||||
* <p>
|
||||
* https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing
|
||||
*/
|
||||
@Test
|
||||
|
@ -3275,35 +3291,22 @@ public class XmlParserDstu3Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBaseUrlFooResourceCorrectlySerializedInExtensionValueReference() {
|
||||
String refVal = "http://my.org/FooBar";
|
||||
|
||||
Patient fhirPat = new Patient();
|
||||
fhirPat.addExtension().setUrl("x1").setValue(new Reference(refVal));
|
||||
|
||||
IParser parser = ourCtx.newXmlParser();
|
||||
|
||||
String output = parser.encodeResourceToString(fhirPat);
|
||||
System.out.println("output: " + output);
|
||||
|
||||
// Deserialize then check that valueReference value is still correct
|
||||
fhirPat = parser.parseResource(Patient.class, output);
|
||||
|
||||
List<Extension> extlst = fhirPat.getExtensionsByUrl("x1");
|
||||
Assert.assertEquals(1, extlst.size());
|
||||
Assert.assertEquals(refVal, ((Reference) extlst.get(0).getValue()).getReference());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
IGenericClient c = ourCtx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
|
||||
// c.registerInterceptor(new LoggingInterceptor(true));
|
||||
c.read().resource("Patient").withId("324").execute();
|
||||
public static void compareXml(String content, String reEncoded) {
|
||||
Diff d = DiffBuilder.compare(Input.fromString(content))
|
||||
.withTest(Input.fromString(reEncoded))
|
||||
.withNodeMatcher(new DefaultNodeMatcher(ElementSelectors.byNameAndText))
|
||||
.checkForSimilar()
|
||||
.ignoreWhitespace() // this is working with newest Saxon 9.8.0-2 (not worked with 9.7.0-15
|
||||
.ignoreComments() // this is not working even with newest Saxon 9.8.0-2
|
||||
.withComparisonController(ComparisonControllers.Default)
|
||||
.build();
|
||||
|
||||
assertTrue(d.toString(), !d.hasDifferences());
|
||||
}
|
||||
|
||||
@ResourceDef(name = "Patient")
|
||||
|
|
|
@ -1,32 +1,5 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
|
@ -38,15 +11,46 @@ import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
|||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.*;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.HumanName;
|
||||
import org.hl7.fhir.r4.model.OperationOutcome;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SearchR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchR4Test.class);
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
private static TokenAndListParam ourIdentifiers;
|
||||
private static String ourLastMethod;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchR4Test.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
|
@ -57,74 +61,63 @@ public class SearchR4Test {
|
|||
ourIdentifiers = null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNormal() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
|
||||
private Bundle executeAndReturnLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException, ClientProtocolException {
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
Bundle bundle;
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
|
||||
assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
EncodingEnum ct = EncodingEnum.forContentType(status.getEntity().getContentType().getValue().replaceAll(";.*", "").trim());
|
||||
assertEquals(theExpectEncoding, ct);
|
||||
bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent);
|
||||
assertEquals(10, bundle.getEntry().size());
|
||||
String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertNotNull(linkNext);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithInvalidChain() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) ourCtx.newJsonParser().parseResource(responseContent);
|
||||
assertEquals(
|
||||
"Invalid search parameter \"identifier.chain\". Parameter contains a chain (.chain) and chains are not supported for this parameter (chaining is only allowed on reference parameters)",
|
||||
oo.getIssueFirstRep().getDiagnostics());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingJson() throws Exception {
|
||||
public void testPagingPreservesElements() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
String linkSelf;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=json");
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_elements=name");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
linkSelf = bundle.getLink(Constants.LINK_SELF).getUrl();
|
||||
assertThat(linkSelf, containsString("_elements=name"));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
|
||||
ourLog.info(toJson(bundle));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("active")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
|
||||
}
|
||||
|
||||
|
@ -161,34 +154,35 @@ public class SearchR4Test {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testPagingPreservesEncodingXml() throws Exception {
|
||||
public void testPagingPreservesEncodingJson() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=xml");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=json");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), containsString("active"));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
assertThat(linkNext, containsString("_format=json"));
|
||||
|
||||
}
|
||||
|
||||
|
@ -260,25 +254,75 @@ public class SearchR4Test {
|
|||
|
||||
}
|
||||
|
||||
private Bundle executeAndReturnLinkNext(HttpGet httpGet, EncodingEnum theExpectEncoding) throws IOException, ClientProtocolException {
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
@Test
|
||||
public void testPagingPreservesEncodingXml() throws Exception {
|
||||
HttpGet httpGet;
|
||||
String linkNext;
|
||||
Bundle bundle;
|
||||
|
||||
// Initial search
|
||||
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_format=xml");
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
// Fetch the next page
|
||||
httpGet = new HttpGet(linkNext);
|
||||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.XML);
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_format=xml"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchNormal() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
EncodingEnum ct = EncodingEnum.forContentType(status.getEntity().getContentType().getValue().replaceAll(";.*", "").trim());
|
||||
assertEquals(theExpectEncoding, ct);
|
||||
bundle = ct.newParser(ourCtx).parseResource(Bundle.class, responseContent);
|
||||
assertEquals(10, bundle.getEntry().size());
|
||||
String linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertNotNull(linkNext);
|
||||
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
|
||||
assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
return bundle;
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithInvalidChain() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier.chain=foo%7Cbar");
|
||||
CloseableHttpResponse status = ourClient.execute(httpGet);
|
||||
try {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
assertEquals(400, status.getStatusLine().getStatusCode());
|
||||
|
||||
OperationOutcome oo = (OperationOutcome) ourCtx.newJsonParser().parseResource(responseContent);
|
||||
assertEquals(
|
||||
"Invalid search parameter \"identifier.chain\". Parameter contains a chain (.chain) and chains are not supported for this parameter (chaining is only allowed on reference parameters)",
|
||||
oo.getIssueFirstRep().getDiagnostics());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithPostAndInvalidParameters() throws Exception {
|
||||
|
@ -308,6 +352,10 @@ public class SearchR4Test {
|
|||
|
||||
}
|
||||
|
||||
private String toJson(Bundle theBundle) {
|
||||
return ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theBundle);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
|
@ -357,8 +405,9 @@ public class SearchR4Test {
|
|||
for (int i = 0; i < 200; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||
patient.setActive(true);
|
||||
patient.getIdElement().setValue("Patient/" + i);
|
||||
retVal.add((Patient) patient);
|
||||
retVal.add(patient);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
23
pom.xml
23
pom.xml
|
@ -370,6 +370,14 @@
|
|||
<id>malcolmm83</id>
|
||||
<name>Malcolm McRoberts</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>mouellet</id>
|
||||
<name>Mathieu Ouellet</name>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>JiajingLiang</id>
|
||||
<name>Jiajing Liang</name>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<licenses>
|
||||
|
@ -403,6 +411,7 @@
|
|||
<phloc_schematron_version>2.7.1</phloc_schematron_version>
|
||||
<phloc_commons_version>4.4.11</phloc_commons_version>
|
||||
<spring_version>5.0.0.RELEASE</spring_version>
|
||||
<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
|
||||
<thymeleaf-version>3.0.7.RELEASE</thymeleaf-version>
|
||||
|
||||
<!-- We are aiming to still work on a very old version of SLF4j even though we depend on the newest, just to be nice to users of the API. This version is tested in the hapi-fhir-cobertura. -->
|
||||
|
@ -970,6 +979,13 @@
|
|||
<artifactId>spring-websocket</artifactId>
|
||||
<version>${spring_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-dependencies</artifactId>
|
||||
<version>${spring-boot.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf</groupId>
|
||||
<artifactId>thymeleaf</artifactId>
|
||||
|
@ -1032,7 +1048,7 @@
|
|||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>1.7</source>
|
||||
<target>1.7</target>
|
||||
|
@ -1045,6 +1061,10 @@
|
|||
<testTarget>1.8</testTarget>
|
||||
<forceJavacCompilerUse>true</forceJavacCompilerUse>
|
||||
<encoding>UTF-8</encoding>
|
||||
|
||||
<fork>true</fork>
|
||||
<meminitial>128m</meminitial>
|
||||
<maxmem>1600m</maxmem>
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
@ -1880,6 +1900,7 @@
|
|||
<module>example-projects/hapi-fhir-standalone-overlay-example</module>
|
||||
<module>hapi-fhir-jacoco</module>
|
||||
<module>hapi-fhir-igpacks</module>
|
||||
<module>hapi-fhir-spring-boot</module>
|
||||
<!--<module>hapi-fhir-osgi-core</module>-->
|
||||
</modules>
|
||||
</profile>
|
||||
|
|
|
@ -154,7 +154,7 @@
|
|||
JAX-RS client framework now supports the ability to
|
||||
register your own JAX-RS Component Classes against the client,
|
||||
as well as better documentation about thread safety. Thanks
|
||||
to Sébastien Rivière for the pull request!
|
||||
to Sébastien Rivière for the pull request!
|
||||
</action>
|
||||
<action type="fix" issue="717">
|
||||
Processing of the If-Modified-Since header on FHIR read operations was reversed,
|
||||
|
@ -175,11 +175,43 @@
|
|||
was not encoded correctly. Thanks to Malcolm McRoberts for the pull
|
||||
request with fix and test case!
|
||||
</action>
|
||||
<action type="add">
|
||||
Bundle resources did not have their version encoded when serializing
|
||||
in FHIR resource (XML/JSON) format.
|
||||
</action>
|
||||
<action type="add">
|
||||
The Binary resource endpoint now supports the `X-Security-Context` header when
|
||||
reading or writing Binary contents using their native Content-Type (i.e exchanging
|
||||
the raw binary with the server, as opposed to exchanging a FHIR resource).
|
||||
</action>
|
||||
<action type="fix">
|
||||
When paging through multiple pages of search results, if the
|
||||
client had requested a subset of resources to be returned using the
|
||||
<![CDATA[<code>_elements</code>]]> parameter, the elements list
|
||||
was lost after the first page of results.
|
||||
In addition, elements will not remove elements from
|
||||
search/history Bundles (i.e. elements from the Bundle itself, as opposed
|
||||
to elements in the entry resources) unless the Bundle elements are
|
||||
explicitly listed, e.g. <![CDATA[<code>_include=Bundle.total</code>]]>.
|
||||
Thanks to @parisni for reporting!
|
||||
</action>
|
||||
<action type="add" issue="743">
|
||||
Add support for Spring Boot for initializing a number of parts of the library,
|
||||
as well as several examples.
|
||||
Thanks to Mathieu Ouellet for the contribution!
|
||||
</action>
|
||||
<action type="add" issue="747">
|
||||
JPA server now has lucene index support moved to separate classes from the entity
|
||||
classes in order to facilitate support for ElasticSearch. Thanks to Jiang Liang
|
||||
for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="755">
|
||||
A new client interceptor has been added called
|
||||
AdditionalRequestHeadersInterceptor, which allows
|
||||
a developer to add additional custom headers to a
|
||||
client requests.
|
||||
Thanks to Clayton Bodendein for the pull request!
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.0.0" date="2017-09-27">
|
||||
<action type="add">
|
||||
|
@ -545,7 +577,7 @@ Bundle bundle = client.search().forResource(Patient.class)
|
|||
<action type="fix" issue="686">
|
||||
Correct an issue in the validator (DSTU3/R4) where elements were not always
|
||||
correctly validated if the element contained only a profiled extension. Thanks
|
||||
to Sébastien Rivière for the pull request!
|
||||
to Sébastien Rivière for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="701">
|
||||
Testing UI now has a dropdown for modifiers on token search. Thanks
|
||||
|
@ -559,7 +591,7 @@ Bundle bundle = client.search().forResource(Patient.class)
|
|||
</action>
|
||||
<action type="fix" issue="695">
|
||||
Extensions on ID datatypes were not parsed or serialized correctly. Thanks to
|
||||
Stephen Rivière for the pull request!
|
||||
Stephen Rivière for the pull request!
|
||||
</action>
|
||||
<action type="fix" issue="710">
|
||||
Fix a bug in REST Hook Subscription interceptors which prevented subscriptions
|
||||
|
@ -880,7 +912,7 @@ Bundle bundle = client.search().forResource(Patient.class)
|
|||
<action type="add">
|
||||
DaoConfig#setAllowInlineMatchUrlReferences() now defaults to
|
||||
<![CDATA[<code>true</code>]]> since inline conditional references
|
||||
are now a part of the FHIR specification. Thanks to Jan Dědek for
|
||||
are now a part of the FHIR specification. Thanks to Jan DÄdek for
|
||||
pointing this out!
|
||||
</action>
|
||||
<action type="add" issue="609">
|
||||
|
@ -1860,7 +1892,7 @@ Bundle bundle = client.search().forResource(Patient.class)
|
|||
</action>
|
||||
<action type="fix" issue="426">
|
||||
Parser failed to parse resources containing an extension with a value type of
|
||||
"id". Thanks to Raphael Mäder for reporting!
|
||||
"id". Thanks to Raphael Mäder for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
When committing a transaction in JPA server
|
||||
|
@ -2122,7 +2154,7 @@ Bundle bundle = client.search().forResource(Patient.class)
|
|||
array instead of a string. Thanks to David Hay for reporting!
|
||||
</action>
|
||||
<action type="add" issue="367">
|
||||
Sébastien Rivière contributed an excellent pull request which adds a
|
||||
Sébastien Rivière contributed an excellent pull request which adds a
|
||||
number of enhancements to JAX-RS module:
|
||||
<![CDATA[
|
||||
<ul>
|
||||
|
|
Loading…
Reference in New Issue