Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2016-06-20 10:53:43 -04:00
commit 89f3df80a4
98 changed files with 2756 additions and 2107 deletions

View File

@ -354,11 +354,6 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
RuntimeChildChoiceDefinition def = new RuntimeChildChoiceDefinition(next, elementName, childAnnotation, descriptionAnnotation, choiceTypes);
orderMap.put(order, def);
} else if (next.getType().equals(ExtensionDt.class)) {
RuntimeChildExtensionDt def = new RuntimeChildExtensionDt(next, elementName, childAnnotation, descriptionAnnotation);
orderMap.put(order, def);
} else if (extensionAttr != null) {
/*
* Child is an extension
@ -427,8 +422,6 @@ public abstract class BaseRuntimeElementCompositeDefinition<T extends IBase> ext
} else {
def = new RuntimeChildPrimitiveDatatypeDefinition(next, elementName, descriptionAnnotation, childAnnotation, nextDatatype);
}
} else if (IBaseXhtml.class.isAssignableFrom(nextElementType)) {
def = new RuntimeChildXhtmlDatatypeDefinition(next, elementName, descriptionAnnotation, childAnnotation, nextDatatype);
} else {
if (IBoundCodeableConcept.class.isAssignableFrom(nextElementType)) {
IValueSetEnumBinder<Enum<?>> binder = ModelScanner.getBoundCodeBinder(next);

View File

@ -44,6 +44,7 @@ import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
@ -574,6 +575,8 @@ class ModelScanner {
}
} catch (IOException e) {
throw new ConfigurationException("Failed to load model property file from classpath: " + "/ca/uhn/fhir/model/dstu/model.properties");
} finally {
IOUtils.closeQuietly(str);
}
return retVal;

View File

@ -1,40 +0,0 @@
package ca.uhn.fhir.context;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Field;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
public class RuntimeChildExtensionDt extends RuntimeChildAny {
public RuntimeChildExtensionDt(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation) {
super(theField, theElementName, theChildAnnotation, theDescriptionAnnotation);
}
public IElement newInstance() {
return new ExtensionDt();
}
}

View File

@ -1,40 +0,0 @@
package ca.uhn.fhir.context;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Field;
import org.hl7.fhir.instance.model.api.IBase;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
/**
* HL7org XHTML type
*/
public class RuntimeChildXhtmlDatatypeDefinition extends RuntimeChildPrimitiveDatatypeDefinition {
public RuntimeChildXhtmlDatatypeDefinition(Field theField, String theElementName, Description theDescriptionAnnotation, Child theChildAnnotation, Class<? extends IBase> theDatatype) {
super(theField, theElementName, theDescriptionAnnotation, theChildAnnotation, theDatatype);
}
}

View File

@ -1,45 +0,0 @@
package ca.uhn.fhir.model.api;
import ca.uhn.fhir.util.CoverageIgnore;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
/**
* Represents a FHIR resource path specification, e.g.
* <code>Patient.gender.coding</code>
* <p>
* Note on equality: This class uses the {@link PathSpecification#setValue(String) value}
* as the single item used to provide {@link #hashCode()} and {@link #equals(Object)}.
* </p>
*
* @deprecated {@link Include} should be used instead
*/
@CoverageIgnore
@Deprecated
public class PathSpecification extends Include {
public PathSpecification(String theInclude) {
super(theInclude);
}
}

View File

@ -1,125 +0,0 @@
package ca.uhn.fhir.model.dstu.valueset;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.util.CoverageIgnore;
@CoverageIgnore
public enum SecurityEventObjectSensitivityEnum {
;
/**
* Identifier for this Value Set:
* http://hl7.org/fhir/vs/security-event-sensitivity
*/
public static final String VALUESET_IDENTIFIER = "http://hl7.org/fhir/vs/security-event-sensitivity";
/**
* Name for this Value Set:
* Security Event Object Sensitivity
*/
public static final String VALUESET_NAME = "Security Event Object Sensitivity";
private static Map<String, SecurityEventObjectSensitivityEnum> CODE_TO_ENUM = new HashMap<String, SecurityEventObjectSensitivityEnum>();
private static Map<String, Map<String, SecurityEventObjectSensitivityEnum>> SYSTEM_TO_CODE_TO_ENUM = new HashMap<String, Map<String, SecurityEventObjectSensitivityEnum>>();
private final String myCode;
private final String mySystem;
static {
for (SecurityEventObjectSensitivityEnum next : SecurityEventObjectSensitivityEnum.values()) {
CODE_TO_ENUM.put(next.getCode(), next);
if (!SYSTEM_TO_CODE_TO_ENUM.containsKey(next.getSystem())) {
SYSTEM_TO_CODE_TO_ENUM.put(next.getSystem(), new HashMap<String, SecurityEventObjectSensitivityEnum>());
}
SYSTEM_TO_CODE_TO_ENUM.get(next.getSystem()).put(next.getCode(), next);
}
}
/**
* Returns the code associated with this enumerated value
*/
public String getCode() {
return myCode;
}
/**
* Returns the code system associated with this enumerated value
*/
public String getSystem() {
return mySystem;
}
/**
* Returns the enumerated value associated with this code
*/
public SecurityEventObjectSensitivityEnum forCode(String theCode) {
SecurityEventObjectSensitivityEnum retVal = CODE_TO_ENUM.get(theCode);
return retVal;
}
/**
* Converts codes to their respective enumerated values
*/
public static final IValueSetEnumBinder<SecurityEventObjectSensitivityEnum> VALUESET_BINDER = new IValueSetEnumBinder<SecurityEventObjectSensitivityEnum>() {
@Override
public String toCodeString(SecurityEventObjectSensitivityEnum theEnum) {
return theEnum.getCode();
}
@Override
public String toSystemString(SecurityEventObjectSensitivityEnum theEnum) {
return theEnum.getSystem();
}
@Override
public SecurityEventObjectSensitivityEnum fromCodeString(String theCodeString) {
return CODE_TO_ENUM.get(theCodeString);
}
@Override
public SecurityEventObjectSensitivityEnum fromCodeString(String theCodeString, String theSystemString) {
Map<String, SecurityEventObjectSensitivityEnum> map = SYSTEM_TO_CODE_TO_ENUM.get(theSystemString);
if (map == null) {
return null;
}
return map.get(theCodeString);
}
};
/**
* Constructor
*/
SecurityEventObjectSensitivityEnum(String theCode, String theSystem) {
myCode = theCode;
mySystem = theSystem;
}
}

View File

@ -1,153 +0,0 @@
package ca.uhn.fhir.model.dstu.valueset;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.util.CoverageIgnore;
@CoverageIgnore
public enum SecurityEventObjectTypeEnum {
/**
* Code Value: <b>1</b>
*
* Person.
*/
PERSON("1", "http://hl7.org/fhir/object-type"),
/**
* Code Value: <b>2</b>
*
* System Object.
*/
SYSTEM_OBJECT("2", "http://hl7.org/fhir/object-type"),
/**
* Code Value: <b>3</b>
*
* Organization.
*/
ORGANIZATION("3", "http://hl7.org/fhir/object-type"),
/**
* Code Value: <b>4</b>
*
* Other.
*/
OTHER("4", "http://hl7.org/fhir/object-type"),
;
/**
* Identifier for this Value Set:
* http://hl7.org/fhir/vs/object-type
*/
public static final String VALUESET_IDENTIFIER = "http://hl7.org/fhir/vs/object-type";
/**
* Name for this Value Set:
* SecurityEventObjectType
*/
public static final String VALUESET_NAME = "SecurityEventObjectType";
private static Map<String, SecurityEventObjectTypeEnum> CODE_TO_ENUM = new HashMap<String, SecurityEventObjectTypeEnum>();
private static Map<String, Map<String, SecurityEventObjectTypeEnum>> SYSTEM_TO_CODE_TO_ENUM = new HashMap<String, Map<String, SecurityEventObjectTypeEnum>>();
private final String myCode;
private final String mySystem;
static {
for (SecurityEventObjectTypeEnum next : SecurityEventObjectTypeEnum.values()) {
CODE_TO_ENUM.put(next.getCode(), next);
if (!SYSTEM_TO_CODE_TO_ENUM.containsKey(next.getSystem())) {
SYSTEM_TO_CODE_TO_ENUM.put(next.getSystem(), new HashMap<String, SecurityEventObjectTypeEnum>());
}
SYSTEM_TO_CODE_TO_ENUM.get(next.getSystem()).put(next.getCode(), next);
}
}
/**
* Returns the code associated with this enumerated value
*/
public String getCode() {
return myCode;
}
/**
* Returns the code system associated with this enumerated value
*/
public String getSystem() {
return mySystem;
}
/**
* Returns the enumerated value associated with this code
*/
public SecurityEventObjectTypeEnum forCode(String theCode) {
SecurityEventObjectTypeEnum retVal = CODE_TO_ENUM.get(theCode);
return retVal;
}
/**
* Converts codes to their respective enumerated values
*/
public static final IValueSetEnumBinder<SecurityEventObjectTypeEnum> VALUESET_BINDER = new IValueSetEnumBinder<SecurityEventObjectTypeEnum>() {
@Override
public String toCodeString(SecurityEventObjectTypeEnum theEnum) {
return theEnum.getCode();
}
@Override
public String toSystemString(SecurityEventObjectTypeEnum theEnum) {
return theEnum.getSystem();
}
@Override
public SecurityEventObjectTypeEnum fromCodeString(String theCodeString) {
return CODE_TO_ENUM.get(theCodeString);
}
@Override
public SecurityEventObjectTypeEnum fromCodeString(String theCodeString, String theSystemString) {
Map<String, SecurityEventObjectTypeEnum> map = SYSTEM_TO_CODE_TO_ENUM.get(theSystemString);
if (map == null) {
return null;
}
return map.get(theCodeString);
}
};
/**
* Constructor
*/
SecurityEventObjectTypeEnum(String theCode, String theSystem) {
myCode = theCode;
mySystem = theSystem;
}
}

View File

@ -52,6 +52,7 @@ public class TimeDt extends StringDt implements IQueryParameterType {
*/
@SimpleSetter
public TimeDt(@SimpleSetter.Parameter(name = "theString") String theValue) {
this();
setValue(theValue);
}

View File

@ -1,55 +0,0 @@
package ca.uhn.fhir.narrative;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.thymeleaf.TemplateProcessingParameters;
import org.thymeleaf.templateresolver.ITemplateResolver;
import org.thymeleaf.templateresolver.TemplateResolution;
public class ThymeleafResolver implements ITemplateResolver {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ThymeleafResolver.class);
@Override
public String getName() {
return "";
}
@Override
public Integer getOrder() {
return 0;
}
@Override
public void initialize() {
// nothing
}
@Override
public TemplateResolution resolveTemplate(TemplateProcessingParameters theTemplateProcessingParameters) {
String templateName = theTemplateProcessingParameters.getTemplateName();
ourLog.info("Resolving template: {}", templateName);
return null;
}
}

View File

@ -314,21 +314,6 @@ public abstract class BaseParser implements IParser {
}
}
protected String determineResourceBaseUrl(String bundleBaseUrl, BundleEntry theEntry) {
IResource resource = theEntry.getResource();
if (resource == null) {
return null;
}
String resourceBaseUrl = null;
if (resource.getId() != null && resource.getId().hasBaseUrl()) {
if (!resource.getId().getBaseUrl().equals(bundleBaseUrl)) {
resourceBaseUrl = resource.getId().getBaseUrl();
}
}
return resourceBaseUrl;
}
protected abstract void doEncodeBundleToWriter(Bundle theBundle, Writer theWriter) throws IOException, DataFormatException;
protected abstract void doEncodeResourceToWriter(IBaseResource theResource, Writer theWriter) throws IOException, DataFormatException;

View File

@ -70,6 +70,13 @@ import ca.uhn.fhir.util.OperationOutcomeUtil;
public abstract class BaseClient implements IRestfulClient {
/**
* This property is used by unit tests - do not rely on it in production code
* as it may change at any time. If you want to capture responses in a reliable
* way in your own code, just use client interceptors
*/
static final String HAPI_CLIENT_KEEPRESPONSES = "hapi.client.keepresponses";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseClient.class);
private final IHttpClient myClient;
@ -89,6 +96,15 @@ public abstract class BaseClient implements IRestfulClient {
myClient = theClient;
myUrlBase = theUrlBase;
myFactory = theFactory;
/*
* This property is used by unit tests - do not rely on it in production code
* as it may change at any time. If you want to capture responses in a reliable
* way in your own code, just use client interceptors
*/
if ("true".equals(System.getProperty(HAPI_CLIENT_KEEPRESPONSES))) {
setKeepResponses(true);
}
}
protected Map<String, List<String>> createExtraParams() {
@ -193,7 +209,7 @@ public abstract class BaseClient implements IRestfulClient {
// TODO: handle non 2xx status codes by throwing the correct exception,
// and ensure it's passed upwards
IHttpRequest httpRequest;
IHttpRequest httpRequest = null;
IHttpResponse response = null;
try {
Map<String, List<String>> params = createExtraParams();
@ -339,11 +355,13 @@ public abstract class BaseClient implements IRestfulClient {
}
} catch (DataFormatException e) {
throw new FhirClientConnectionException(e);
String msg = getFhirContext().getLocalizer().getMessage(BaseClient.class, "failedToParseResponse", httpRequest.getHttpVerbName(), httpRequest.getUri(), e.toString());
throw new FhirClientConnectionException(msg, e);
} catch (IllegalStateException e) {
throw new FhirClientConnectionException(e);
} catch (IOException e) {
throw new FhirClientConnectionException(e);
String msg = getFhirContext().getLocalizer().getMessage(BaseClient.class, "ioExceptionDuringOperation", httpRequest.getHttpVerbName(), httpRequest.getUri(), e.toString());
throw new FhirClientConnectionException(msg, e);
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {

View File

@ -76,6 +76,7 @@ import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.gclient.IClientExecutable;
import ca.uhn.fhir.rest.gclient.ICreate;
import ca.uhn.fhir.rest.gclient.ICreateTyped;
@ -136,7 +137,7 @@ import ca.uhn.fhir.rest.method.SearchStyleEnum;
import ca.uhn.fhir.rest.method.SortParameter;
import ca.uhn.fhir.rest.method.TransactionMethodBinding;
import ca.uhn.fhir.rest.method.ValidateMethodBindingDstu1;
import ca.uhn.fhir.rest.method.ValidateMethodBindingDstu2;
import ca.uhn.fhir.rest.method.ValidateMethodBindingDstu2Plus;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.TokenParam;
@ -174,8 +175,8 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public IBaseConformance conformance() {
if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU2_HL7ORG)) {
throw new IllegalArgumentException("Must call fetchConformance() instead of conformance() for RI/DSTU3+ structures");
if (myContext.getVersion().getVersion().isRi()) {
throw new IllegalArgumentException("Must call fetchConformance() instead of conformance() for RI/STU3+ structures");
}
HttpGetClientInvocation invocation = MethodUtil.createConformanceInvocation(getFhirContext());
@ -376,7 +377,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
}
}
throw new RuntimeException(myContext.getLocalizer().getMessage(I18N_CANNOT_DETEMINE_RESOURCE_TYPE, theUrl.getValueAsString()));
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(I18N_CANNOT_DETEMINE_RESOURCE_TYPE, theUrl.getValueAsString()));
}
@ -385,6 +386,12 @@ public class GenericClient extends BaseClient implements IGenericClient {
// return doReadOrVRead(theType, theId, false, null, null);
// }
/**
* @deprecated Use {@link LoggingInterceptor} as a client interceptor registered to your
* client instead, as this provides much more fine-grained control over what is logged. This
* method will be removed at some point (deprecated in HAPI 1.6 - 2016-06-16)
*/
@Deprecated
public boolean isLogRequestAndResponse() {
return myLogRequestAndResponse;
}
@ -549,7 +556,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
if (myContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU1)) {
invocation = ValidateMethodBindingDstu1.createValidateInvocation(theResource, null, myContext);
} else {
invocation = ValidateMethodBindingDstu2.createValidateInvocation(myContext, theResource);
invocation = ValidateMethodBindingDstu2Plus.createValidateInvocation(myContext, theResource);
}
if (isKeepResponses()) {
@ -714,7 +721,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
protected IBaseResource parseResourceBody(String theResourceBody) {
EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(theResourceBody);
if (encoding == null) {
throw new InvalidRequestException("FHIR client can't determine resource encoding");
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
}
return encoding.newParser(myContext).parseResource(theResourceBody);
}
@ -2213,7 +2220,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myRawBundle = theBundle;
myRawBundleEncoding = MethodUtil.detectEncodingNoDefault(myRawBundle);
if (myRawBundleEncoding == null) {
throw new IllegalArgumentException("Can not determine encoding of raw resource body");
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
}
}
@ -2402,7 +2409,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
@Override
public MethodOutcome execute() {
BaseHttpClientInvocation invocation = ValidateMethodBindingDstu2.createValidateInvocation(myContext, myResource);
BaseHttpClientInvocation invocation = ValidateMethodBindingDstu2Plus.createValidateInvocation(myContext, myResource);
ResourceResponseHandler<BaseOperationOutcome> handler = new ResourceResponseHandler<BaseOperationOutcome>(null, null);
IBaseOperationOutcome outcome = invoke(null, handler, invocation);
MethodOutcome retVal = new MethodOutcome();
@ -2424,7 +2431,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
EncodingEnum enc = MethodUtil.detectEncodingNoDefault(theResourceRaw);
if (enc == null) {
throw new IllegalArgumentException("Could not detect encoding (XML/JSON) in string. Is this a valid FHIR resource?");
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
}
switch (enc) {
case XML:

View File

@ -37,6 +37,7 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.gclient.ICreate;
import ca.uhn.fhir.rest.gclient.IDelete;
import ca.uhn.fhir.rest.gclient.IFetchConformanceUntyped;
@ -288,7 +289,11 @@ public interface IGenericClient extends IRestfulClient {
*
* @param theLogRequestAndResponse
* Should requests and responses be logged
* @deprecated Use {@link LoggingInterceptor} as a client interceptor registered to your
* client instead, as this provides much more fine-grained control over what is logged. This
* method will be removed at some point (deprecated in HAPI 1.6 - 2016-06-16)
*/
@Deprecated
void setLogRequestAndResponse(boolean theLogRequestAndResponse);
/**

View File

@ -194,7 +194,7 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
public void validateServerBaseIfConfiguredToDoSo(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
String serverBase = normalizeBaseUrlForMap(theServerBase);
switch (myServerValidationMode) {
switch (getServerValidationMode()) {
case NEVER:
break;
case ONCE:
@ -268,22 +268,6 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
resetHttpClient();
}
/**
* Instantiates a new client invocation handler
* @param theClient
* the client which will invoke the call
* @param theUrlBase
* the url base
* @param theMethodToReturnValue
* @param theBindings
* @param theMethodToLambda
* @return a newly created client invocation handler
*/
ClientInvocationHandler newInvocationHandler(IHttpClient theClient, String theUrlBase, Map<Method, Object> theMethodToReturnValue, Map<Method, BaseMethodBinding<?>> theBindings, Map<Method, ClientInvocationHandlerFactory.ILambda> theMethodToLambda) {
return new ClientInvocationHandler(theClient, getFhirContext(), theUrlBase.toString(), theMethodToReturnValue,
theBindings, theMethodToLambda, this);
}
@SuppressWarnings("unchecked")
@Override
public void validateServerBase(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
@ -300,7 +284,8 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
Class implementingClass = myContext.getResourceDefinition("Conformance").getImplementingClass();
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
} catch (FhirClientConnectionException e) {
throw new FhirClientConnectionException(myContext.getLocalizer().getMessage(RestfulClientFactory.class, "failedToRetrieveConformance", theServerBase + Constants.URL_TOKEN_METADATA), e);
String msg = myContext.getLocalizer().getMessage(RestfulClientFactory.class, "failedToRetrieveConformance", theServerBase + Constants.URL_TOKEN_METADATA);
throw new FhirClientConnectionException(msg, e);
}
FhirTerser t = myContext.newTerser();

View File

@ -44,8 +44,8 @@ import ca.uhn.fhir.rest.client.api.IHttpResponse;
*/
public class ApacheHttpRequest implements IHttpRequest {
private HttpRequestBase myRequest;
private HttpClient myClient;
private HttpRequestBase myRequest;
public ApacheHttpRequest(HttpClient theClient, HttpRequestBase theApacheRequest) {
this.myClient = theClient;
@ -57,14 +57,6 @@ public class ApacheHttpRequest implements IHttpRequest {
myRequest.addHeader(theName, theValue);
}
/**
* Get the ApacheRequest
* @return the ApacheRequest
*/
public HttpRequestBase getApacheRequest() {
return myRequest;
}
@Override
public IHttpResponse execute() throws IOException {
return new ApacheHttpResponse(myClient.execute(myRequest));
@ -82,9 +74,17 @@ public class ApacheHttpRequest implements IHttpRequest {
return result;
}
/**
* Get the ApacheRequest
* @return the ApacheRequest
*/
public HttpRequestBase getApacheRequest() {
return myRequest;
}
@Override
public String toString() {
return myRequest.toString();
public String getHttpVerbName() {
return myRequest.getMethod();
}
@Override
@ -98,4 +98,14 @@ public class ApacheHttpRequest implements IHttpRequest {
return null;
}
@Override
public String getUri() {
return myRequest.getURI().toString();
}
@Override
public String toString() {
return myRequest.toString();
}
}

View File

@ -57,6 +57,7 @@ public class ApacheRestfulClientFactory extends RestfulClientFactory {
* Constructor
*/
public ApacheRestfulClientFactory() {
super();
}
/**

View File

@ -56,4 +56,14 @@ public interface IHttpRequest {
*/
public String getRequestBodyFromStream() throws IOException;
/**
* Return the request URI, or null
*/
public String getUri();
/**
* Return the HTTP verb (e.g. "GET")
*/
public String getHttpVerbName();
}

View File

@ -25,6 +25,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -200,9 +201,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
if (myParams != null) {
return httpClient.createParamRequest(getContext(), myParams, encoding);
} else {
if (encoding == null) {
encoding = EncodingEnum.XML;
}
encoding = ObjectUtils.defaultIfNull(encoding, EncodingEnum.XML);
String contents = encodeContents(thePrettyPrint, encoding);
String contentType = getContentType(encoding);
return httpClient.createByteRequest(getContext(), contents, contentType, encoding);

View File

@ -516,7 +516,7 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
if (theContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) {
return new ValidateMethodBindingDstu1(theMethod, theContext, theProvider);
} else {
return new ValidateMethodBindingDstu2(returnType, returnTypeFromRp, theMethod, theContext, theProvider, validate);
return new ValidateMethodBindingDstu2Plus(returnType, returnTypeFromRp, theMethod, theContext, theProvider, validate);
}
} else if (getTags != null) {
return new GetTagsMethodBinding(theMethod, theContext, theProvider, getTags);

View File

@ -253,7 +253,7 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
Set<SummaryEnum> summaryMode = Collections.emptySet();
return restfulResponse.streamResponseAsResource(outcome, prettyPrint, summaryMode, operationStatus, theRequest.isRespondGzip(), true);
return restfulResponse.streamResponseAsResource(outcome, prettyPrint, summaryMode, operationStatus, null, theRequest.isRespondGzip(), true);
// return theRequest.getResponse().returnResponse(ParseAction.create(outcome), operationStatus, allowPrefer, response, getResourceName());
}

View File

@ -36,6 +36,7 @@ import java.util.Set;
import java.util.TreeSet;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -45,7 +46,6 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -232,7 +232,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
return resource;
case METHOD_OUTCOME:
MethodOutcome retVal = new MethodOutcome();
retVal.setOperationOutcome((BaseOperationOutcome) resource);
retVal.setOperationOutcome((IBaseOperationOutcome) resource);
return retVal;
}
break;
@ -260,8 +260,8 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
return theRequest.getResponse().streamResponseAsResource(responseObject.getResource(), prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(),
isAddContentLocationHeader());
return theRequest.getResponse().streamResponseAsResource(responseObject.getResource(), prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, null,
theRequest.isRespondGzip(), isAddContentLocationHeader());
} else {
// Is this request coming from a browser

View File

@ -31,7 +31,6 @@ import java.util.TreeSet;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.PathSpecification;
import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.param.BaseQueryParameter;
import ca.uhn.fhir.rest.server.Constants;
@ -60,7 +59,7 @@ class IncludeParameter extends BaseQueryParameter {
}
mySpecType = theSpecType;
if (mySpecType != Include.class && mySpecType != PathSpecification.class && mySpecType != String.class) {
if (mySpecType != Include.class && mySpecType != String.class) {
throw new ConfigurationException("Invalid @" + IncludeParam.class.getSimpleName() + " parameter type: " + mySpecType);
}
@ -72,7 +71,7 @@ class IncludeParameter extends BaseQueryParameter {
ArrayList<QualifiedParamList> retVal = new ArrayList<QualifiedParamList>();
if (myInstantiableCollectionType == null) {
if (mySpecType == Include.class || mySpecType == PathSpecification.class) {
if (mySpecType == Include.class) {
convertAndAddIncludeToList(retVal, (Include) theObject);
} else {
retVal.add(QualifiedParamList.singleton(((String) theObject)));

View File

@ -6,10 +6,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.PushbackReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -23,6 +21,7 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
@ -40,14 +39,12 @@ import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.PathSpecification;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.At;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
@ -90,7 +87,9 @@ import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
import ca.uhn.fhir.rest.server.SearchParameterMap;
import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.UrlUtil;
/*
* #%L
@ -114,6 +113,12 @@ import ca.uhn.fhir.util.ReflectionUtil;
@SuppressWarnings("deprecation")
public class MethodUtil {
/** Non instantiable */
private MethodUtil() {
// nothing
}
private static final String LABEL = "label=\"";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MethodUtil.class);
@ -133,19 +138,14 @@ public class MethodUtil {
}
public static IIdType convertIdToType(IIdType value, Class<? extends IIdType> idParamType) {
if (value != null && !idParamType.isAssignableFrom(value.getClass())) {
try {
IIdType newValue = idParamType.newInstance();
@SuppressWarnings("unchecked")
public static <T extends IIdType> T convertIdToType(IIdType value, Class<T> theIdParamType) {
if (value != null && !theIdParamType.isAssignableFrom(value.getClass())) {
IIdType newValue = ReflectionUtil.newInstance(theIdParamType);
newValue.setValue(value.getValue());
value = newValue;
} catch (InstantiationException e) {
throw new ConfigurationException("Failed to instantiate " + idParamType, e);
} catch (IllegalAccessException e) {
throw new ConfigurationException("Failed to instantiate " + idParamType, e);
}
}
return value;
return (T) value;
}
public static HttpGetClientInvocation createConformanceInvocation(FhirContext theContext) {
@ -213,13 +213,9 @@ public class MethodUtil {
for (String nextValue : nextEntry.getValue()) {
b.append(haveQuestionMark ? '&' : '?');
haveQuestionMark = true;
try {
b.append(URLEncoder.encode(nextEntry.getKey(), "UTF-8"));
b.append(UrlUtil.escape(nextEntry.getKey()));
b.append('=');
b.append(URLEncoder.encode(nextValue, "UTF-8"));
} catch (UnsupportedEncodingException e) {
throw new ConfigurationException("UTF-8 not supported on this platform");
}
b.append(UrlUtil.escape(nextValue));
}
}
@ -288,9 +284,7 @@ public class MethodUtil {
public static EncodingEnum detectEncoding(String theBody) {
EncodingEnum retVal = detectEncodingNoDefault(theBody);
if (retVal == null) {
retVal = EncodingEnum.XML;
}
retVal = ObjectUtils.defaultIfNull(retVal, EncodingEnum.XML);
return retVal;
}
@ -322,10 +316,6 @@ public class MethodUtil {
}
}
public static Integer findConditionalOperationParameterIndex(Method theMethod) {
return MethodUtil.findParamAnnotationIndex(theMethod, ConditionalUrlParam.class);
}
public static Integer findIdParameterIndex(Method theMethod, FhirContext theContext) {
Integer index = MethodUtil.findParamAnnotationIndex(theMethod, IdParam.class);
if (index != null) {
@ -366,7 +356,7 @@ public class MethodUtil {
}
@SuppressWarnings("unchecked")
public static List<IParameter> getResourceParameters(FhirContext theContext, Method theMethod, Object theProvider, RestOperationTypeEnum theRestfulOperationTypeEnum) {
public static List<IParameter> getResourceParameters(final FhirContext theContext, Method theMethod, Object theProvider, RestOperationTypeEnum theRestfulOperationTypeEnum) {
List<IParameter> parameters = new ArrayList<IParameter>();
Class<?>[] parameterTypes = theMethod.getParameterTypes();
@ -442,7 +432,7 @@ public class MethodUtil {
if (parameterType == String.class) {
instantiableCollectionType = null;
specType = String.class;
} else if ((parameterType != Include.class && parameterType != PathSpecification.class) || innerCollectionType == null || outerCollectionType != null) {
} else if ((parameterType != Include.class) || innerCollectionType == null || outerCollectionType != null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' is annotated with @" + IncludeParam.class.getSimpleName() + " but has a type other than Collection<" + Include.class.getSimpleName() + ">");
} else {
instantiableCollectionType = (Class<? extends Collection<Include>>) CollectionBinder.getInstantiableCollectionType(innerCollectionType, "Method '" + theMethod.getName() + "'");
@ -515,7 +505,7 @@ public class MethodUtil {
@Override
public Object outgoingClient(Object theObject) {
return new StringDt(((ValidationModeEnum)theObject).getCode());
return ParametersUtil.createString(theContext, ((ValidationModeEnum)theObject).getCode());
}
});
} else if (nextAnnotation instanceof Validate.Profile) {
@ -530,7 +520,7 @@ public class MethodUtil {
@Override
public Object outgoingClient(Object theObject) {
return new StringDt(theObject.toString());
return ParametersUtil.createString(theContext, theObject.toString());
}
});
} else {

View File

@ -59,7 +59,6 @@ import ca.uhn.fhir.rest.param.HasParam;
import ca.uhn.fhir.rest.param.NumberAndListParam;
import ca.uhn.fhir.rest.param.NumberOrListParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.QualifiedDateParam;
import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.param.QuantityOrListParam;
import ca.uhn.fhir.rest.param.QuantityParam;
@ -81,7 +80,6 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.CollectionUtil;
import ca.uhn.fhir.util.ReflectionUtil;
@SuppressWarnings("deprecation")
public class SearchParameter extends BaseQueryParameter {
private static final String EMPTY_STRING = "";
@ -341,8 +339,6 @@ public class SearchParameter extends BaseQueryParameter {
// ok
} else if (StringDt.class.isAssignableFrom(type)) {
myParamType = RestSearchParameterTypeEnum.STRING;
} else if (QualifiedDateParam.class.isAssignableFrom(type)) {
myParamType = RestSearchParameterTypeEnum.DATE;
} else if (BaseIdentifierDt.class.isAssignableFrom(type)) {
myParamType = RestSearchParameterTypeEnum.TOKEN;
} else if (BaseQuantityDt.class.isAssignableFrom(type)) {

View File

@ -1,54 +0,0 @@
package ca.uhn.fhir.rest.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
/**
* Created by dsotnikov on 2/25/2014.
*/
class Util {
// public static Integer findCountParameterIndex(Method theMethod) {
// return findParamIndex(theMethod, Count.class);
// }
public static Map<String, String> getQueryParams(String query) {
try {
Map<String, String> params = new HashMap<String, String>();
for (String param : query.split("&")) {
String[] pair = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = URLDecoder.decode(pair[1], "UTF-8");
params.put(key, value);
}
return params;
} catch (UnsupportedEncodingException ex) {
throw new AssertionError(ex);
}
}
}

View File

@ -37,9 +37,9 @@ import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.ParametersUtil;
public class ValidateMethodBindingDstu2 extends OperationMethodBinding {
public class ValidateMethodBindingDstu2Plus extends OperationMethodBinding {
public ValidateMethodBindingDstu2(Class<?> theReturnResourceType, Class<? extends IBaseResource> theReturnTypeFromRp, Method theMethod, FhirContext theContext, Object theProvider,
public ValidateMethodBindingDstu2Plus(Class<?> theReturnResourceType, Class<? extends IBaseResource> theReturnTypeFromRp, Method theMethod, FhirContext theContext, Object theProvider,
Validate theAnnotation) {
super(theReturnResourceType, theReturnTypeFromRp, theMethod, theContext, theProvider, true, Constants.EXTOP_VALIDATE, theAnnotation.type(), new OperationParam[0], BundleTypeEnum.COLLECTION);

View File

@ -1,84 +0,0 @@
package ca.uhn.fhir.rest.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.client.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.ResourceParameter;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.util.ParametersUtil;
public class ValidateMethodBindingDstu3 extends OperationMethodBinding {
public ValidateMethodBindingDstu3(Class<?> theReturnResourceType, Class<? extends IBaseResource> theReturnTypeFromRp, Method theMethod, FhirContext theContext, Object theProvider,
Validate theAnnotation) {
super(theReturnResourceType, theReturnTypeFromRp, theMethod, theContext, theProvider, true, Constants.EXTOP_VALIDATE, theAnnotation.type(), new OperationParam[0], BundleTypeEnum.COLLECTION);
List<IParameter> newParams = new ArrayList<IParameter>();
int idx = 0;
for (IParameter next : getParameters()) {
if (next instanceof ResourceParameter) {
if (IBaseResource.class.isAssignableFrom(((ResourceParameter) next).getResourceType())) {
Class<?> parameterType = theMethod.getParameterTypes()[idx];
if (String.class.equals(parameterType) || EncodingEnum.class.equals(parameterType)) {
newParams.add(next);
} else {
OperationParameter parameter = new OperationParameter(theContext, Constants.EXTOP_VALIDATE, Constants.EXTOP_VALIDATE_RESOURCE, 0, 1);
parameter.initializeTypes(theMethod, null, null, parameterType);
newParams.add(parameter);
}
} else {
newParams.add(next);
}
} else {
newParams.add(next);
}
idx++;
}
setParameters(newParams);
}
public static BaseHttpClientInvocation createValidateInvocation(FhirContext theContext, IBaseResource theResource) {
IBaseParameters parameters = (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
ParametersUtil.addParameterToParameters(theContext, parameters, theResource, "resource");
String resourceName = theContext.getResourceDefinition(theResource).getName();
String resourceId = theResource.getIdElement().getIdPart();
BaseHttpClientInvocation retVal = createOperationInvocation(theContext, resourceName, resourceId, Constants.EXTOP_VALIDATE, parameters, false);
return retVal;
}
}

View File

@ -1,65 +0,0 @@
package ca.uhn.fhir.rest.param;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Date;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.util.CoverageIgnore;
/**
* @deprecated Use {@link DateParam} instead (this class is identical, but was renamed to be less confusing)
*/
@Deprecated
@CoverageIgnore
public class QualifiedDateParam extends DateParam {
/**
* Constructor
*/
public QualifiedDateParam() {
}
/**
* Constructor
*/
public QualifiedDateParam(QuantityCompararatorEnum theComparator, Date theDate) {
setComparator(theComparator);
setValue(theDate);
}
/**
* Constructor
*/
public QualifiedDateParam(QuantityCompararatorEnum theComparator, String theDate) {
setComparator(theComparator);
setValueAsString(theDate);
}
/**
* Constructor which takes a complete [qualifier]{date} string.
*
* @param theString The string
*/
public QualifiedDateParam(String theString) {
setValueAsQueryToken(null, theString);
}
}

View File

@ -38,7 +38,7 @@ import ca.uhn.fhir.rest.method.ParseAction;
public interface IRestfulResponse {
Object streamResponseAsResource(IBaseResource theActualResourceToReturn, boolean prettyPrint, Set<SummaryEnum> summaryMode, int operationStatus, boolean respondGzip, boolean addContentLocationHeader) throws IOException;
Object streamResponseAsResource(IBaseResource theActualResourceToReturn, boolean thePrettyPrint, Set<SummaryEnum> theSummaryMode, int theStatusCode, String theStatusMessage, boolean theRespondGzip, boolean theAddContentLocation) throws IOException;
Object streamResponseAsBundle(Bundle bundle, Set<SummaryEnum> summaryMode, boolean respondGzip, boolean requestIsBrowser) throws IOException;
@ -48,7 +48,7 @@ public interface IRestfulResponse {
*/
Object returnResponse(ParseAction<?> outcome, int operationStatus, boolean allowPrefer, MethodOutcome response, String resourceName) throws IOException;
Writer getResponseWriter(int statusCode, String contentType, String charset, boolean respondGzip) throws UnsupportedEncodingException, IOException;
Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException;
Object sendWriterResponse(int status, String contentType, String charset, Writer writer) throws IOException;

View File

@ -90,10 +90,10 @@ public abstract class RestfulResponse<T extends RequestDetails> implements IRest
}
@Override
public final Object streamResponseAsResource(IBaseResource resource, boolean prettyPrint, Set<SummaryEnum> summaryMode,
int statusCode, boolean respondGzip, boolean addContentLocationHeader)
public final Object streamResponseAsResource(IBaseResource theResource, boolean thePrettyPrint, Set<SummaryEnum> theSummaryMode,
int theStatusCode, String theStatusMessage, boolean theRespondGzip, boolean theAddContentLocation)
throws IOException {
return RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), resource, summaryMode, statusCode, addContentLocationHeader, respondGzip, getRequestDetails(), myOperationResourceId, myOperationResourceLastUpdated);
return RestfulServerUtils.streamResponseAsResource(theRequestDetails.getServer(), theResource, theSummaryMode, theStatusCode, theStatusMessage, theAddContentLocation, theRespondGzip, getRequestDetails(), myOperationResourceId, myOperationResourceLastUpdated);
}

View File

@ -537,7 +537,7 @@ public class RestfulServerUtils {
String contentType = responseEncoding.getBundleContentType();
String charset = Constants.CHARSET_NAME_UTF8;
Writer writer = theRequestDetails.getResponse().getResponseWriter(status, contentType, charset, respondGzip);
Writer writer = theRequestDetails.getResponse().getResponseWriter(status, null, contentType, charset, respondGzip);
try {
IParser parser = RestfulServerUtils.getNewParser(theServer.getFhirContext(), theRequestDetails);
@ -552,11 +552,11 @@ public class RestfulServerUtils {
}
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails) throws IOException {
return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null);
return streamResponseAsResource(theServer, theResource, theSummaryMode, stausCode, null, theAddContentLocationHeader, respondGzip, theRequestDetails, null, null);
}
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int stausCode, boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType<Date> theOperationResourceLastUpdated) throws IOException {
public static Object streamResponseAsResource(IRestfulServerDefaults theServer, IBaseResource theResource, Set<SummaryEnum> theSummaryMode, int theStausCode, String theStatusMessage, boolean theAddContentLocationHeader, boolean respondGzip, RequestDetails theRequestDetails, IIdType theOperationResourceId, IPrimitiveType<Date> theOperationResourceLastUpdated) throws IOException {
IRestfulResponse restUtil = theRequestDetails.getResponse();
// Determine response encoding
@ -596,7 +596,7 @@ public class RestfulServerUtils {
// malicious images or HTML blocks being served up as content.
restUtil.addHeader(Constants.HEADER_CONTENT_DISPOSITION, "Attachment;");
return restUtil.sendAttachmentResponse(bin, stausCode, contentType);
return restUtil.sendAttachmentResponse(bin, theStausCode, contentType);
}
// Ok, we're not serving a binary resource, so apply default encoding
@ -656,7 +656,7 @@ public class RestfulServerUtils {
}
String charset = Constants.CHARSET_NAME_UTF8;
Writer writer = restUtil.getResponseWriter(stausCode, contentType, charset, respondGzip);
Writer writer = restUtil.getResponseWriter(theStausCode, theStatusMessage, contentType, charset, respondGzip);
if (theResource == null) {
// No response is being returned
} else if (encodingDomainResourceAsText && theResource instanceof IResource) {
@ -666,7 +666,7 @@ public class RestfulServerUtils {
parser.encodeResourceToWriter(theResource, writer);
}
return restUtil.sendWriterResponse(stausCode, contentType, charset, writer);
return restUtil.sendWriterResponse(theStausCode, contentType, charset, writer);
}
public static IIdType fullyQualifyResourceIdOrReturnNull(IRestfulServerDefaults theServer, IBaseResource theResource, String theServerBase, IIdType theResourceId) {

View File

@ -39,6 +39,7 @@ import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.IRestfulResponse;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
import ca.uhn.fhir.util.OperationOutcomeUtil;
public class ExceptionHandlingInterceptor extends InterceptorAdapter {
@ -79,7 +80,15 @@ public class ExceptionHandlingInterceptor extends InterceptorAdapter {
}
}
return response.streamResponseAsResource(oo, true, Collections.singleton(SummaryEnum.FALSE), statusCode, false, false);
String statusMessage = null;
if (theException instanceof UnclassifiedServerFailureException) {
String sm = theException.getMessage();
if (isNotBlank(sm) && sm.indexOf('\n') == -1) {
statusMessage = sm;
}
}
return response.streamResponseAsResource(oo, true, Collections.singleton(SummaryEnum.FALSE), statusCode, statusMessage, false, false);
// theResponse.setStatus(statusCode);
// theRequestDetails.getServer().addHeadersToResponse(theResponse);
// theResponse.setContentType("text/plain");

View File

@ -340,19 +340,21 @@ public class ResponseHighlighterInterceptor extends InterceptorAdapter {
b.append("<p>");
b.append("This result is being rendered in HTML for easy viewing. ");
b.append("You may view this content as ");
b.append("You may access this content as ");
b.append("<a href=\"");
b.append(createLinkHref(parameters, Constants.FORMAT_JSON));
b.append("\">Raw JSON</a>, ");
b.append("\">Raw JSON</a> or ");
b.append("<a href=\"");
b.append(createLinkHref(parameters, Constants.FORMAT_XML));
b.append("\">Raw XML</a>, ");
b.append(" or view this content in ");
b.append("<a href=\"");
b.append(createLinkHref(parameters, Constants.FORMATS_HTML_JSON));
b.append("\">HTML JSON</a>, ");
b.append("\">HTML JSON</a> ");
b.append("or ");
b.append("<a href=\"");

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict;
abstract class BaseRule implements IAuthRule {
private String myName;
private PolicyEnum myMode;
BaseRule(String theRuleName) {
myName = theRuleName;
}
@Override
public String getName() {
return myName;
}
public void setMode(PolicyEnum theRuleMode) {
myMode = theRuleMode;
}
Verdict newVerdict() {
return new Verdict(myMode, this);
}
public PolicyEnum getMode() {
return myMode;
}
}

View File

@ -0,0 +1,17 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
public interface IAuthRuleBuilderOperation {
/**
* This rule applies to the operation with the given name
*
* @param The operation name, e.g. "validate" or "$validate" (either form may be used here)
*/
IAuthRuleBuilderOperationNamed named(String theOperationName);
/**
* This rule applies to any operation
*/
IAuthRuleBuilderOperationNamed withAnyName();
}

View File

@ -0,0 +1,23 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
public interface IAuthRuleBuilderOperationNamed {
/**
* Rule applies to invocations of this operation at the <code>server</code> level
*/
IAuthRuleBuilderRuleOpClassifierFinished onServer();
/**
* Rule applies to invocations of this operation at the <code>type</code> level
*/
IAuthRuleBuilderRuleOpClassifierFinished onType(Class<? extends IBaseResource> theType);
/**
* Rule applies to invocations of this operation at the <code>instance</code> level
*/
IAuthRuleBuilderRuleOpClassifierFinished onInstance(IIdType theInstanceId);
}

View File

@ -55,4 +55,9 @@ public interface IAuthRuleBuilderRule {
*/
IAuthRuleBuilderRuleOp write();
/**
* This rule applies to a FHIR operation (e.g. <code>$validate</code>)
*/
IAuthRuleBuilderOperation operation();
}

View File

@ -0,0 +1,96 @@
package ca.uhn.fhir.rest.server.interceptor.auth;
import java.util.HashSet;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor.Verdict;
class OperationRule extends BaseRule implements IAuthRule {
public OperationRule(String theRuleName) {
super(theRuleName);
}
private String myOperationName;
private boolean myAppliesToServer;
private HashSet<Class<? extends IBaseResource>> myAppliesToTypes;
private List<IIdType> myAppliesToIds;
/**
* Must include the leading $
*/
public void setOperationName(String theOperationName) {
myOperationName = theOperationName;
}
public String getOperationName() {
return myOperationName;
}
@Override
public Verdict applyRule(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IBaseResource theInputResource, IBaseResource theOutputResource, IRuleApplier theRuleApplier) {
FhirContext ctx = theRequestDetails.getServer().getFhirContext();
boolean applies = false;
switch (theOperation) {
case EXTENDED_OPERATION_SERVER:
if (myAppliesToServer) {
applies = true;
}
break;
case EXTENDED_OPERATION_TYPE:
if (myAppliesToTypes != null) {
for (Class<? extends IBaseResource> next : myAppliesToTypes) {
String resName = ctx.getResourceDefinition(theRequestDetails.getResourceName()).getName();
if (resName.equals(theRequestDetails.getResourceName())) {
applies = true;
break;
}
}
}
break;
case EXTENDED_OPERATION_INSTANCE:
if (myAppliesToIds != null) {
String instanceId = theRequestDetails.getId().toUnqualifiedVersionless().getValue();
for (IIdType next : myAppliesToIds) {
if (next.toUnqualifiedVersionless().getValue().equals(instanceId)) {
applies = true;
break;
}
}
}
break;
default:
return null;
}
if (!applies) {
return null;
}
if (myOperationName != null && !myOperationName.equals(theRequestDetails.getOperation())) {
return null;
}
return newVerdict();
}
public void appliesToServer() {
myAppliesToServer = true;
}
public void appliesToTypes(HashSet<Class<? extends IBaseResource>> theAppliesToTypes) {
myAppliesToTypes = theAppliesToTypes;
}
public void appliesToInstances(List<IIdType> theAppliesToIds) {
myAppliesToIds = theAppliesToIds;
}
}

View File

@ -24,7 +24,6 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -40,20 +39,18 @@ import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.BundleUtil.BundleEntryParts;
import ca.uhn.fhir.util.FhirTerser;
class Rule implements IAuthRule {
class Rule extends BaseRule implements IAuthRule {
private AppliesTypeEnum myAppliesTo;
private Set<?> myAppliesToTypes;
private String myClassifierCompartmentName;
private Collection<? extends IIdType> myClassifierCompartmentOwners;
private ClassifierTypeEnum myClassifierType;
private PolicyEnum myMode;
private String myName;
private RuleOpEnum myOp;
private TransactionAppliesToEnum myTransactionAppliesToOp;
public Rule(String theRuleName) {
myName = theRuleName;
super(theRuleName);
}
@Override
@ -77,7 +74,7 @@ class Rule implements IAuthRule {
case DELETE:
if (theOperation == RestOperationTypeEnum.DELETE) {
if (theInputResource == null) {
return new Verdict(myMode, this);
return newVerdict();
} else {
appliesTo = theInputResource;
}
@ -88,7 +85,7 @@ class Rule implements IAuthRule {
case BATCH:
case TRANSACTION:
if (theInputResource != null && requestAppliesToTransaction(ctx, myOp, theInputResource)) {
if (myMode == PolicyEnum.DENY) {
if (getMode() == PolicyEnum.DENY) {
return new Verdict(PolicyEnum.DENY, this);
} else {
List<BundleEntryParts> inputResources = BundleUtil.toListOfEntries(ctx, (IBaseBundle) theInputResource);
@ -155,7 +152,7 @@ class Rule implements IAuthRule {
return new Verdict(PolicyEnum.DENY, this);
case METADATA:
if (theOperation == RestOperationTypeEnum.METADATA) {
return new Verdict(myMode, this);
return newVerdict();
} else {
return null;
}
@ -196,9 +193,10 @@ class Rule implements IAuthRule {
throw new IllegalStateException("Unable to apply security to event of applies to type " + myAppliesTo);
}
return new Verdict(myMode, this);
return newVerdict();
}
private boolean requestAppliesToTransaction(FhirContext theContext, RuleOpEnum theOp, IBaseResource theInputResource) {
if (!"Bundle".equals(theContext.getResourceDefinition(theInputResource).getName())) {
return false;
@ -216,11 +214,6 @@ class Rule implements IAuthRule {
}
}
@Override
public String getName() {
return myName;
}
public TransactionAppliesToEnum getTransactionAppliesToOp() {
return myTransactionAppliesToOp;
}
@ -245,9 +238,6 @@ class Rule implements IAuthRule {
myClassifierType = theClassifierType;
}
public void setMode(PolicyEnum theRuleMode) {
myMode = theRuleMode;
}
public Rule setOp(RuleOpEnum theRuleOp) {
myOp = theRuleOp;
@ -257,4 +247,5 @@ class Rule implements IAuthRule {
public void setTransactionAppliesToOp(TransactionAppliesToEnum theOp) {
myTransactionAppliesToOp = theOp;
}
}

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -243,6 +244,80 @@ public class RuleBuilder implements IAuthRuleBuilder {
}
private class RuleBuilderRuleOperation implements IAuthRuleBuilderOperation {
private class RuleBuilderRuleOperationNamed implements IAuthRuleBuilderOperationNamed {
private String myOperationName;
public RuleBuilderRuleOperationNamed(String theOperationName) {
if (theOperationName != null && !theOperationName.startsWith("$")) {
myOperationName = '$' + theOperationName;
} else {
myOperationName = theOperationName;
}
}
@Override
public IAuthRuleBuilderRuleOpClassifierFinished onServer() {
OperationRule rule = createRule();
rule.appliesToServer();
myRules.add(rule);
return new RuleBuilderFinished();
}
private OperationRule createRule() {
OperationRule rule = new OperationRule(myRuleName);
rule.setOperationName(myOperationName);
rule.setMode(myRuleMode);
return rule;
}
@Override
public IAuthRuleBuilderRuleOpClassifierFinished onType(Class<? extends IBaseResource> theType) {
Validate.notNull(theType, "theType must not be null");
OperationRule rule = createRule();
HashSet<Class<? extends IBaseResource>> appliesToTypes = new HashSet<Class<? extends IBaseResource>>();
appliesToTypes.add(theType);
rule.appliesToTypes(appliesToTypes);
myRules.add(rule);
return new RuleBuilderFinished();
}
@Override
public IAuthRuleBuilderRuleOpClassifierFinished onInstance(IIdType theInstanceId) {
Validate.notNull(theInstanceId, "theInstanceId must not be null");
Validate.notBlank(theInstanceId.getResourceType(), "theInstanceId does not have a resource type");
Validate.notBlank(theInstanceId.getIdPart(), "theInstanceId does not have an ID part");
OperationRule rule = createRule();
ArrayList<IIdType> ids = new ArrayList<IIdType>();
ids.add(theInstanceId);
rule.appliesToInstances(ids);
myRules.add(rule);
return new RuleBuilderFinished();
}
}
@Override
public IAuthRuleBuilderOperationNamed named(String theOperationName) {
Validate.notBlank(theOperationName, "theOperationName must not be null or empty");
return new RuleBuilderRuleOperationNamed(theOperationName);
}
@Override
public IAuthRuleBuilderOperationNamed withAnyName() {
return new RuleBuilderRuleOperationNamed(null);
}
}
@Override
public IAuthRuleBuilderOperation operation() {
return new RuleBuilderRuleOperation();
}
}
}

View File

@ -28,5 +28,6 @@ enum RuleOpEnum {
TRANSACTION,
METADATA,
BATCH,
DELETE
DELETE,
OPERATION
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.rest.server.servlet;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
* #%L
* HAPI FHIR - Core Library
@ -61,12 +63,12 @@ public class ServletRestfulResponse extends RestfulResponse<ServletRequestDetail
}
@Override
public Writer getResponseWriter(int statusCode, String contentType, String charset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException {
public Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip) throws UnsupportedEncodingException, IOException {
addHeaders();
HttpServletResponse theHttpResponse = getRequestDetails().getServletResponse();
theHttpResponse.setCharacterEncoding(charset);
theHttpResponse.setStatus(statusCode);
theHttpResponse.setContentType(contentType);
theHttpResponse.setCharacterEncoding(theCharset);
theHttpResponse.setStatus(theStatusCode);
theHttpResponse.setContentType(theContentType);
if (theRespondGzip) {
theHttpResponse.addHeader(Constants.HEADER_CONTENT_ENCODING, Constants.ENCODING_GZIP);
return new OutputStreamWriter(new GZIPOutputStream(theHttpResponse.getOutputStream()), Constants.CHARSET_NAME_UTF8);

View File

@ -1656,10 +1656,6 @@ public class XmlUtil {
ourHaveLoggedStaxImplementation = true;
}
public static void main(String[] args) throws FactoryConfigurationError, XMLStreamException {
createXmlWriter(new StringWriter());
}
private static final class ExtendedEntityReplacingXmlResolver implements XMLResolver {
@Override
public Object resolveEntity(String thePublicID, String theSystemID, String theBaseURI, String theNamespace) throws XMLStreamException {

View File

@ -7,11 +7,15 @@ ca.uhn.fhir.context.FhirContext.noStructuresForSpecifiedVersion=Could not find t
ca.uhn.fhir.context.RuntimeResourceDefinition.nonInstantiableType=Resource type "{0}" can not be instantiated. Check that this class has a no-argument constructor, and that it is static if it is a nested type. Error is: {1}
ca.uhn.fhir.rest.client.BaseClient.ioExceptionDuringOperation=Encountered IOException when performing {0} to URL {1} - {2}
ca.uhn.fhir.rest.client.BaseClient.failedToParseResponse=Failed to parse response from server when performing {0} to URL {1} - {2}
ca.uhn.fhir.rest.client.GenericClient.cantDetermineRequestType=Unable to determing encoding of request (body does not appear to be valid XML or JSON)
ca.uhn.fhir.rest.client.GenericClient.noPagingLinkFoundInBundle=Can not perform paging operation because no link was found in Bundle with relation "{0}"
ca.uhn.fhir.rest.client.GenericClient.noVersionIdForVread=No version specified in URL for 'vread' operation: {0}
ca.uhn.fhir.rest.client.GenericClient.incompleteUriForRead=The given URI is not an absolute URL and is not usable for this operation: {0}
ca.uhn.fhir.rest.client.GenericClient.cannotDetermineResourceTypeFromUri=Unable to determine the resource type from the given URI: {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.failedToRetrieveConformance=Failed to retrieve the server's metadata statement during client initialization. URL used was: {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.failedToRetrieveConformance=Failed to retrieve the server metadata statement during client initialization. URL used was {0}
ca.uhn.fhir.rest.client.RestfulClientFactory.wrongVersionInConformance=The server at base URL "{0}" returned a conformance statement indicating that it supports FHIR version "{1}" which corresponds to {2}, but this client is configured to use {3} (via the FhirContext).
ca.uhn.fhir.rest.method.BaseOutcomeReturningMethodBindingWithResourceParam.incorrectIdForUpdate=Can not update resource, resource body must contain an ID element which matches the request URL for update (PUT) operation - Resource body ID of "{0}" does not match URL ID of "{1}"

View File

@ -26,7 +26,7 @@ public class FhirDbConfig {
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
// extraProperties.put("hibernate.search.default.worker.execution", "async");
extraProperties.put("hibernate.search.default.worker.execution", "async");
if (System.getProperty("lowmem") != null) {
extraProperties.put("hibernate.search.autoregister_listeners", "false");

View File

@ -103,4 +103,14 @@ public class JaxRsHttpRequest implements IHttpRequest {
return null;
}
@Override
public String getUri() {
return ""; // TODO: can we get this from somewhere?
}
@Override
public String getHttpVerbName() {
return myRequestType.name();
}
}

View File

@ -194,7 +194,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
if (conformance != null) {
Set<SummaryEnum> summaryMode = Collections.emptySet();
return (Response) response.streamResponseAsResource(conformance, false, summaryMode, Constants.STATUS_HTTP_200_OK, true, false);
return (Response) response.streamResponseAsResource(conformance, false, summaryMode, Constants.STATUS_HTTP_200_OK, null, true, false);
}
return (Response) response.returnResponse(null, Constants.STATUS_HTTP_500_INTERNAL_ERROR, true, null, getResourceType().getSimpleName());
}

View File

@ -65,7 +65,7 @@ public class JaxRsResponse extends RestfulResponse<JaxRsRequest> {
* by the server.
*/
@Override
public Writer getResponseWriter(int statusCode, String contentType, String charset, boolean respondGzip)
public Writer getResponseWriter(int theStatusCode, String theStatusMessage, String theContentType, String theCharset, boolean theRespondGzip)
throws UnsupportedEncodingException, IOException {
return new StringWriter();
}

View File

@ -65,6 +65,7 @@ import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.BaseClient;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.api.Header;
@ -94,6 +95,7 @@ public class GenericJaxRsClientDstu3Test {
ourCtx.setRestfulClientFactory(clientFactory);
ourResponseCount = 0;
System.setProperty("hapi.client.keepresponses", "true");
}
private String getPatientFeedWithOneResult() {
@ -211,7 +213,6 @@ public class GenericJaxRsClientDstu3Test {
}
@Test
@SuppressWarnings("deprecation")
public void testConformance() throws Exception {
IParser p = ourCtx.newXmlParser();
@ -228,7 +229,7 @@ public class GenericJaxRsClientDstu3Test {
//@formatter:off
Conformance resp = (Conformance)client.conformance();
Conformance resp = (Conformance)client.fetchConformance().ofType(Conformance.class).execute();
//@formatter:on
assertEquals("http://localhost:" + ourPort + "/fhir/metadata", ourRequestUri);

View File

@ -51,8 +51,13 @@ public class DaoConfig {
// ***
// update setter javadoc if default changes
// ***
private int myDeferIndexingForCodesystemsOfSize = 2000;
// ***
// update setter javadoc if default changes
// ***
private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR;
private int myHardSearchLimit = 1000;
private int myHardTagListLimit = 1000;
private int myIncludeLimit = 2000;
@ -63,13 +68,13 @@ public class DaoConfig {
private boolean myIndexContainedResources = true;
private List<IServerInterceptor> myInterceptors;
// ***
// update setter javadoc if default changes
// ***
private int myMaximumExpansionSize = 5000;
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
private boolean mySchedulingDisabled;
private boolean mySubscriptionEnabled;
@ -77,8 +82,20 @@ public class DaoConfig {
private long mySubscriptionPollDelay = 1000;
private Long mySubscriptionPurgeInactiveAfterMillis;
private Set<String> myTreatBaseUrlsAsLocal = new HashSet<String>();
/**
* When a code system is added that contains more than this number of codes,
* the code system will be indexed later in an incremental process in order to
* avoid overwhelming Lucene with a huge number of codes in a single operation.
* <p>
* Defaults to 2000
* </p>
*/
public int getDeferIndexingForCodesystemsOfSize() {
return myDeferIndexingForCodesystemsOfSize;
}
/**
* Sets the number of milliseconds that search results for a given client search
* should be preserved before being purged from the database.
@ -117,6 +134,7 @@ public class DaoConfig {
}
return myInterceptors;
}
/**
* See {@link #setMaximumExpansionSize(int)}
*/
@ -180,7 +198,6 @@ public class DaoConfig {
public boolean isAllowInlineMatchUrlReferences() {
return myAllowInlineMatchUrlReferences;
}
public boolean isAllowMultipleDelete() {
return myAllowMultipleDelete;
}
@ -251,6 +268,18 @@ public class DaoConfig {
myAllowMultipleDelete = theAllowMultipleDelete;
}
/**
* When a code system is added that contains more than this number of codes,
* the code system will be indexed later in an incremental process in order to
* avoid overwhelming Lucene with a huge number of codes in a single operation.
* <p>
* Defaults to 2000
* </p>
*/
public void setDeferIndexingForCodesystemsOfSize(int theDeferIndexingForCodesystemsOfSize) {
myDeferIndexingForCodesystemsOfSize = theDeferIndexingForCodesystemsOfSize;
}
/**
* Sets the number of milliseconds that search results for a given client search
* should be preserved before being purged from the database.

View File

@ -1,79 +0,0 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Date;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
class HistoryTuple implements Comparable<HistoryTuple> {
private Long myId;
private boolean myIsHistory;
private Date myUpdated;
public HistoryTuple(boolean theIsHistory, Date theUpdated, Long theId) {
super();
myIsHistory = theIsHistory;
myUpdated = theUpdated;
myId = theId;
}
@Override
public int compareTo(HistoryTuple theO) {
return myUpdated.compareTo(theO.myUpdated);
}
public Long getId() {
return myId;
}
public boolean isHistory() {
return myIsHistory;
}
public Date getUpdated() {
return myUpdated;
}
public void setId(Long theId) {
myId = theId;
}
public void setIsHistory(boolean theIsHistory) {
myIsHistory = theIsHistory;
}
public void setUpdated(Date theUpdated) {
myUpdated = theUpdated;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("id", myId);
b.append("history", myIsHistory);
b.append("updated", myUpdated);
return b.build();
}
}

View File

@ -55,14 +55,12 @@ 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.indexes.interceptor.DontInterceptEntityInterceptor;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
//@formatter:off
@Entity
@Indexed(interceptor=DeferConceptIndexingInterceptor.class)
@Indexed()
@Table(name="TRM_CONCEPT", uniqueConstraints= {
@UniqueConstraint(name="IDX_CONCEPT_CS_CODE", columnNames= {"CODESYSTEM_PID", "CODE"})
}, indexes= {
@ -71,7 +69,6 @@ import ca.uhn.fhir.jpa.search.DeferConceptIndexingInterceptor;
//@formatter:on
public class TermConcept implements Serializable {
private static final int MAX_DESC_LENGTH = 400;
private static final long serialVersionUID = 1L;
@OneToMany(fetch=FetchType.LAZY, mappedBy="myParent")
@ -189,6 +186,10 @@ public class TermConcept implements Serializable {
return myId;
}
public Long getIndexStatus() {
return myIndexStatus;
}
public Collection<TermConceptParentChildLink> getParents() {
if (myParents == null) {
myParents = new ArrayList<TermConceptParentChildLink>();

View File

@ -66,6 +66,10 @@ public class TermConceptParentChildLink implements Serializable {
return myChild;
}
public RelationshipTypeEnum getRelationshipType() {
return myRelationshipType;
}
public TermCodeSystemVersion getCodeSystem() {
return myCodeSystem;
}

View File

@ -1,44 +0,0 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.beans.factory.annotation.Required;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
public class BaseJpaPlainProvider extends BaseJpaProvider {
private IFhirSystemDao<?,?> myDao;
public BaseJpaPlainProvider() {
// nothing
}
@Required
public void setDao(IFhirSystemDao<?,?> theDao) {
myDao = theDao;
}
public IFhirSystemDao<?,?> getDao() {
return myDao;
}
}

View File

@ -1,29 +0,0 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
public class BaseJpaResourceProviderQuestionnaireResponseDstu2 extends JpaResourceProviderDstu2<QuestionnaireResponse> {
// nothing yet
}

View File

@ -1,29 +0,0 @@
package ca.uhn.fhir.jpa.provider.dstu3;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public class BaseJpaResourceProviderQuestionnaireResponseDstu3 extends JpaResourceProviderDstu3<QuestionnaireResponse> {
// nothing yet
}

View File

@ -26,7 +26,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
@ -85,7 +84,9 @@ public class TerminologyUploaderProviderDstu3 extends BaseJpaProvider {
} else if (thePackage == null || thePackage.getData() == null || thePackage.getData().length == 0) {
throw new InvalidRequestException("No 'localfile' or 'package' parameter, or package had no data");
} else {
data = Arrays.asList(thePackage.getData());
data = new ArrayList<byte[]>();
data.add(thePackage.getData());
thePackage.setData(null);
}
String url = theUrl != null ? theUrl.getValueAsString() : null;

View File

@ -1,9 +0,0 @@
package ca.uhn.fhir.jpa.search;
import org.hibernate.search.indexes.interceptor.DontInterceptEntityInterceptor;
public class DeferConceptIndexingInterceptor extends DontInterceptEntityInterceptor
//implements EntityIndexingInterceptor<TermConcept>
{
// nothing for now
}

View File

@ -1,42 +0,0 @@
package ca.uhn.fhir.jpa.subscription;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.beans.factory.FactoryBean;
public class SubscriptionWebsocketHandlerFactoryDstu2 implements FactoryBean<ISubscriptionWebsocketHandler> {
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionWebsocketHandlerDstu2.class);
@Override
public ISubscriptionWebsocketHandler getObject() throws Exception {
return new SubscriptionWebsocketHandlerDstu2();
}
@Override
public Class<ISubscriptionWebsocketHandler> getObjectType() {
return ISubscriptionWebsocketHandler.class;
}
@Override
public boolean isSingleton() {
return false;
}
}

View File

@ -1,42 +0,0 @@
package ca.uhn.fhir.jpa.subscription;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.beans.factory.FactoryBean;
public class SubscriptionWebsocketHandlerFactoryDstu3 implements FactoryBean<ISubscriptionWebsocketHandler> {
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionWebsocketHandlerDstu3.class);
@Override
public ISubscriptionWebsocketHandler getObject() throws Exception {
return new SubscriptionWebsocketHandlerDstu3();
}
@Override
public Class<ISubscriptionWebsocketHandler> getObjectType() {
return ISubscriptionWebsocketHandler.class;
}
@Override
public boolean isSingleton() {
return false;
}
}

View File

@ -33,6 +33,7 @@ import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
@ -67,9 +68,13 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
@Autowired
protected ITermConceptDao myConceptDao;
private List<TermConceptParentChildLink> myConceptLinksToSaveLater = new ArrayList<TermConceptParentChildLink>();
@Autowired
private ITermConceptParentChildLinkDao myConceptParentChildLinkDao;
private List<TermConcept> myConceptsToSaveLater = new ArrayList<TermConcept>();
@Autowired
protected FhirContext myContext;
@ -79,6 +84,8 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
protected EntityManager myEntityManager;
private boolean myProcessDeferred = true;
private boolean addToSet(Set<TermConcept> theSetToPopulate, TermConcept theConcept) {
boolean retVal = theSetToPopulate.add(theConcept);
if (retVal) {
@ -197,37 +204,103 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
TermCodeSystemVersion csv = cs.getCurrentVersion();
return csv;
}
private TermCodeSystem getCodeSystem(String theSystem) {
TermCodeSystem cs = myCodeSystemDao.findByCodeSystemUri(theSystem);
return cs;
}
private void parentPids(TermConcept theNextConcept, Set<Long> theParentPids) {
for (TermConceptParentChildLink nextParentLink : theNextConcept.getParents()){
TermConcept parent = nextParentLink.getParent();
if (parent != null && theParentPids.add(parent.getId())) {
parentPids(parent, theParentPids);
}
}
}
private void persistChildren(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack, int theTotalConcepts) {
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
return;
}
if (theConceptsStack.size() % 1000 == 0) {
if (theConceptsStack.size() == 1 || theConceptsStack.size() % 10000 == 0) {
float pct = (float) theConceptsStack.size() / (float) theTotalConcepts;
ourLog.info("Have saved {}/{} concepts ({}%), flushing", theConceptsStack.size(), theTotalConcepts, (int)( pct*100.0f));
myConceptDao.flush();
myConceptParentChildLinkDao.flush();
ourLog.info("Have processed {}/{} concepts ({}%)", theConceptsStack.size(), theTotalConcepts, (int)( pct*100.0f));
}
theConcept.setCodeSystem(theCodeSystem);
theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED);
Set<Long> parentPids = new HashSet<Long>();
parentPids(theConcept, parentPids);
theConcept.setParentPids(parentPids);
if (theConceptsStack.size() <= myDaoConfig.getDeferIndexingForCodesystemsOfSize()) {
myConceptDao.save(theConcept);
} else {
myConceptsToSaveLater.add(theConcept);
}
for (TermConceptParentChildLink next : theConcept.getChildren()) {
persistChildren(next.getChild(), theCodeSystem, theConceptsStack, theTotalConcepts);
}
for (TermConceptParentChildLink next : theConcept.getChildren()) {
if (theConceptsStack.size() <= myDaoConfig.getDeferIndexingForCodesystemsOfSize()) {
myConceptParentChildLinkDao.save(next);
} else {
myConceptLinksToSaveLater.add(next);
}
}
}
private void populateVersion(TermConcept theNext, TermCodeSystemVersion theCodeSystemVersion) {
if (theNext.getCodeSystem() != null) {
return;
}
theNext.setCodeSystem(theCodeSystemVersion);
for (TermConceptParentChildLink next : theNext.getChildren()) {
populateVersion(next.getChild(), theCodeSystemVersion);
}
}
@Scheduled(fixedRate=5000)
@Transactional(propagation=Propagation.REQUIRED)
@Override
public synchronized void saveDeferred() {
if (!myProcessDeferred || ((myConceptsToSaveLater.isEmpty() && myConceptLinksToSaveLater.isEmpty()))) {
return;
}
int codeCount = 0, relCount = 0;
int count = Math.min(myDaoConfig.getDeferIndexingForCodesystemsOfSize(), myConceptsToSaveLater.size());
ourLog.info("Saving {} deferred concepts...", count);
while (codeCount < count && myConceptsToSaveLater.size() > 0) {
TermConcept next = myConceptsToSaveLater.remove(0);
myConceptDao.save(next);
codeCount++;
}
if (codeCount == 0) {
count = Math.min(myDaoConfig.getDeferIndexingForCodesystemsOfSize(), myConceptLinksToSaveLater.size());
ourLog.info("Saving {} deferred concept relationships...", count);
while (relCount < count && myConceptLinksToSaveLater.size() > 0) {
TermConceptParentChildLink next = myConceptLinksToSaveLater.remove(0);
myConceptParentChildLinkDao.save(next);
relCount++;
}
}
ourLog.info("Saved {} deferred concepts ({} remain) and {} deferred relationships ({} remain)", new Object[] {codeCount, myConceptsToSaveLater.size(), relCount, myConceptLinksToSaveLater.size()});
}
@Override
public void setProcessDeferred(boolean theProcessDeferred) {
myProcessDeferred = theProcessDeferred;
}
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void storeNewCodeSystemVersion(Long theCodeSystemResourcePid, String theSystemUri, TermCodeSystemVersion theCodeSystemVersion) {
@ -263,7 +336,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
ourLog.info("Validating all codes in CodeSystem for storage (this can take some time for large sets)");
// Validate the code system
IdentityHashMap<TermConcept, Object> conceptsStack = new IdentityHashMap<TermConcept, Object>();
ArrayList<String> conceptsStack = new ArrayList<String>();
IdentityHashMap<TermConcept, Object> allConcepts = new IdentityHashMap<TermConcept, Object>();
int totalCodeCount = 0;
for (TermConcept next : theCodeSystemVersion.getConcepts()) {
@ -279,11 +352,17 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
codeSystem.setCurrentVersion(theCodeSystemVersion);
codeSystem = myCodeSystemDao.saveAndFlush(codeSystem);
ourLog.info("Setting codesystemversion on {} concepts...", totalCodeCount);
for (TermConcept next : theCodeSystemVersion.getConcepts()) {
populateVersion(next, codeSystemVersion);
}
ourLog.info("Saving {} concepts...", totalCodeCount);
conceptsStack = new IdentityHashMap<TermConcept, Object>();
IdentityHashMap<TermConcept, Object> conceptsStack2 = new IdentityHashMap<TermConcept, Object>();
for (TermConcept next : theCodeSystemVersion.getConcepts()) {
persistChildren(next, codeSystemVersion, conceptsStack, totalCodeCount);
persistChildren(next, codeSystemVersion, conceptsStack2, totalCodeCount);
}
ourLog.info("Done saving concepts, flushing to database");
@ -291,27 +370,6 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
myConceptDao.flush();
myConceptParentChildLinkDao.flush();
ourLog.info("Building multi-axial hierarchy...");
int index = 0;
int totalParents = 0;
for (TermConcept nextConcept : conceptsStack.keySet()) {
if (index++ % 1000 == 0) {
float pct = (float) index / (float) totalCodeCount;
ourLog.info("Have built hierarchy for {}/{} concepts - {}%", index, totalCodeCount, (int)( pct*100.0f));
}
Set<Long> parentPids = new HashSet<Long>();
parentPids(nextConcept, parentPids);
nextConcept.setParentPids(parentPids);
totalParents += parentPids.size();
myConceptDao.save(nextConcept);
}
ourLog.info("Done building hierarchy, found {} parents", totalParents);
/*
* For now we always delete old versions.. At some point it would be nice to allow configuration to keep old versions
*/
@ -324,14 +382,9 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
}
ourLog.info("Done deleting old code system versions");
}
private void parentPids(TermConcept theNextConcept, Set<Long> theParentPids) {
for (TermConceptParentChildLink nextParentLink : theNextConcept.getParents()){
TermConcept parent = nextParentLink.getParent();
if (parent != null && theParentPids.add(parent.getId())) {
parentPids(parent, theParentPids);
}
if (myConceptsToSaveLater.size() > 0 || myConceptLinksToSaveLater.size() > 0) {
ourLog.info("Note that some concept saving was deferred - still have {} concepts and {} relationships", myConceptsToSaveLater.size(), myConceptLinksToSaveLater.size());
}
}
@ -349,15 +402,16 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
return retVal;
}
private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, IdentityHashMap<TermConcept, Object> theConceptsStack,
private int validateConceptForStorage(TermConcept theConcept, TermCodeSystemVersion theCodeSystem, ArrayList<String> theConceptsStack,
IdentityHashMap<TermConcept, Object> theAllConcepts) {
ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystem() != null, "CodesystemValue is null");
ValidateUtil.isTrueOrThrowInvalidRequest(theConcept.getCodeSystem() == theCodeSystem, "CodeSystems are not equal");
ValidateUtil.isNotBlankOrThrowInvalidRequest(theConcept.getCode(), "Codesystem contains a code with no code value");
if (theConceptsStack.put(theConcept, PLACEHOLDER_OBJECT) != null) {
if (theConceptsStack.contains(theConcept.getCode())) {
throw new InvalidRequestException("CodeSystem contains circular reference around code " + theConcept.getCode());
}
theConceptsStack.add(theConcept.getCode());
int retVal = 0;
if (theAllConcepts.put(theConcept, theAllConcepts) == null) {
@ -372,7 +426,7 @@ public abstract class BaseHapiTerminologySvc implements IHapiTerminologySvc {
retVal += validateConceptForStorage(next.getChild(), theCodeSystem, theConceptsStack, theAllConcepts);
}
theConceptsStack.remove(theConcept);
theConceptsStack.remove(theConceptsStack.size() - 1);
return retVal;
}

View File

@ -174,7 +174,7 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
} else if (nextFilter.getOp() == FilterOperator.ISA) {
if (isNotBlank(nextFilter.getValue())) {
TermConcept code = super.findCode(system, nextFilter.getValue());
bool.must(qb.keyword().onField("myParentPids").matching(code.getId()).createQuery());
bool.must(qb.keyword().onField("myParentPids").matching("" + code.getId()).createQuery());
}
} else {
throw new InvalidRequestException("Unknown filter property[" + nextFilter + "] + op[" + nextFilter.getOpElement().getValueAsString() + "]");

View File

@ -48,4 +48,12 @@ public interface IHapiTerminologySvc {
List<TermConcept> findCodes(String theSystem);
void saveDeferred();
/**
* This is mostly for unit tests - we can disable processing of deferred concepts
* by changing this flag
*/
void setProcessDeferred(boolean theProcessDeferred);
}

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.jpa.term;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
@ -24,20 +23,19 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
*/
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@ -56,18 +54,20 @@ import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
import ca.uhn.fhir.jpa.entity.TermConcept;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvc.LoincHierarchyHandler;
import ca.uhn.fhir.jpa.util.Counter;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.CoverageIgnore;
public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
private static final int LOG_INCREMENT = 100000;
public static final String LOINC_FILE = "loinc.csv";
public static final String LOINC_HIERARCHY_FILE = "MULTI-AXIAL_HIERARCHY.CSV";
@ -79,14 +79,7 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
@Autowired
private IHapiTerminologySvc myTermSvc;
private void cleanUpTemporaryFiles(Map<String, File> filenameToFile) {
ourLog.info("Finished terminology file import, cleaning up temporary files");
for (File nextFile : filenameToFile.values()) {
nextFile.delete();
}
}
private void dropCircularRefs(TermConcept theConcept, LinkedHashSet<String> theChain, Map<String, TermConcept> theCode2concept) {
private void dropCircularRefs(TermConcept theConcept, ArrayList<String> theChain, Map<String, TermConcept> theCode2concept, Counter theCircularCounter) {
theChain.add(theConcept.getCode());
for (Iterator<TermConceptParentChildLink> childIter = theConcept.getChildren().iterator(); childIter.hasNext();) {
@ -110,46 +103,25 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
ourLog.info(b.toString(), theConcept.getCode());
childIter.remove();
} else {
dropCircularRefs(nextChild, theChain, theCode2concept);
dropCircularRefs(nextChild, theChain, theCode2concept, theCircularCounter);
}
}
theChain.remove(theConcept.getCode());
theChain.remove(theChain.size() - 1);
}
private Map<String, File> extractFiles(List<byte[]> theZipBytes, List<String> theExpectedFilenameFragments) {
Map<String, File> filenameToFile = new HashMap<String, File>();
private void extractFiles(List<byte[]> theZipBytes, List<String> theExpectedFilenameFragments) {
Set<String> foundFragments = new HashSet<String>();
for (byte[] nextZipBytes : theZipBytes) {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(nextZipBytes)));
try {
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null;) {
ZippedFileInputStream inputStream = new ZippedFileInputStream(zis);
boolean want = false;
for (String next : theExpectedFilenameFragments) {
if (nextEntry.getName().contains(next)) {
want = true;
foundFragments.add(next);
}
}
if (!want) {
ourLog.info("Ignoring zip entry: {}", nextEntry.getName());
continue;
}
ourLog.info("Streaming ZIP entry {} into temporary file", nextEntry.getName());
File nextOutFile = File.createTempFile("hapi_fhir", ".csv");
nextOutFile.deleteOnExit();
OutputStream outputStream = new SinkOutputStream(new FileOutputStream(nextOutFile, false), nextEntry.getName());
try {
IOUtils.copyLarge(inputStream, outputStream);
} finally {
IOUtils.closeQuietly(outputStream);
}
filenameToFile.put(nextEntry.getName(), nextOutFile);
}
} catch (IOException e) {
throw new InternalErrorException(e);
@ -158,10 +130,12 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
}
}
if (filenameToFile.size() != theExpectedFilenameFragments.size()) {
throw new InvalidRequestException("Invalid input zip file, expected zip to contain the following name fragments: " + theExpectedFilenameFragments + " but found: " + filenameToFile.keySet());
for (String next : theExpectedFilenameFragments) {
if (!foundFragments.contains(next)) {
throw new InvalidRequestException("Invalid input zip file, expected zip to contain the following name fragments: " + theExpectedFilenameFragments + " but found: " + foundFragments);
}
return filenameToFile;
}
}
public String firstNonBlank(String... theStrings) {
@ -185,18 +159,24 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
return concept;
}
private void iterateOverZipFile(Map<String, File> theFilenameToFile, String fileNamePart, IRecordHandler handler, char theDelimiter, QuoteMode theQuoteMode) {
private void iterateOverZipFile(List<byte[]> theZipBytes, String fileNamePart, IRecordHandler handler, char theDelimiter, QuoteMode theQuoteMode) {
boolean found = false;
for (Entry<String, File> nextEntry : new HashMap<String, File>(theFilenameToFile).entrySet()) {
if (nextEntry.getKey().contains(fileNamePart)) {
ourLog.info("Processing file {}", nextEntry.getKey());
for (byte[] nextZipBytes : theZipBytes) {
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(nextZipBytes)));
try {
for (ZipEntry nextEntry; (nextEntry = zis.getNextEntry()) != null;) {
ZippedFileInputStream inputStream = new ZippedFileInputStream(zis);
String nextFilename = nextEntry.getName();
if (nextFilename.contains(fileNamePart)) {
ourLog.info("Processing file {}", nextFilename);
found = true;
Reader reader = null;
CSVParser parsed = null;
try {
reader = new BufferedReader(new FileReader(nextEntry.getValue()));
reader = new InputStreamReader(zis, Charsets.UTF_8);
CSVFormat format = CSVFormat.newFormat(theDelimiter).withFirstRecordAsHeader();
if (theQuoteMode != null) {
format = format.withQuote('"').withQuoteMode(theQuoteMode);
@ -206,28 +186,27 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
ourLog.debug("Header map: {}", parsed.getHeaderMap());
int count = 0;
int logIncrement = 100000;
int nextLoggedCount = logIncrement;
int logIncrement = LOG_INCREMENT;
int nextLoggedCount = 0;
while (iter.hasNext()) {
CSVRecord nextRecord = iter.next();
handler.accept(nextRecord);
count++;
if (count >= nextLoggedCount) {
ourLog.info(" * Processed {} records in {}", count, fileNamePart);
ourLog.info(" * Processed {} records in {}", count, nextFilename);
nextLoggedCount += logIncrement;
}
}
ourLog.info("Deleting temporary file: {}", nextEntry.getValue());
nextEntry.getValue().delete();
theFilenameToFile.remove(nextEntry.getKey());
} catch (IOException e) {
throw new InternalErrorException(e);
}
}
}
} catch (IOException e) {
throw new InternalErrorException(e);
} finally {
IOUtils.closeQuietly(parsed);
IOUtils.closeQuietly(reader);
}
IOUtils.closeQuietly(zis);
}
}
@ -239,41 +218,35 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
public UploadStatistics loadLoinc(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
List<String> expectedFilenameFragments = Arrays.asList(LOINC_FILE, LOINC_HIERARCHY_FILE);
Map<String, File> filenameToFile = extractFiles(theZipBytes, expectedFilenameFragments);
extractFiles(theZipBytes, expectedFilenameFragments);
ourLog.info("Beginning LOINC processing");
try {
return processLoincFiles(filenameToFile, theRequestDetails);
} finally {
cleanUpTemporaryFiles(filenameToFile);
}
return processLoincFiles(theZipBytes, theRequestDetails);
}
@Override
public UploadStatistics loadSnomedCt(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
List<String> expectedFilenameFragments = Arrays.asList(SCT_FILE_DESCRIPTION, SCT_FILE_RELATIONSHIP, SCT_FILE_CONCEPT);
Map<String, File> filenameToFile = extractFiles(theZipBytes, expectedFilenameFragments);
extractFiles(theZipBytes, expectedFilenameFragments);
ourLog.info("Beginning SNOMED CT processing");
try {
return processSnomedCtFiles(filenameToFile, theRequestDetails);
} finally {
cleanUpTemporaryFiles(filenameToFile);
}
return processSnomedCtFiles(theZipBytes, theRequestDetails);
}
UploadStatistics processLoincFiles(Map<String, File> filenameToFile, RequestDetails theRequestDetails) {
UploadStatistics processLoincFiles(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
final TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
final Map<String, TermConcept> code2concept = new HashMap<String, TermConcept>();
IRecordHandler handler = new LoincHandler(codeSystemVersion, code2concept);
iterateOverZipFile(filenameToFile, LOINC_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theZipBytes, LOINC_FILE, handler, ',', QuoteMode.NON_NUMERIC);
handler = new LoincHierarchyHandler(codeSystemVersion, code2concept);
iterateOverZipFile(filenameToFile, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
iterateOverZipFile(theZipBytes, LOINC_HIERARCHY_FILE, handler, ',', QuoteMode.NON_NUMERIC);
theZipBytes.clear();
for (Iterator<Entry<String, TermConcept>> iter = code2concept.entrySet().iterator(); iter.hasNext();) {
Entry<String, TermConcept> next = iter.next();
@ -290,39 +263,60 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
ourLog.info("Have {} total concepts, {} root concepts", code2concept.size(), codeSystemVersion.getConcepts().size());
myTermSvc.storeNewCodeSystemVersion(LOINC_URL, codeSystemVersion, theRequestDetails);
String url = LOINC_URL;
storeCodeSystem(theRequestDetails, codeSystemVersion, url);
return new UploadStatistics(code2concept.size());
}
UploadStatistics processSnomedCtFiles(Map<String, File> filenameToFile, RequestDetails theRequestDetails) {
private void storeCodeSystem(RequestDetails theRequestDetails, final TermCodeSystemVersion codeSystemVersion, String url) {
myTermSvc.setProcessDeferred(false);
myTermSvc.storeNewCodeSystemVersion(url, codeSystemVersion, theRequestDetails);
myTermSvc.setProcessDeferred(true);
}
UploadStatistics processSnomedCtFiles(List<byte[]> theZipBytes, RequestDetails theRequestDetails) {
final TermCodeSystemVersion codeSystemVersion = new TermCodeSystemVersion();
final Map<String, TermConcept> id2concept = new HashMap<String, TermConcept>();
final Map<String, TermConcept> code2concept = new HashMap<String, TermConcept>();
final Set<String> validConceptIds = new HashSet<String>();
IRecordHandler handler = new SctHandlerConcept(validConceptIds);
iterateOverZipFile(filenameToFile, SCT_FILE_CONCEPT, handler, '\t', null);
iterateOverZipFile(theZipBytes, SCT_FILE_CONCEPT, handler, '\t', null);
ourLog.info("Have {} valid concept IDs", validConceptIds.size());
handler = new SctHandlerDescription(validConceptIds, code2concept, id2concept, codeSystemVersion);
iterateOverZipFile(filenameToFile, SCT_FILE_DESCRIPTION, handler, '\t', null);
iterateOverZipFile(theZipBytes, SCT_FILE_DESCRIPTION, handler, '\t', null);
ourLog.info("Got {} concepts, cloning map", code2concept.size());
final HashMap<String, TermConcept> rootConcepts = new HashMap<String, TermConcept>(code2concept);
handler = new SctHandlerRelationship(codeSystemVersion, rootConcepts, code2concept);
iterateOverZipFile(filenameToFile, SCT_FILE_RELATIONSHIP, handler, '\t', null);
iterateOverZipFile(theZipBytes, SCT_FILE_RELATIONSHIP, handler, '\t', null);
theZipBytes.clear();
ourLog.info("Looking for root codes");
for (Iterator<Entry<String, TermConcept>> iter = rootConcepts.entrySet().iterator(); iter.hasNext(); ) {
if (iter.next().getValue().getParents().isEmpty() == false) {
iter.remove();
}
}
ourLog.info("Done loading SNOMED CT files - {} root codes, {} total codes", rootConcepts.size(), code2concept.size());
Counter circularCounter = new Counter();
for (TermConcept next : rootConcepts.values()) {
dropCircularRefs(next, new LinkedHashSet<String>(), code2concept);
long count = circularCounter.getThenAdd();
float pct = ((float)count / rootConcepts.size()) * 100.0f;
ourLog.info(" * Scanning for circular refs - have scanned {} / {} codes ({}%)", count, rootConcepts.size(), pct);
dropCircularRefs(next, new ArrayList<String>(), code2concept, circularCounter);
}
codeSystemVersion.getConcepts().addAll(rootConcepts.values());
myTermSvc.storeNewCodeSystemVersion(SCT_URL, codeSystemVersion, theRequestDetails);
String url = SCT_URL;
storeCodeSystem(theRequestDetails, codeSystemVersion, url);
return new UploadStatistics(code2concept.size());
}
@ -332,20 +326,6 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
myTermSvc = theTermSvc;
}
@CoverageIgnore
public static void main(String[] args) throws Exception {
TerminologyLoaderSvc svc = new TerminologyLoaderSvc();
// byte[] bytes = IOUtils.toByteArray(new FileInputStream("/Users/james/Downloads/SnomedCT_Release_INT_20160131_Full.zip"));
// svc.loadSnomedCt(bytes);
Map<String, File> files = new HashMap<String, File>();
files.put(SCT_FILE_CONCEPT, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Concept_Full_INT_20160131.txt"));
files.put(SCT_FILE_DESCRIPTION, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Description_Full-en_INT_20160131.txt"));
files.put(SCT_FILE_RELATIONSHIP, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Relationship_Full_INT_20160131.txt"));
svc.processSnomedCtFiles(files, null);
}
private interface IRecordHandler {
void accept(CSVRecord theRecord);
}
@ -506,23 +486,33 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
String destinationId = theRecord.get("destinationId");
String typeId = theRecord.get("typeId");
boolean active = "1".equals(theRecord.get("active"));
if (!active) {
return;
}
TermConcept typeConcept = myCode2concept.get(typeId);
TermConcept sourceConcept = myCode2concept.get(sourceId);
TermConcept targetConcept = myCode2concept.get(destinationId);
if (sourceConcept != null && targetConcept != null && typeConcept != null) {
if (typeConcept.getDisplay().equals("Is a (attribute)")) {
RelationshipTypeEnum relationshipType = RelationshipTypeEnum.ISA;
if (!sourceId.equals(destinationId)) {
if (active) {
TermConceptParentChildLink link = new TermConceptParentChildLink();
link.setChild(sourceConcept);
link.setParent(targetConcept);
link.setRelationshipType(TermConceptParentChildLink.RelationshipTypeEnum.ISA);
link.setRelationshipType(relationshipType);
link.setCodeSystem(myCodeSystemVersion);
myRootConcepts.remove(link.getChild().getCode());
targetConcept.addChild(sourceConcept, RelationshipTypeEnum.ISA);
targetConcept.addChild(sourceConcept, relationshipType);
} else {
// not active, so we're removing any existing links
for (TermConceptParentChildLink next : new ArrayList<TermConceptParentChildLink>(targetConcept.getChildren())) {
if (next.getRelationshipType() == relationshipType) {
if (next.getChild().getCode().equals(sourceConcept.getCode())) {
next.getParent().getChildren().remove(next);
next.getChild().getParents().remove(next);
}
}
}
}
}
} else if (ignoredTypes.contains(typeConcept.getDisplay())) {
// ignore
@ -534,57 +524,6 @@ public class TerminologyLoaderSvc implements IHapiTerminologyLoaderSvc {
}
private static class SinkOutputStream extends OutputStream {
private static final long LOG_INCREMENT = 10 * FileUtils.ONE_MB;
private int myBytes;
private String myFilename;
private long myNextLogCount = LOG_INCREMENT;
private FileOutputStream myWrap;
public SinkOutputStream(FileOutputStream theWrap, String theFilename) {
myWrap = theWrap;
myFilename = theFilename;
}
private void addCount(int theCount) {
myBytes += theCount;
if (myBytes > myNextLogCount) {
ourLog.info(" * Wrote {} of {}", FileUtils.byteCountToDisplaySize(myBytes), myFilename);
myNextLogCount = myBytes + LOG_INCREMENT;
}
}
@Override
public void close() throws IOException {
myWrap.close();
}
@Override
public void flush() throws IOException {
myWrap.flush();
}
@Override
public void write(byte[] theB) throws IOException {
myWrap.write(theB);
addCount(theB.length);
}
@Override
public void write(byte[] theB, int theOff, int theLen) throws IOException {
myWrap.write(theB, theOff, theLen);
addCount(theLen);
}
@Override
public void write(int theB) throws IOException {
myWrap.write(theB);
addCount(1);
}
}
private static class ZippedFileInputStream extends InputStream {
private ZipInputStream is;

View File

@ -0,0 +1,11 @@
package ca.uhn.fhir.jpa.util;
public class Counter {
private long myCount;
public long getThenAdd() {
return myCount++;
}
}

View File

@ -1,65 +0,0 @@
package ca.uhn.fhir.jpa.util;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hibernate.cfg.ImprovedNamingStrategy;
public class CustomNamingStrategy extends ImprovedNamingStrategy {
private static final long serialVersionUID = 1L;
private static final String PREFIX = "FR_";
// @Override
// public String classToTableName(final String className) {
// return this.addPrefix(super.classToTableName(className));
// }
//
// @Override
// public String collectionTableName(final String ownerEntity,
// final String ownerEntityTable, final String associatedEntity,
// final String associatedEntityTable, final String propertyName) {
// return this.addPrefix(super.collectionTableName(ownerEntity,
// ownerEntityTable, associatedEntity, associatedEntityTable,
// propertyName));
// }
//
// @Override
// public String foreignKeyColumnName(String thePropertyName, String thePropertyEntityName, String thePropertyTableName, String theReferencedColumnName) {
// String foreignKeyColumnName = super.foreignKeyColumnName(thePropertyName, thePropertyEntityName, thePropertyTableName, theReferencedColumnName);
// return foreignKeyColumnName;
// }
//
// @Override
// public String logicalCollectionTableName(final String tableName,
// final String ownerEntityTable, final String associatedEntityTable,
// final String propertyName) {
// return this.addPrefix(super.logicalCollectionTableName(tableName,
// ownerEntityTable, associatedEntityTable, propertyName));
// }
//
// private String addPrefix(final String composedTableName) {
//
// return PREFIX
// + composedTableName.toUpperCase().replace("_", "");
//
// }
}

View File

@ -1,36 +0,0 @@
package ca.uhn.fhir.jpa.util;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2016 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hibernate.dialect.DerbyTenSevenDialect;
/**
* As of Hibernate 5.0.1, DerbyTenSevenDialect doesn't seem to work when updating
* the schema, as it tries to create a duplicate schema
*/
public class HapiDerbyTenSevenDialect extends DerbyTenSevenDialect {
@Override
public String getQuerySequencesString() {
return "select SEQUENCENAME from sys.syssequences";
}
}

View File

@ -9,7 +9,6 @@ import static org.junit.Assert.fail;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.hl7.fhir.dstu3.model.AuditEvent;
import org.hl7.fhir.dstu3.model.CodeSystem;
@ -22,11 +21,13 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu3.model.ValueSet.FilterOperator;
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
@ -339,6 +340,42 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
assertEquals(URL_MY_CODE_SYSTEM, result.getExpansion().getContains().get(idx).getSystem());
}
@Test
public void testIndexingIsDeferredForLargeCodeSystems() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(1);
myTermSvc.setProcessDeferred(false);
createExternalCsAndLocalVs();
ValueSet vs = new ValueSet();
ConceptSetComponent include = vs.getCompose().addInclude();
include.setSystem(URL_MY_CODE_SYSTEM);
include.addFilter().setProperty("display").setOp(FilterOperator.ISA).setValue("ParentA");
ValueSet result = myValueSetDao.expand(vs, null);
String encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
assertEquals(0, result.getExpansion().getContains().size());
myTermSvc.setProcessDeferred(true);
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
myTermSvc.saveDeferred();
result = myValueSetDao.expand(vs, null);
encoded = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result);
ourLog.info(encoded);
assertEquals(4, result.getExpansion().getContains().size());
}
@Test
public void testExpandWithExcludeInExternalValueSet() {
createExternalCsAndLocalVs();
@ -487,6 +524,11 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
myDaoConfig.setMaximumExpansionSize(5000);
}
@After
public void after() {
myDaoConfig.setDeferIndexingForCodesystemsOfSize(new DaoConfig().getDeferIndexingForCodesystemsOfSize());
}
@Test
public void testSearchCodeBelowLocalCodesystem() {
createLocalCsAndVs();

View File

@ -185,22 +185,22 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
List<String> idValues;
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient/" + id.getIdPart() + "/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
assertThat(idValues.toString(), idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/Patient/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
assertThat(idValues.toString(), idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
assertThat(idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
assertThat(idValues.toString(), idValues, contains(ids.get(2), ids.get(1), ids.get(0)));
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/_history?_at=gt2060");
assertThat(idValues, empty());
assertThat(idValues.toString(), idValues, empty());
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/_history?_at=" + InstantDt.withCurrentTime().getYear());
assertThat(idValues, hasSize(10)); // 10 is the page size
assertThat(idValues.toString(), idValues, hasSize(10)); // 10 is the page size
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/_history?_at=ge" + InstantDt.withCurrentTime().getYear());
assertThat(idValues, hasSize(10));
assertThat(idValues.toString(), idValues, hasSize(10));
idValues = searchAndReturnUnqualifiedIdValues(ourServerBase + "/_history?_at=gt" + InstantDt.withCurrentTime().getYear());
assertThat(idValues, hasSize(0));

View File

@ -34,7 +34,7 @@ public class TerminologyLoaderSvcIntegrationTest extends BaseJpaDstu3Test {
files.put(TerminologyLoaderSvc.SCT_FILE_CONCEPT, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Concept_Full_INT_20160131.txt"));
files.put(TerminologyLoaderSvc.SCT_FILE_DESCRIPTION, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Description_Full-en_INT_20160131.txt"));
files.put(TerminologyLoaderSvc.SCT_FILE_RELATIONSHIP, new File("/Users/james/tmp/sct/SnomedCT_Release_INT_20160131_Full/Terminology/sct2_Relationship_Full_INT_20160131.txt"));
myLoader.processSnomedCtFiles(files, mySrd);
// myLoader.processSnomedCtFiles(files, mySrd);
}
}

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.term;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInRelativeOrder;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
@ -12,8 +13,10 @@ import static org.mockito.Mockito.verify;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@ -62,18 +65,18 @@ public class TerminologyLoaderSvcTest {
public void testLoadLoinc() throws Exception {
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
ZipOutputStream zos1 = new ZipOutputStream(bos1);
addEntry(zos1,"/loinc/", "loinc.csv");
addEntry(zos1, "/loinc/", "loinc.csv");
zos1.close();
ourLog.info("ZIP file has {} bytes", bos1.toByteArray().length);
ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
ZipOutputStream zos2 = new ZipOutputStream(bos2);
addEntry(zos2,"/loinc/", "LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV");
addEntry(zos2, "/loinc/", "LOINC_2.54_MULTI-AXIAL_HIERARCHY.CSV");
zos2.close();
ourLog.info("ZIP file has {} bytes", bos2.toByteArray().length);
RequestDetails details = mock(RequestDetails.class);
mySvc.loadLoinc(Arrays.asList(bos1.toByteArray(), bos2.toByteArray()), details);
mySvc.loadLoinc(list(bos1.toByteArray(), bos2.toByteArray()), details);
}
@Test
@ -84,38 +87,48 @@ public class TerminologyLoaderSvcTest {
addEntry(zos, "/sct/", "sct2_Concept_Full-en_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Description_Full-en_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Identifier_Full_INT_20160131.txt");
addEntry(zos,"/sct/", "sct2_Relationship_Full_INT_20160131.txt");
addEntry(zos,"/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_Relationship_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_StatedRelationship_Full_INT_20160131.txt");
addEntry(zos, "/sct/", "sct2_TextDefinition_Full-en_INT_20160131.txt");
zos.close();
ourLog.info("ZIP file has {} bytes", bos.toByteArray().length);
RequestDetails details = mock(RequestDetails.class);
mySvc.loadSnomedCt(Collections.singletonList(bos.toByteArray()), details);
mySvc.loadSnomedCt(list(bos.toByteArray()), details);
verify(myTermSvc).storeNewCodeSystemVersion(any(String.class), myCsvCaptor.capture(), any(RequestDetails.class));
TermCodeSystemVersion csv = myCsvCaptor.getValue();
TreeSet<String> allCodes = toCodes(csv);
TreeSet<String> allCodes = toCodes(csv, true);
ourLog.info(allCodes.toString());
assertThat(allCodes, containsInRelativeOrder("116680003"));
assertThat(allCodes, not(containsInRelativeOrder("207527008")));
allCodes = toCodes(csv, false);
ourLog.info(allCodes.toString());
assertThat(allCodes, hasItem("126816002"));
}
private TreeSet<String> toCodes(TermCodeSystemVersion theCsv) {
private List<byte[]> list(byte[]... theByteArray) {
return new ArrayList<byte[]>(Arrays.asList(theByteArray));
}
private TreeSet<String> toCodes(TermCodeSystemVersion theCsv, boolean theAddChildren) {
TreeSet<String> retVal = new TreeSet<String>();
for (TermConcept next : theCsv.getConcepts()) {
toCodes(retVal, next);
toCodes(retVal, next, theAddChildren);
}
return retVal;
}
private void toCodes(TreeSet<String> theCodes, TermConcept theConcept) {
private void toCodes(TreeSet<String> theCodes, TermConcept theConcept, boolean theAddChildren) {
theCodes.add(theConcept.getCode());
if (theAddChildren) {
for (TermConceptParentChildLink next : theConcept.getChildren()) {
toCodes(theCodes, next.getChild());
toCodes(theCodes, next.getChild(), theAddChildren);
}
}
}
@ -146,5 +159,4 @@ public class TerminologyLoaderSvcTest {
zos.closeEntry();
}
}

View File

@ -13,6 +13,7 @@ id effectiveTime active moduleId definitionStatusId
126813005 20020131 1 900000000000207008 900000000000074008
126813006 20020131 1 900000000000207008 900000000000074008
126817006 20020131 1 900000000000207008 900000000000074008
126816002 20020131 1 900000000000207008 900000000000074008
207527008 20020131 1 900000000000207008 900000000000074008
207527008 20040731 1 900000000000207008 900000000000073002
207527008 20090731 0 900000000000207008 900000000000074008

View File

@ -1,5 +1,6 @@
id effectiveTime active moduleId sourceId destinationId relationshipGroup typeId characteristicTypeId modifierId
100022 20020131 1 900000000000207008 126815003 126813005 0 116680003 900000000000011006 900000000000451002
100022 20090731 0 900000000000207008 126816002 126813005 0 116680003 900000000000011006 900000000000451002
100025 20020131 1 900000000000207008 126816002 126813005 0 116680003 900000000000011006 900000000000451002
100025 20090731 0 900000000000207008 126816002 126813005 0 116680003 900000000000011006 900000000000451002
101021 20020131 1 900000000000207008 126817006 126815003 0 116680003 900000000000011006 900000000000451002
101021 20020131 1 900000000000207008 126815003 126817006 0 116680003 900000000000011006 900000000000451002

View File

@ -44,6 +44,7 @@ import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.AllergyIntolerance;
import ca.uhn.fhir.model.dstu.resource.Binary;
import ca.uhn.fhir.model.dstu.resource.CarePlan;
import ca.uhn.fhir.model.dstu.resource.Composition;
import ca.uhn.fhir.model.dstu.resource.Condition;
import ca.uhn.fhir.model.dstu.resource.Conformance;
@ -67,6 +68,7 @@ import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.IdrefDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
@ -95,6 +97,21 @@ public class XmlParserTest {
}
@Test
public void testEncodeAndParseIdref() {
CarePlan cp = new CarePlan();
cp.addGoal().setNotes("Goal Notes").setElementSpecificId("goalId0");
IdrefDt idref = new IdrefDt();
idref.setValue("#goalId0");
idref.setTarget(cp);
idref.getTarget();
cp.addActivity().getGoal().add(idref);
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(cp);
ourLog.info(encoded);
}
/**
* Test for #82 - Not yet enabled because the test won't pass
*/

View File

@ -32,7 +32,7 @@ import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerExcept
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.TestUtil;
public class ClientServerValidationTestDstu {
public class ClientServerValidationDstu1Test {
private FhirContext myCtx;
private HttpClient myHttpClient;

View File

@ -15,7 +15,9 @@ import java.io.InputStream;
import java.io.StringReader;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
@ -33,6 +35,7 @@ import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -82,6 +85,8 @@ public class GenericClientTest {
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
System.setProperty(BaseClient.HAPI_CLIENT_KEEPRESPONSES, "true");
}
private String extractBody(ArgumentCaptor<HttpUriRequest> capt, int count) throws IOException {
@ -89,6 +94,24 @@ public class GenericClientTest {
return body;
}
@Test
public void testInvalidCalls() {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.meta();
fail();
} catch (IllegalStateException e) {
assertEquals("Can not call $meta operations on a DSTU1 client", e.getMessage());
}
try {
client.operation();
fail();
} catch (IllegalStateException e) {
assertEquals("Operations are only supported in FHIR DSTU2 and later. This client was created using a context configured for DSTU1", e.getMessage());
}
}
private String getPatientFeedWithOneResult() {
//@formatter:off
String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
@ -155,6 +178,9 @@ public class GenericClientTest {
resp = client.create().resource(ourCtx.newXmlParser().encodeResourceToString(p1)).execute();
assertNull(resp.getCreated());
ourLog.info("lastRequest: {}", ((GenericClient)client).getLastRequest());
ourLog.info("lastResponse: {}", ((GenericClient)client).getLastResponse());
ourLog.info("lastResponseBody: {}", ((GenericClient)client).getLastResponseBody());
}
@Test
@ -1471,6 +1497,25 @@ public class GenericClientTest {
}
@SuppressWarnings("deprecation")
@Test
public void testTransactionOldStyle() throws Exception {
String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json"));
Bundle bundle = ourCtx.newJsonParser().parseBundle(bundleStr);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(bundleStr), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
List<IBaseResource> input = new ArrayList<IBaseResource>();
input.addAll(bundle.toListOfResources());
client.transaction(input);
}
@Test
public void testTransactionJson() throws Exception {
String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json"));

View File

@ -10,11 +10,25 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.reflect.ClassPath;
import com.google.common.reflect.ClassPath.ClassInfo;
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
import ca.uhn.fhir.util.TestUtil;
public class ExceptionPropertiesTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionPropertiesTest.class);
@Test
public void testConstructors() {
new FhirClientConnectionException("");
new FhirClientConnectionException("", new Exception());
new FhirClientConnectionException(new Exception());
new NotImplementedOperationException("");
new NotImplementedOperationException(null, new OperationOutcome());
new FhirClientInappropriateForServerException(new Exception());
new FhirClientInappropriateForServerException("", new Exception());
}
@SuppressWarnings("deprecation")
@Test
public void testExceptionsAreGood() throws Exception {

View File

@ -11,6 +11,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.AdministrativeGenderEnum;
import ca.uhn.fhir.model.dstu2.valueset.MaritalStatusCodesEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.util.TestUtil;
public class FhirContextDstu2Test {
@ -23,6 +24,12 @@ public class FhirContextDstu2Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Test(expected=DataFormatException.class)
public void testScanInvalid() {
FhirContext ctx = FhirContext.forDstu2();
ctx.getResourceDefinition("InvalidResource");
}
@Test
public void testQueryBoundCode() {

View File

@ -0,0 +1,15 @@
package ca.uhn.fhir.model.primitive;
import static org.junit.Assert.*;
import org.junit.Test;
public class TimeDtTest {
@Test
public void testEncode() {
TimeDt dt = new TimeDt("11:33:01.123");
assertEquals("11:33:01.123", dt.getValue());
}
}

View File

@ -37,9 +37,9 @@ import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.util.TestUtil;
public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
public class DefaultThymeleafNarrativeGeneratorDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultThymeleafNarrativeGeneratorTestDstu2.class);
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultThymeleafNarrativeGeneratorDstu2Test.class);
private DefaultThymeleafNarrativeGenerator myGen;
@AfterClass

View File

@ -1,7 +1,12 @@
package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -32,16 +37,15 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
import ca.uhn.fhir.util.TestUtil;
public class ClientServerValidationTestDstu2 {
public class ClientServerValidationDstu2Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientServerValidationTestDstu2.class);
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ClientServerValidationDstu2Test.class);
private FhirContext myCtx;
private boolean myFirstResponse;
private HttpClient myHttpClient;

View File

@ -19,6 +19,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.io.IOUtils;
@ -45,18 +46,20 @@ import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu2.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Conformance.Rest;
import ca.uhn.fhir.model.dstu2.resource.Conformance.RestSecurity;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Encounter;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
@ -68,15 +71,19 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.XmlParserDstu2Test;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.method.SearchStyleEnum;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
@ -84,28 +91,29 @@ import ca.uhn.fhir.util.TestUtil;
public class GenericClientDstu2Test {
private static FhirContext ourCtx;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientDstu2Test.class);
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientDstu2Test.class);
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
private int myResponseCount = 0;
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ourCtx.setRestfulClientFactory(new ApacheRestfulClientFactory(ourCtx));
ourCtx.getRestfulClientFactory().setConnectionRequestTimeout(10000);
ourCtx.getRestfulClientFactory().setConnectTimeout(10000);
ourCtx.getRestfulClientFactory().setPoolMaxPerRoute(100);
ourCtx.getRestfulClientFactory().setPoolMaxTotal(100);
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
myResponseCount = 0;
System.setProperty(BaseClient.HAPI_CLIENT_KEEPRESPONSES, "true");
}
private String extractBody(ArgumentCaptor<HttpUriRequest> capt, int count) throws IOException {
@ -113,7 +121,6 @@ public class GenericClientDstu2Test {
return body;
}
private String getPatientFeedWithOneResult() {
//@formatter:off
String msg = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
@ -177,70 +184,6 @@ public class GenericClientDstu2Test {
idx++;
}
/**
* See #322
*/
@Test
public void testFetchConformanceWithSmartExtensions() throws Exception {
final String respString = IOUtils.toString(GenericClientDstu2Test.class.getResourceAsStream("/conformance_322.json"));
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:8080/fhir");
Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
Rest rest = conf.getRest().get(0);
RestSecurity security = rest.getSecurity();
List<ExtensionDt> ext = security.getUndeclaredExtensionsByUrl("http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris");
List<ExtensionDt> tokenExts = ext.get(0).getUndeclaredExtensionsByUrl("token");
ExtensionDt tokenExt = tokenExts.get(0);
UriDt value = (UriDt) tokenExt.getValue();
assertEquals("https://my-server.org/token", value.getValueAsString());
}
/**
* See #322
*/
@Test
public void testFetchConformanceWithSmartExtensionsAltCase() throws Exception {
final String respString = IOUtils.toString(GenericClientDstu2Test.class.getResourceAsStream("/conformance_322.json")).replace("valueuri", "valueUri");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:8080/fhir");
Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
Rest rest = conf.getRest().get(0);
RestSecurity security = rest.getSecurity();
List<ExtensionDt> ext = security.getUndeclaredExtensionsByUrl("http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris");
List<ExtensionDt> tokenExts = ext.get(0).getUndeclaredExtensionsByUrl("token");
ExtensionDt tokenExt = tokenExts.get(0);
UriDt value = (UriDt) tokenExt.getValue();
assertEquals("https://my-server.org/token", value.getValueAsString());
}
@Test
public void testAcceptHeaderPreflightConformance() throws Exception {
String methodName = "testAcceptHeaderPreflightConformance";
@ -540,6 +483,30 @@ public class GenericClientDstu2Test {
assertEquals("Patient/123", output.getResource().getIdElement().toUnqualifiedVersionless().getValue());
}
@Test
public void testDeleteByResource() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_204_NO_CONTENT, ""));
when(myHttpResponse.getEntity().getContent()).then(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
Patient pat = new Patient();
pat.setId("Patient/123");
client.delete().resource(pat).execute();
assertEquals("DELETE", capt.getAllValues().get(idx).getMethod());
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
}
@Test
public void testDeleteConditional() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -575,6 +542,49 @@ public class GenericClientDstu2Test {
}
@Test
public void testDeleteInvalidRequest() throws Exception {
Patient pat = new Patient();
pat.setId("123");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.delete().resource(pat).execute();
fail();
} catch (IllegalArgumentException e){
assertEquals("theResource.getId() must contain a resource type and logical ID at a minimum (e.g. Patient/1234), found: 123", e.getMessage());
}
try {
client.delete().resourceById(new IdDt("123")).execute();
fail();
} catch (IllegalArgumentException e){
assertEquals("theId must contain a resource type and logical ID at a minimum (e.g. Patient/1234)found: 123", e.getMessage());
}
try {
client.delete().resourceById("", "123").execute();
fail();
} catch (IllegalArgumentException e){
assertEquals("theResourceType can not be blank/null", e.getMessage());
}
try {
client.delete().resourceById("Patient", "").execute();
fail();
} catch (IllegalArgumentException e){
assertEquals("theLogicalId can not be blank/null", e.getMessage());
}
try {
client.delete().resourceConditionalByType("InvalidType");
fail();
} catch (DataFormatException e){
assertEquals("Unknown resource name \"InvalidType\" (this name is not known in FHIR version \"DSTU2\")", e.getMessage());
}
}
@SuppressWarnings("deprecation")
@Test
public void testDeleteNonFluent() throws Exception {
@ -604,6 +614,68 @@ public class GenericClientDstu2Test {
}
/**
* See #322
*/
@Test
public void testFetchConformanceWithSmartExtensions() throws Exception {
final String respString = IOUtils.toString(GenericClientDstu2Test.class.getResourceAsStream("/conformance_322.json"));
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:8080/fhir");
Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
Rest rest = conf.getRest().get(0);
RestSecurity security = rest.getSecurity();
List<ExtensionDt> ext = security.getUndeclaredExtensionsByUrl("http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris");
List<ExtensionDt> tokenExts = ext.get(0).getUndeclaredExtensionsByUrl("token");
ExtensionDt tokenExt = tokenExts.get(0);
UriDt value = (UriDt) tokenExt.getValue();
assertEquals("https://my-server.org/token", value.getValueAsString());
}
/**
* See #322
*/
@Test
public void testFetchConformanceWithSmartExtensionsAltCase() throws Exception {
final String respString = IOUtils.toString(GenericClientDstu2Test.class.getResourceAsStream("/conformance_322.json")).replace("valueuri", "valueUri");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:8080/fhir");
Conformance conf = client.fetchConformance().ofType(Conformance.class).execute();
Rest rest = conf.getRest().get(0);
RestSecurity security = rest.getSecurity();
List<ExtensionDt> ext = security.getUndeclaredExtensionsByUrl("http://fhir-registry.smarthealthit.org/StructureDefinition/oauth-uris");
List<ExtensionDt> tokenExts = ext.get(0).getUndeclaredExtensionsByUrl("token");
ExtensionDt tokenExt = tokenExts.get(0);
UriDt value = (UriDt) tokenExt.getValue();
assertEquals("https://my-server.org/token", value.getValueAsString());
}
@Test
public void testHistory() throws Exception {
@ -709,6 +781,16 @@ public class GenericClientDstu2Test {
idx++;
}
@Test
public void testInvalidClient() {
try {
ourCtx.getRestfulClientFactory().newClient(RestfulClientInstance.class, "http://foo");
fail();
} catch (ConfigurationException e) {
assertEquals("ca.uhn.fhir.context.ConfigurationException: ca.uhn.fhir.rest.client.GenericClientDstu2Test.RestfulClientInstance is not an interface", e.toString());
}
}
@Test
public void testMetaAdd() throws Exception {
IParser p = ourCtx.newXmlParser();
@ -1576,6 +1658,24 @@ public class GenericClientDstu2Test {
assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue());
}
@Test
public void testReadForUnknownType() throws Exception {
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
try {
client.read(new UriDt("1"));
fail();
} catch (IllegalArgumentException e) {
assertEquals("The given URI is not an absolute URL and is not usable for this operation: 1", e.getMessage());
}
try {
client.read(new UriDt("http://example.com/InvalidResource/1"));
fail();
} catch (DataFormatException e) {
assertEquals("Unknown resource name \"InvalidResource\" (this name is not known in FHIR version \"DSTU2\")", e.getMessage());
}
}
@Test
public void testReadUpdatedHeaderDoesntOverwriteResourceValue() throws Exception {
@ -1699,6 +1799,76 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchByNumber() throws Exception {
final String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).then(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.greaterThan().number(123))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=gt123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.lessThan().number(123))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=lt123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.greaterThanOrEqual().number("123"))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=ge123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.lessThanOrEqual().number("123"))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=le123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.exactly().number(123))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=123", capt.getAllValues().get(idx).getURI().toString());
idx++;
}
@Test
public void testSearchByPost() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
@ -1805,75 +1975,6 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchByNumber() throws Exception {
final String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).then(new Answer<InputStream>() {
@Override
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
}});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.greaterThan().number(123))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=gt123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.lessThan().number(123))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=lt123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.greaterThanOrEqual().number("123"))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=ge123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.lessThanOrEqual().number("123"))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=le123", capt.getAllValues().get(idx).getURI().toString());
idx++;
//@formatter:off
client.search()
.forResource("Encounter")
.where(Encounter.LENGTH.exactly().number(123))
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Encounter?length=123", capt.getAllValues().get(idx).getURI().toString());
idx++;
}
@Test
public void testSearchByUrl() throws Exception {
@ -2035,6 +2136,27 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchWithMap() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
HashMap<String, List<IQueryParameterType>> params = new HashMap<String, List<IQueryParameterType>>();
params.put("foo", Arrays.asList((IQueryParameterType)new DateParam("2001")));
Bundle response = client.search(Patient.class, params);
assertEquals("http://example.com/fhir/Patient?foo=2001", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchWithProfileAndSecurity() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
@ -2521,9 +2643,61 @@ public class GenericClientDstu2Test {
return (OperationOutcome) theOperationOutcome;
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() {
ourCtx = FhirContext.forDstu2();
}
public final static class RestfulClientInstance implements IRestfulClient {
@Override
public <T extends IBaseResource> T fetchResourceFromUrl(Class<T> theResourceType, String theUrl) {
return null;
}
@Override
public FhirContext getFhirContext() {
return null;
}
@Override
public IHttpClient getHttpClient() {
return null;
}
@Override
public String getServerBase() {
return null;
}
@Override
public void registerInterceptor(IClientInterceptor theInterceptor) {
//nothing
}
@Override
public void setEncoding(EncodingEnum theEncoding) {
//nothing
}
@Override
public void setPrettyPrint(Boolean thePrettyPrint) {
//nothing
}
@Override
public void setSummary(SummaryEnum theSummary) {
//nothing
}
@Override
public void unregisterInterceptor(IClientInterceptor theInterceptor) {
//nothing
}
}
}

View File

@ -0,0 +1,40 @@
package ca.uhn.fhir.rest.client.apache;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.BaseClient;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
public class ApacheRestfulClientFactoryTest {
@Test
public void testSetContext() {
ApacheRestfulClientFactory factory = new ApacheRestfulClientFactory();
factory.getServerValidationModeEnum();
factory.setFhirContext(FhirContext.forDstu2());
try {
factory.setFhirContext(FhirContext.forDstu2());
fail();
} catch (IllegalStateException e) {
assertEquals("java.lang.IllegalStateException: RestfulClientFactory instance is already associated with one FhirContext. RestfulClientFactory instances can not be shared.", e.toString());
}
}
@Test
public void testValidatateBase() {
FhirContext ctx = FhirContext.forDstu2();
ApacheRestfulClientFactory factory = new ApacheRestfulClientFactory();
factory.setFhirContext(ctx);
factory.setConnectTimeout(1);
try {
factory.validateServerBase("http://127.0.0.1:22225", factory.getHttpClient("http://foo"), (BaseClient) ctx.newRestfulGenericClient("http://foo"));
fail();
} catch (FhirClientConnectionException e) {
assertEquals("Failed to retrieve the server metadata statement during client initialization. URL used was http://127.0.0.1:22225metadata", e.getMessage());
}
}
}

View File

@ -18,6 +18,7 @@ import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.TestUtil;
@ -62,6 +63,51 @@ public class ServerInvalidDefinitionDstu2Test {
}
}
@Test
public void testWrongResourceType() {
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.setResourceProviders(new UpdateWithWrongResourceType());
try {
srv.init();
fail();
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains.containsString("Method 'update' is annotated with @ResourceParam but has a type that is not an implemtation of org.hl7.fhir.instance.model.api.IBaseResource or String or byte[]"));
}
}
@Test
public void testWrongValidateModeType() {
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.setResourceProviders(new ValidateWithWrongModeType());
try {
srv.init();
fail();
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains.containsString("Parameter annotated with @Validate.Mode must be of type ca.uhn.fhir.rest.api.ValidationModeEnum"));
}
}
@Test
public void testWrongValidateProfileType() {
RestfulServer srv = new RestfulServer(ourCtx);
srv.setFhirContext(ourCtx);
srv.setResourceProviders(new ValidateWithWrongProfileType());
try {
srv.init();
fail();
} catch (ServletException e) {
assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
assertThat(e.getCause().toString(), StringContains.containsString("Parameter annotated with @Validate.Profile must be of type java.lang.String"));
}
}
public static class OperationReturningOldBundleProvider implements IResourceProvider {
@Override
@ -90,4 +136,46 @@ public class ServerInvalidDefinitionDstu2Test {
}
public static class UpdateWithWrongResourceType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Update
public MethodOutcome update(@ResourceParam Integer theParam2) {
return null;
}
}
public static class ValidateWithWrongModeType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Validate
public MethodOutcome update(@ResourceParam Patient thePatient, @Validate.Mode Integer theParam2) {
return null;
}
}
public static class ValidateWithWrongProfileType implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Validate
public MethodOutcome update(@ResourceParam Patient thePatient, @Validate.Profile Integer theParam2) {
return null;
}
}
}

View File

@ -40,6 +40,7 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
@ -47,6 +48,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
@ -158,6 +160,215 @@ public class AuthorizationInterceptorDstu2Test {
assertTrue(ourHitMethod);
}
@Test
public void testOperationServerLevel() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("RULE 1").operation().named("opName").onServer().andThen()
.build();
//@formatter:on
}
});
HttpGet httpGet;
HttpResponse status;
String response;
// Server
ourHitMethod = false;
ourReturn = Arrays.asList(createObservation(10, "Patient/2"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
status = ourClient.execute(httpGet);
extractResponseAndClose(status);
assertEquals(200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
// Type
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Instance
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
}
@Test
public void testOperationInstanceLevel() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("RULE 1").operation().named("opName").onInstance(new IdDt("http://example.com/Patient/1/_history/2")).andThen()
.build();
//@formatter:on
}
});
HttpGet httpGet;
HttpResponse status;
String response;
// Server
ourHitMethod = false;
ourReturn = Arrays.asList(createObservation(10, "Patient/2"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Type
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Instance
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertEquals(200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
// Wrong instance
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
}
@Test
public void testOperationAnyName() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("RULE 1").operation().withAnyName().onServer().andThen()
.build();
//@formatter:on
}
});
HttpGet httpGet;
HttpResponse status;
String response;
// Server
ourHitMethod = false;
ourReturn = Arrays.asList(createObservation(10, "Patient/2"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
assertEquals(200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
}
@Test
public void testOperationTypeLevel() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
//@formatter:off
return new RuleBuilder()
.allow("RULE 1").operation().named("opName").onType(Patient.class).andThen()
.build();
//@formatter:on
}
});
HttpGet httpGet;
HttpResponse status;
String response;
// Server
ourHitMethod = false;
ourReturn = Arrays.asList(createObservation(10, "Patient/2"));
httpGet = new HttpGet("http://localhost:" + ourPort + "/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Type
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertEquals(200, status.getStatusLine().getStatusCode());
assertTrue(ourHitMethod);
// Wrong type
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/1/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Wrong name
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName2");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
// Instance
ourHitMethod = false;
ourReturn = Arrays.asList(createPatient(2));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/$opName");
status = ourClient.execute(httpGet);
response = extractResponseAndClose(status);
ourLog.info(response);
assertThat(response, containsString("Access denied by default policy"));
assertEquals(403, status.getStatusLine().getStatusCode());
assertFalse(ourHitMethod);
}
@Test
public void testDenyAll() throws Exception {
ourServlet.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
@ -762,6 +973,17 @@ public class AuthorizationInterceptorDstu2Test {
retVal.setResource(theResource);
return retVal;
}
@Operation(name="opName", idempotent=true)
public Parameters operation() {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
@Operation(name="opName", idempotent=true)
public Parameters operation(@IdParam IdDt theId) {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
}
@ -814,10 +1036,36 @@ public class AuthorizationInterceptorDstu2Test {
return retVal;
}
@Operation(name="opName", idempotent=true)
public Parameters operation() {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
@Operation(name="opName", idempotent=true)
public Parameters operation(@IdParam IdDt theId) {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
@Operation(name="opName2", idempotent=true)
public Parameters operation2(@IdParam IdDt theId) {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
}
public static class PlainProvider
{
@Operation(name="opName", idempotent=true)
public Parameters operation() {
ourHitMethod = true;
return (Parameters) new Parameters().setId("1");
}
@Transaction()
public Bundle search(@TransactionParam Bundle theInput) {
ourHitMethod = true;

View File

@ -1,4 +1,9 @@
package ca.uhn.fhir.validation;
package ca.uhn.fhir.parser;
import org.junit.Test;
import ca.uhn.fhir.parser.ErrorHandlerAdapter;
import ca.uhn.fhir.parser.IParserErrorHandler;
/*
* #%L
@ -20,16 +25,15 @@ package ca.uhn.fhir.validation;
* #L%
*/
public class Problem {
/**
* Adapter implementation with NOP implementations of all {@link IParserErrorHandler} methods.
*/
public class ErrorHandlerAdapterTest {
private String myDescription;
public Problem(String theDescription) {
myDescription=theDescription;
@Test
public void testMethods() {
new ErrorHandlerAdapter().unexpectedRepeatingElement(null, null);
new ErrorHandlerAdapter().unknownAttribute(null, null);
new ErrorHandlerAdapter().unknownElement(null, null);
}
public String getDescription() {
return myDescription;
}
}

View File

@ -0,0 +1,122 @@
package ca.uhn.fhir.rest.client;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.TestUtil;
public class NonGenericClientDstu3Test {
private static FhirContext ourCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
System.setProperty(BaseClient.HAPI_CLIENT_KEEPRESPONSES, "true");
}
private String extractBodyAsString(ArgumentCaptor<HttpUriRequest> capt, int theIdx) throws IOException {
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(theIdx)).getEntity().getContent(), "UTF-8");
return body;
}
@Test
public void testValidateResourceOnly() throws Exception {
IParser p = ourCtx.newXmlParser();
OperationOutcome conf = new OperationOutcome();
conf.getText().setDivAsString("OK!");
final String respString = p.encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IClient client = ourCtx.newRestfulClient(IClient.class, "http://example.com/fhir");
Patient patient = new Patient();
patient.addName().addFamily("FAM");
int idx = 0;
MethodOutcome outcome = client.validate(patient, null, null);
String resp = ourCtx.newXmlParser().encodeResourceToString(outcome.getOperationOutcome());
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
String request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter></Parameters>", request);
idx = 1;
outcome = client.validate(patient, ValidationModeEnum.CREATE, "http://foo");
resp = ourCtx.newXmlParser().encodeResourceToString(outcome.getOperationOutcome());
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><text><div xmlns=\"http://www.w3.org/1999/xhtml\">OK!</div></text></OperationOutcome>", resp);
assertEquals("http://example.com/fhir/$validate", capt.getAllValues().get(idx).getURI().toString());
request = extractBodyAsString(capt,idx);
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><family value=\"FAM\"/></name></Patient></resource></parameter><parameter><name value=\"mode\"/><valueString value=\"create\"/></parameter><parameter><name value=\"profile\"/><valueString value=\"http://foo\"/></parameter></Parameters>", request);
}
private interface IClient extends IRestfulClient {
@Validate
MethodOutcome validate(@ResourceParam IBaseResource theResource, @Validate.Mode ValidationModeEnum theMode, @Validate.Profile String theProfile);
}
@AfterClass
public static void afterClassClearContext() {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() {
ourCtx = FhirContext.forDstu3();
}
}

View File

@ -0,0 +1,19 @@
package ca.uhn.fhir.rest.method;
import static org.junit.Assert.*;
import org.hl7.fhir.dstu3.model.IdType;
import org.junit.Test;
import ca.uhn.fhir.model.primitive.IdDt;
public class MethodUtilTest {
@Test
public void testConvertIdToType() {
IdDt id = new IdDt("Patient/123");
IdType id2 = MethodUtil.convertIdToType(id, IdType.class);
assertEquals("Patient/123", id2.getValue());
}
}

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.rest.server;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
@ -8,6 +9,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
@ -25,6 +27,7 @@ import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@ -50,7 +53,7 @@ public class InterceptorDstu3Test {
private static final FhirContext ourCtx = FhirContext.forDstu3();
private static int ourPort;
private static Server ourServer;
private static RestfulServer servlet;
private static RestfulServer ourServlet;
private IServerInterceptor myInterceptor1;
private IServerInterceptor myInterceptor2;
@ -58,7 +61,7 @@ public class InterceptorDstu3Test {
public void before() {
myInterceptor1 = mock(IServerInterceptor.class);
myInterceptor2 = mock(IServerInterceptor.class);
servlet.setInterceptors(myInterceptor1, myInterceptor2);
ourServlet.setInterceptors(myInterceptor1, myInterceptor2);
}
@ -122,6 +125,13 @@ public class InterceptorDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
@After
public void after() {
for (IServerInterceptor next : new ArrayList<IServerInterceptor>(ourServlet.getInterceptors())) {
ourServlet.unregisterInterceptor(next);
}
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
@ -130,9 +140,9 @@ public class InterceptorDstu3Test {
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
servlet = new RestfulServer(ourCtx);
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
ourServlet = new RestfulServer(ourCtx);
ourServlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();

View File

@ -1,8 +1,6 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.List;
@ -26,13 +24,10 @@ import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Sort;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;

View File

@ -21,14 +21,11 @@ import org.hl7.fhir.dstu3.model.HumanName;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
@ -55,6 +52,55 @@ public class SearchWithServerAddressStrategyDstu3Test {
assertThat(responseContent, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/Patient/1\"/>"));
}
@Test
public void testApacheProxyAddressStrategy() throws Exception {
ourServlet.setServerAddressStrategy(ApacheProxyAddressStrategy.forHttp());
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
assertThat(responseContent, containsString("<fullUrl value=\"http://localhost:" + ourPort + "/Patient/1\"/>"));
ourServlet.setServerAddressStrategy(new ApacheProxyAddressStrategy(false));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
httpGet.addHeader("x-forwarded-host", "foo.com");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
assertThat(responseContent, containsString("<fullUrl value=\"http://foo.com/Patient/1\"/>"));
ourServlet.setServerAddressStrategy(ApacheProxyAddressStrategy.forHttps());
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
httpGet.addHeader("x-forwarded-host", "foo.com");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
assertThat(responseContent, containsString("<fullUrl value=\"https://foo.com/Patient/1\"/>"));
ourServlet.setServerAddressStrategy(new ApacheProxyAddressStrategy(false));
httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
httpGet.addHeader("x-forwarded-host", "foo.com");
httpGet.addHeader("x-forwarded-proto", "https");
status = ourClient.execute(httpGet);
responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(responseContent, containsString("<family value=\"FAMILY\""));
assertThat(responseContent, containsString("<fullUrl value=\"https://foo.com/Patient/1\"/>"));
}
@Test
public void testHardcodedAddressStrategy() throws Exception {
ourServlet.setServerAddressStrategy(new HardcodedServerAddressStrategy("http://example.com/fhir/base"));

View File

@ -0,0 +1,110 @@
package ca.uhn.fhir.rest.server;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.OperationOutcome.IssueType;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
import ca.uhn.fhir.util.PortUtil;
import ca.uhn.fhir.util.TestUtil;
public class UnclassifiedServerExceptionDstu3Test {
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UnclassifiedServerExceptionDstu3Test.class);
private static int ourPort;
private static Server ourServer;
public static UnclassifiedServerFailureException ourException;
@Test
public void testSearch() throws Exception {
OperationOutcome operationOutcome = new OperationOutcome();
operationOutcome.addIssue().setCode(IssueType.BUSINESSRULE);
ourException = new UnclassifiedServerFailureException(477, "SOME MESSAGE", operationOutcome);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
CloseableHttpResponse status = ourClient.execute(httpGet);
try {
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info(status.getStatusLine().toString());
ourLog.info(responseContent);
assertEquals(477, status.getStatusLine().getStatusCode());
//assertEquals("SOME MESSAGE", status.getStatusLine().getReasonPhrase());
assertThat(responseContent, stringContainsInOrder("business-rule"));
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}
}
@AfterClass
public static void afterClassClearContext() throws Exception {
ourServer.stop();
TestUtil.clearAllStaticFieldsForUnitTest();
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
RestfulServer servlet = new RestfulServer(ourCtx);
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
public static class DummyPatientResourceProvider implements IResourceProvider {
@Override
public Class<? extends IBaseResource> getResourceType() {
return Patient.class;
}
@Search()
public List<Patient> search() {
throw ourException;
}
}
}

View File

@ -30,8 +30,6 @@ import org.junit.BeforeClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;

View File

@ -1,23 +1,20 @@
package ca.uhn.fhir.validation;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.*;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import java.util.Locale;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.AfterClass;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.util.TestUtil;
public class SchemaValidationTestDstu3 {
public class SchemaValidationDstu3Test {
private static FhirContext ourCtx = FhirContext.forDstu3();
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SchemaValidationTestDstu3.class);
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SchemaValidationDstu3Test.class);
/**
* See #339

View File

@ -41,6 +41,16 @@
</ul>
]]>
</action>
<action type="remove">
Remove some clases that were deprecated over a year ago and have
suitable replacements:
<![CDATA[
<ul>
<li>QualifiedDateParam has been removed, but DateParam may be used instead</li>
<li>PathSpecification has been removedm but Include may be used instead</li>
</ul>
]]>
</action>
<action type="fix" issue="345">
ResponseValidatingInterceptor threw an InternalErrorException (HTTP 500) for operations
that do not return any content (e.g. delete). Thanks to Mohammad Jafari for reporting!
@ -359,6 +369,18 @@
Server now supports the _at parameter (including multiple repetitions)
for history operation
</action>
<!--
This one actually doesn't seem possible without using a deprecated servlet API
<action type="fix">
When throwing UnclassifiedServerException in server methods, the HTTP response
status line contained the response code specified in the exception, but not the
response message
</action>
-->
<action type="add">
AuthorizationInterceptor can now allow or deny requests to extended
operations (e.g. $everything)
</action>
<action type="fix">
DecimalType used BigDecimal constructor instead of valueOf method to
create a BigDecimal from a double, resulting in weird floating point