Continue work on refactor

This commit is contained in:
James 2017-06-28 10:26:01 -04:00
parent fbe2f98a02
commit ea1264cd8e
79 changed files with 661 additions and 3028 deletions

View File

@ -37,6 +37,7 @@ import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.view.ViewGenerator; import ca.uhn.fhir.model.view.ViewGenerator;
import ca.uhn.fhir.narrative.INarrativeGenerator; import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.parser.*; import ca.uhn.fhir.parser.*;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.*;
import ca.uhn.fhir.util.*; import ca.uhn.fhir.util.*;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
@ -460,6 +461,10 @@ public class FhirContext {
return !myDefaultTypeForProfile.isEmpty(); return !myDefaultTypeForProfile.isEmpty();
} }
public IVersionSpecificBundleFactory newBundleFactory() {
return myVersion.newBundleFactory(this);
}
/** /**
* Creates a new FluentPath engine which can be used to exvaluate * Creates a new FluentPath engine which can be used to exvaluate
* path expressions over FHIR resources. Note that this engine will use the * path expressions over FHIR resources. Note that this engine will use the
@ -818,7 +823,7 @@ public class FhirContext {
public void setValidationSupport(IContextValidationSupport<?, ?, ?, ?, ?, ?> theValidationSupport) { public void setValidationSupport(IContextValidationSupport<?, ?, ?, ?, ?, ?> theValidationSupport) {
myValidationSupport = theValidationSupport; myValidationSupport = theValidationSupport;
} }
@SuppressWarnings({ "cast" }) @SuppressWarnings({ "cast" })
private List<Class<? extends IElement>> toElementList(Collection<Class<? extends IBaseResource>> theResourceTypes) { private List<Class<? extends IElement>> toElementList(Collection<Class<? extends IBaseResource>> theResourceTypes) {
if (theResourceTypes == null) { if (theResourceTypes == null) {
@ -830,7 +835,7 @@ public class FhirContext {
} }
return resTypes; return resTypes;
} }
private void validateInitialized() { private void validateInitialized() {
// See #610 // See #610
if (!myInitialized) { if (!myInitialized) {

View File

@ -10,7 +10,7 @@ package ca.uhn.fhir.model.api;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -33,6 +33,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.support.IContextValidationSupport; import ca.uhn.fhir.context.support.IContextValidationSupport;
import ca.uhn.fhir.fluentpath.IFluentPath; import ca.uhn.fhir.fluentpath.IFluentPath;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
/** /**
* Each structure version JAR will have an implementation of this interface. * Each structure version JAR will have an implementation of this interface.
@ -44,7 +45,7 @@ import ca.uhn.fhir.fluentpath.IFluentPath;
public interface IFhirVersion { public interface IFhirVersion {
IFluentPath createFluentPathExecutor(FhirContext theFhirContext); IFluentPath createFluentPathExecutor(FhirContext theFhirContext);
IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport(); IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport();
IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase); IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase);
@ -61,6 +62,8 @@ public interface IFhirVersion {
FhirVersionEnum getVersion(); FhirVersionEnum getVersion();
IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext);
IBase newCodingDt(); IBase newCodingDt();
IIdType newIdType(); IIdType newIdType();

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.rest.api.server; package ca.uhn.fhir.rest.api;
/* /*
* #%L * #%L
@ -19,7 +19,9 @@ package ca.uhn.fhir.rest.api.server;
* limitations under the License. * limitations under the License.
* #L% * #L%
*/ */
import java.util.*; import java.util.Date;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -28,7 +30,6 @@ import ca.uhn.fhir.context.api.BundleInclusionRule;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.api.EncodingEnum;
/** /**
* This interface should be considered experimental and will likely change in future releases of HAPI. Use with caution! * This interface should be considered experimental and will likely change in future releases of HAPI. Use with caution!
@ -39,8 +40,8 @@ public interface IVersionSpecificBundleFactory {
void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, IPrimitiveType<Date> theLastUpdated); void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, IPrimitiveType<Date> theLastUpdated);
void initializeBundleFromBundleProvider(IRestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, // void initializeBundleFromBundleProvider(IRestfulServer<?> theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes); // int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
Bundle getDstu1Bundle(); Bundle getDstu1Bundle();

View File

@ -21,20 +21,29 @@ package ca.uhn.fhir.rest.client.apache;
*/ */
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.*; import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair; import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*; import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/** /**

View File

@ -28,7 +28,6 @@ import java.io.Reader;
import java.io.StringReader; import java.io.StringReader;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -41,7 +40,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import ca.uhn.fhir.rest.client.api.IHttpResponse; import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/** /**

View File

@ -31,7 +31,10 @@ import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider; import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig; import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.*; import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.client.ProxyAuthenticationStrategy;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;

View File

@ -26,10 +26,13 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseBinary; import org.hl7.fhir.instance.model.api.IBaseBinary;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.client.api.HttpClientUtil;
import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.*;
public abstract class BaseHttpClient implements IHttpClient { public abstract class BaseHttpClient implements IHttpClient {

View File

@ -29,8 +29,9 @@ import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ByteArrayEntity; import org.apache.http.entity.ByteArrayEntity;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/** /**
* Client interceptor which GZip compresses outgoing (POST/PUT) contents being uploaded * Client interceptor which GZip compresses outgoing (POST/PUT) contents being uploaded

View File

@ -22,25 +22,51 @@ package ca.uhn.fhir.rest.client.impl;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.*; import java.io.IOException;
import java.util.*; import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.*; import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.*; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.exceptions.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.method.HttpGetClientInvocation; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.method.IClientResponseHandler; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.method.IClientResponseHandlerHandlesBinary; import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.method.MethodUtil; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.client.method.HttpGetClientInvocation;
import ca.uhn.fhir.rest.client.method.IClientResponseHandler;
import ca.uhn.fhir.rest.client.method.IClientResponseHandlerHandlesBinary;
import ca.uhn.fhir.rest.client.method.MethodUtil;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.util.OperationOutcomeUtil; import ca.uhn.fhir.util.OperationOutcomeUtil;
import ca.uhn.fhir.util.XmlUtil; import ca.uhn.fhir.util.XmlUtil;

View File

@ -28,9 +28,12 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.Header;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
public abstract class BaseHttpClientInvocation { public abstract class BaseHttpClientInvocation {

View File

@ -27,7 +27,7 @@ import java.util.Map;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IHttpClient; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.impl.ClientInvocationHandlerFactory.ILambda; import ca.uhn.fhir.rest.client.impl.ClientInvocationHandlerFactory.ILambda;
import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.client.method.BaseMethodBinding;
public class ClientInvocationHandler extends BaseClient implements InvocationHandler { public class ClientInvocationHandler extends BaseClient implements InvocationHandler {

View File

@ -28,10 +28,12 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.method.BaseMethodBinding; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.method.BaseMethodBinding;
public class ClientInvocationHandlerFactory { public class ClientInvocationHandlerFactory {

View File

@ -71,15 +71,35 @@ import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PatchTypeEnum; import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.api.PreferReturnEnum; import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.api.SortOrderEnum; import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IGenericClient;
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.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.client.method.DeleteMethodBinding;
import ca.uhn.fhir.rest.client.method.HistoryMethodBinding;
import ca.uhn.fhir.rest.client.method.HttpDeleteClientInvocation;
import ca.uhn.fhir.rest.client.method.HttpGetClientInvocation;
import ca.uhn.fhir.rest.client.method.HttpSimpleGetClientInvocation;
import ca.uhn.fhir.rest.client.method.IClientResponseHandler;
import ca.uhn.fhir.rest.client.method.MethodUtil;
import ca.uhn.fhir.rest.client.method.OperationMethodBinding;
import ca.uhn.fhir.rest.client.method.ReadMethodBinding;
import ca.uhn.fhir.rest.client.method.SearchMethodBinding;
import ca.uhn.fhir.rest.client.method.SortParameter;
import ca.uhn.fhir.rest.client.method.TransactionMethodBinding;
import ca.uhn.fhir.rest.client.method.ValidateMethodBindingDstu1;
import ca.uhn.fhir.rest.client.method.ValidateMethodBindingDstu2Plus;
import ca.uhn.fhir.rest.gclient.IClientExecutable; import ca.uhn.fhir.rest.gclient.IClientExecutable;
import ca.uhn.fhir.rest.gclient.ICreate; import ca.uhn.fhir.rest.gclient.ICreate;
import ca.uhn.fhir.rest.gclient.ICreateTyped; import ca.uhn.fhir.rest.gclient.ICreateTyped;
@ -133,27 +153,9 @@ import ca.uhn.fhir.rest.gclient.IUpdateWithQuery;
import ca.uhn.fhir.rest.gclient.IUpdateWithQueryTyped; import ca.uhn.fhir.rest.gclient.IUpdateWithQueryTyped;
import ca.uhn.fhir.rest.gclient.IValidate; import ca.uhn.fhir.rest.gclient.IValidate;
import ca.uhn.fhir.rest.gclient.IValidateUntyped; import ca.uhn.fhir.rest.gclient.IValidateUntyped;
import ca.uhn.fhir.rest.method.DeleteMethodBinding;
import ca.uhn.fhir.rest.method.HistoryMethodBinding;
import ca.uhn.fhir.rest.method.HttpDeleteClientInvocation;
import ca.uhn.fhir.rest.method.HttpGetClientInvocation;
import ca.uhn.fhir.rest.method.HttpSimpleGetClientInvocation;
import ca.uhn.fhir.rest.method.IClientResponseHandler;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.method.OperationMethodBinding;
import ca.uhn.fhir.rest.method.ReadMethodBinding;
import ca.uhn.fhir.rest.method.SearchMethodBinding;
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.ValidateMethodBindingDstu2Plus;
import ca.uhn.fhir.rest.param.DateParam; import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.NotModifiedException; import ca.uhn.fhir.rest.server.exceptions.NotModifiedException;
@ -216,11 +218,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); OutcomeResponseHandler binding = new OutcomeResponseHandler();
final String resourceName = def.getName();
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse); MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
return resp; return resp;
@ -239,8 +237,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
final String resourceName = myContext.getResourceDefinition(theType).getName(); OutcomeResponseHandler binding = new OutcomeResponseHandler();
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse); MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
return resp; return resp;
} }
@ -555,10 +552,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); OutcomeResponseHandler binding = new OutcomeResponseHandler();
final String resourceName = def.getName();
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse); MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
return resp; return resp;
} }
@ -586,10 +580,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint()); myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
} }
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource); OutcomeResponseHandler binding = new OutcomeResponseHandler();
final String resourceName = def.getName();
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse); MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
return resp; return resp;
} }
@ -742,7 +733,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
} }
protected IBaseResource parseResourceBody(String theResourceBody) { protected IBaseResource parseResourceBody(String theResourceBody) {
EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(theResourceBody); EncodingEnum encoding = EncodingEnum.detectEncodingNoDefault(theResourceBody);
if (encoding == null) { if (encoding == null) {
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType")); throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
} }
@ -853,9 +844,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
addPreferHeader(myPrefer, invocation); addPreferHeader(myPrefer, invocation);
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
final String resourceName = def.getName(); OutcomeResponseHandler binding = new OutcomeResponseHandler(myPrefer);
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName, myPrefer);
Map<String, List<String>> params = new HashMap<String, List<String>>(); Map<String, List<String>> params = new HashMap<String, List<String>>();
return invoke(params, binding, invocation); return invoke(params, binding, invocation);
@ -1765,14 +1754,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
private final class OutcomeResponseHandler implements IClientResponseHandler<MethodOutcome> { private final class OutcomeResponseHandler implements IClientResponseHandler<MethodOutcome> {
private PreferReturnEnum myPrefer; private PreferReturnEnum myPrefer;
// private final String myResourceName;
private OutcomeResponseHandler(String theResourceName) { private OutcomeResponseHandler() {
// myResourceName = theResourceName; super();
} }
private OutcomeResponseHandler(String theResourceName, PreferReturnEnum thePrefer) { private OutcomeResponseHandler(PreferReturnEnum thePrefer) {
this(theResourceName); this();
myPrefer = thePrefer; myPrefer = thePrefer;
} }
@ -2357,7 +2345,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
public TransactionExecutable(String theBundle) { public TransactionExecutable(String theBundle) {
myRawBundle = theBundle; myRawBundle = theBundle;
myRawBundleEncoding = MethodUtil.detectEncodingNoDefault(myRawBundle); myRawBundleEncoding = EncodingEnum.detectEncodingNoDefault(myRawBundle);
if (myRawBundleEncoding == null) { if (myRawBundleEncoding == null) {
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType")); throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
} }
@ -2381,7 +2369,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
* If the user has explicitly requested a given encoding, we may need to re-encode the raw string * If the user has explicitly requested a given encoding, we may need to re-encode the raw string
*/ */
if (getParamEncoding() != null) { if (getParamEncoding() != null) {
if (MethodUtil.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) { if (EncodingEnum.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) {
IBaseResource parsed = parseResourceBody(myRawBundle); IBaseResource parsed = parseResourceBody(myRawBundle);
myRawBundle = getParamEncoding().newParser(getFhirContext()).encodeResourceToString(parsed); myRawBundle = getParamEncoding().newParser(getFhirContext()).encodeResourceToString(parsed);
} }
@ -2480,7 +2468,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
addPreferHeader(myPrefer, invocation); addPreferHeader(myPrefer, invocation);
OutcomeResponseHandler binding = new OutcomeResponseHandler(null, myPrefer); OutcomeResponseHandler binding = new OutcomeResponseHandler(myPrefer);
Map<String, List<String>> params = new HashMap<String, List<String>>(); Map<String, List<String>> params = new HashMap<String, List<String>>();
return invoke(params, binding, invocation); return invoke(params, binding, invocation);
@ -2529,7 +2517,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
myPatchBody = thePatchBody; myPatchBody = thePatchBody;
EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(thePatchBody); EncodingEnum encoding = EncodingEnum.detectEncodingNoDefault(thePatchBody);
if (encoding == EncodingEnum.XML) { if (encoding == EncodingEnum.XML) {
myPatchType = PatchTypeEnum.XML_PATCH; myPatchType = PatchTypeEnum.XML_PATCH;
} else if (encoding == EncodingEnum.JSON) { } else if (encoding == EncodingEnum.JSON) {
@ -2607,9 +2595,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
addPreferHeader(myPrefer, invocation); addPreferHeader(myPrefer, invocation);
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource); RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
final String resourceName = def.getName(); OutcomeResponseHandler binding = new OutcomeResponseHandler(myPrefer);
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName, myPrefer);
Map<String, List<String>> params = new HashMap<String, List<String>>(); Map<String, List<String>> params = new HashMap<String, List<String>>();
return invoke(params, binding, invocation); return invoke(params, binding, invocation);
@ -2693,7 +2679,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
Validate.notBlank(theResourceRaw, "theResourceRaw must not be null or blank"); Validate.notBlank(theResourceRaw, "theResourceRaw must not be null or blank");
myResource = parseResourceBody(theResourceRaw); myResource = parseResourceBody(theResourceRaw);
EncodingEnum enc = MethodUtil.detectEncodingNoDefault(theResourceRaw); EncodingEnum enc = EncodingEnum.detectEncodingNoDefault(theResourceRaw);
if (enc == null) { if (enc == null) {
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType")); throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
} }

View File

@ -12,7 +12,9 @@ import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IBasicClient;
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IGenericClient;
/* /*
* #%L * #%L

View File

@ -23,42 +23,31 @@ package ca.uhn.fhir.rest.client.impl;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.*; import ca.uhn.fhir.rest.client.api.IRestfulClient;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IRestfulClientFactory;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException; import ca.uhn.fhir.rest.client.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.FhirTerser;
/** /**
* Base class for a REST client factory implementation * Base class for a REST client factory implementation
*/ */
public abstract class RestfulClientFactory implements IRestfulClientFactory { public abstract class RestfulClientFactory implements IRestfulClientFactory {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulClientFactory.class);
private int myConnectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT; private int myConnectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
private int myConnectTimeout = DEFAULT_CONNECT_TIMEOUT; private int myConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
private FhirContext myContext; private FhirContext myContext;
private Map<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory> myInvocationHandlers = new HashMap<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory>(); private Map<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory> myInvocationHandlers = new HashMap<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory>();
private ServerValidationModeEnum myServerValidationMode = DEFAULT_SERVER_VALIDATION_MODE; private ServerValidationModeEnum myServerValidationMode = DEFAULT_SERVER_VALIDATION_MODE;
private int mySocketTimeout = DEFAULT_SOCKET_TIMEOUT; private int mySocketTimeout = DEFAULT_SOCKET_TIMEOUT;
private Set<String> myValidatedServerBaseUrls = Collections.synchronizedSet(new HashSet<String>());
private String myProxyUsername; private String myProxyUsername;
private String myProxyPassword; private String myProxyPassword;
private int myPoolMaxTotal = DEFAULT_POOL_MAX; private int myPoolMaxTotal = DEFAULT_POOL_MAX;
@ -192,21 +181,6 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
return new GenericClient(myContext, httpClient, theServerBase, this); return new GenericClient(myContext, httpClient, theServerBase, this);
} }
@Override
public void validateServerBaseIfConfiguredToDoSo(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
String serverBase = normalizeBaseUrlForMap(theServerBase);
switch (getServerValidationMode()) {
case NEVER:
break;
case ONCE:
if (!myValidatedServerBaseUrls.contains(serverBase)) {
validateServerBase(serverBase, theHttpClient, theClient);
}
break;
}
}
private String normalizeBaseUrlForMap(String theServerBase) { private String normalizeBaseUrlForMap(String theServerBase) {
String serverBase = theServerBase; String serverBase = theServerBase;
@ -270,84 +244,6 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
resetHttpClient(); resetHttpClient();
} }
@SuppressWarnings("unchecked")
@Override
public void validateServerBase(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this);
client.setEncoding(theClient.getEncoding());
for (IClientInterceptor interceptor : theClient.getInterceptors()) {
client.registerInterceptor(interceptor);
}
client.setDontValidateConformance(true);
IBaseResource conformance;
try {
String capabilityStatementResourceName = "CapabilityStatement";
if (myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
capabilityStatementResourceName = "Conformance";
}
@SuppressWarnings("rawtypes")
Class implementingClass;
try {
implementingClass = myContext.getResourceDefinition(capabilityStatementResourceName).getImplementingClass();
} catch (DataFormatException e) {
if (!myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
capabilityStatementResourceName = "Conformance";
implementingClass = myContext.getResourceDefinition(capabilityStatementResourceName).getImplementingClass();
} else {
throw e;
}
}
try {
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
} catch (FhirClientConnectionException e) {
if (!myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3) && e.getCause() instanceof DataFormatException) {
capabilityStatementResourceName = "Conformance";
implementingClass = myContext.getResourceDefinition(capabilityStatementResourceName).getImplementingClass();
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
} else {
throw e;
}
}
} catch (FhirClientConnectionException e) {
String msg = myContext.getLocalizer().getMessage(RestfulClientFactory.class, "failedToRetrieveConformance", theServerBase + Constants.URL_TOKEN_METADATA);
throw new FhirClientConnectionException(msg, e);
}
FhirTerser t = myContext.newTerser();
String serverFhirVersionString = null;
Object value = t.getSingleValueOrNull(conformance, "fhirVersion");
if (value instanceof IPrimitiveType) {
serverFhirVersionString = IPrimitiveType.class.cast(value).getValueAsString();
}
FhirVersionEnum serverFhirVersionEnum = null;
if (StringUtils.isBlank(serverFhirVersionString)) {
// we'll be lenient and accept this
} else {
//FIXME null access on serverFhirVersionString
if (serverFhirVersionString.startsWith("0.80") || serverFhirVersionString.startsWith("0.0.8")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU1;
} else if (serverFhirVersionString.startsWith("0.4")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU2;
} else if (serverFhirVersionString.startsWith("0.5")) {
serverFhirVersionEnum = FhirVersionEnum.DSTU2;
} else {
// we'll be lenient and accept this
ourLog.debug("Server conformance statement indicates unknown FHIR version: {}", serverFhirVersionString);
}
}
if (serverFhirVersionEnum != null) {
FhirVersionEnum contextFhirVersion = myContext.getVersion().getVersion();
if (!contextFhirVersion.isEquivalentTo(serverFhirVersionEnum)) {
throw new FhirClientInappropriateForServerException(myContext.getLocalizer().getMessage(RestfulClientFactory.class, "wrongVersionInConformance", theServerBase + Constants.URL_TOKEN_METADATA, serverFhirVersionString, serverFhirVersionEnum, contextFhirVersion));
}
}
myValidatedServerBaseUrls.add(normalizeBaseUrlForMap(theServerBase));
}
@Deprecated //override deprecated method @Deprecated //override deprecated method
@Override @Override

View File

@ -26,8 +26,9 @@ import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/** /**

View File

@ -22,8 +22,9 @@ package ca.uhn.fhir.rest.client.interceptor;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.CoverageIgnore;
/** /**

View File

@ -1,11 +1,14 @@
package ca.uhn.fhir.rest.client.interceptor; package ca.uhn.fhir.rest.client.interceptor;
import ca.uhn.fhir.rest.client.api.*; import java.io.IOException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import java.io.IOException; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/** /**
* Client interceptor which simply captures request and response objects and stores them so that they can be inspected after a client * Client interceptor which simply captures request and response objects and stores them so that they can be inspected after a client

View File

@ -1,7 +1,8 @@
package ca.uhn.fhir.rest.client.interceptor; package ca.uhn.fhir.rest.client.interceptor;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/** /**
* HTTP interceptor to be used for adding Cookie to requests. * HTTP interceptor to be used for adding Cookie to requests.

View File

@ -30,7 +30,9 @@ import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.slf4j.Logger; import org.slf4j.Logger;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class LoggingInterceptor implements IClientInterceptor { public class LoggingInterceptor implements IClientInterceptor {

View File

@ -23,14 +23,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
*/ */
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.commons.codec.binary.Base64; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import org.apache.commons.lang3.StringUtils; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
import ca.uhn.fhir.rest.client.api.*;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
/** /**
* This interceptor adds an arbitrary header to requests made by this client. Both the * This interceptor adds an arbitrary header to requests made by this client. Both the

View File

@ -22,7 +22,9 @@ package ca.uhn.fhir.rest.client.interceptor;
import java.io.IOException; import java.io.IOException;
import ca.uhn.fhir.rest.client.api.*; import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.api.IHttpResponse;
/** /**
* HTTP interceptor to be used for adding HTTP headers containing user identifying info for auditing purposes to the request * HTTP interceptor to be used for adding HTTP headers containing user identifying info for auditing purposes to the request

View File

@ -21,7 +21,7 @@ package ca.uhn.fhir.rest.client.method;
*/ */
import ca.uhn.fhir.rest.annotation.At; import ca.uhn.fhir.rest.annotation.At;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.api.Constants;
class AtParameter extends SinceOrAtParameter { class AtParameter extends SinceOrAtParameter {

View File

@ -1,26 +1,5 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -33,15 +12,15 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.TagListParam; import ca.uhn.fhir.rest.annotation.TagListParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> { abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> {
@ -54,11 +33,7 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, Class<? extends IBaseResource> theTypeFromMethodAnnotation) { public BaseAddOrDeleteTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, Class<? extends IBaseResource> theTypeFromMethodAnnotation) {
super(theMethod, theContext, theProvider); super(theMethod, theContext, theProvider);
if (theProvider instanceof IResourceProvider) { myType = theTypeFromMethodAnnotation;
myType = ((IResourceProvider) theProvider).getResourceType();
} else {
myType = theTypeFromMethodAnnotation;
}
if (Modifier.isInterface(myType.getModifiers())) { if (Modifier.isInterface(myType.getModifiers())) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' does not specify a resource type, but has an @" + IdParam.class.getSimpleName() + " parameter. Please specity a resource type in the method annotation on this method"); throw new ConfigurationException("Method '" + theMethod.getName() + "' does not specify a resource type, but has an @" + IdParam.class.getSimpleName() + " parameter. Please specity a resource type in the method annotation on this method");
@ -145,65 +120,6 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
return retVal; return retVal;
} }
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
Object[] params = createParametersForServerRequest(theRequest);
params[myIdParamIndex] = theRequest.getId();
if (myVersionIdParamIndex != null) {
params[myVersionIdParamIndex] = theRequest.getId();
}
IParser parser = createAppropriateParserForParsingServerRequest(theRequest);
Reader reader = theRequest.getReader();
try {
TagList tagList = parser.parseTagList(reader);
params[myTagListParamIndex] = tagList;
} finally {
reader.close();
}
invokeServerMethod(theServer, theRequest, params);
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = theServer.getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest);
if (!continueProcessing) {
return null;
}
}
return theRequest.getResponse().returnResponse(null, Constants.STATUS_HTTP_200_OK, false, null, null);
}
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (theRequest.getRequestType() != RequestTypeEnum.POST) {
return false;
}
if (!Constants.PARAM_TAGS.equals(theRequest.getOperation())) {
return false;
}
if (!myResourceName.equals(theRequest.getResourceName())) {
return false;
}
if (theRequest.getId() == null) {
return false;
}
if (isDelete()) {
if (Constants.PARAM_DELETE.equals(theRequest.getSecondaryOperation()) == false) {
return false;
}
} else {
if (theRequest.getSecondaryOperation() != null) {
return false;
}
}
return true;
}
} }

View File

@ -38,12 +38,12 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.client.api.IHttpClient; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.EncodingEnum;
/** /**
* @author James Agnew * @author James Agnew
@ -194,7 +194,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
EncodingEnum encoding = theEncoding; EncodingEnum encoding = theEncoding;
if (myContents != null) { if (myContents != null) {
encoding = MethodUtil.detectEncoding(myContents); encoding = EncodingEnum.detectEncoding(myContents);
} }

View File

@ -27,6 +27,7 @@ import java.util.List;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -1,34 +1,9 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@ -42,22 +17,31 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.annotation.AddTags;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.DeleteTags;
import ca.uhn.fhir.rest.annotation.GetPage;
import ca.uhn.fhir.rest.annotation.GetTags;
import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.Patch;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.BundleProviders; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@ -67,9 +51,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException; import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.ReflectionUtil;
public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T> { public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T> {
@ -112,45 +93,12 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
} }
IParser parser = encoding.newParser(getContext()); IParser parser = encoding.newParser(getContext());
parser.setPreferTypes(thePreferTypes); parser.setPreferTypes(thePreferTypes);
return parser; return parser;
} }
protected IParser createAppropriateParserForParsingServerRequest(RequestDetails theRequest) {
String contentTypeHeader = theRequest.getHeader(Constants.HEADER_CONTENT_TYPE);
EncodingEnum encoding;
if (isBlank(contentTypeHeader)) {
encoding = EncodingEnum.XML;
} else {
int semicolon = contentTypeHeader.indexOf(';');
if (semicolon != -1) {
contentTypeHeader = contentTypeHeader.substring(0, semicolon);
}
encoding = EncodingEnum.forContentType(contentTypeHeader);
}
if (encoding == null) {
throw new InvalidRequestException("Request contins non-FHIR conent-type header value: " + contentTypeHeader);
}
IParser parser = encoding.newParser(getContext());
return parser;
}
protected Object[] createParametersForServerRequest(RequestDetails theRequest) {
Object[] params = new Object[getParameters().size()];
for (int i = 0; i < getParameters().size(); i++) {
IParameter param = getParameters().get(i);
if (param == null) {
continue;
}
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, this);
}
return params;
}
public List<Class<?>> getAllowableParamAnnotations() { public List<Class<?>> getAllowableParamAnnotations() {
return null; return null;
} }
@ -181,43 +129,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
return myProvider; return myProvider;
} }
@SuppressWarnings({ "unchecked", "rawtypes" })
public Set<Include> getRequestIncludesFromParams(Object[] params) {
if (params == null || params.length == 0) {
return null;
}
int index = 0;
boolean match = false;
for (IParameter parameter : myParameters) {
if (parameter instanceof IncludeParameter) {
match = true;
break;
}
index++;
}
if (!match) {
return null;
}
if (index >= params.length) {
ourLog.warn("index out of parameter range (should never happen");
return null;
}
if (params[index] instanceof Set) {
return (Set<Include>) params[index];
}
if (params[index] instanceof Iterable) {
Set includes = new HashSet<Include>();
for (Object o : (Iterable) params[index]) {
if (o instanceof Include) {
includes.add(o);
}
}
return includes;
}
ourLog.warn("include params wasn't Set or Iterable, it was {}", params[index].getClass());
return null;
}
/** /**
* Returns the name of the resource this method handles, or <code>null</code> if this method is not resource specific * Returns the name of the resource this method handles, or <code>null</code> if this method is not resource specific
*/ */
@ -225,47 +136,8 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
public abstract RestOperationTypeEnum getRestOperationType(); public abstract RestOperationTypeEnum getRestOperationType();
/**
* Determine which operation is being fired for a specific request
*
* @param theRequestDetails
* The request
*/
public RestOperationTypeEnum getRestOperationType(RequestDetails theRequestDetails) {
return getRestOperationType();
}
public abstract boolean incomingServerRequestMatchesMethod(RequestDetails theRequest);
public abstract BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException; public abstract BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException;
public abstract Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException;
protected final Object invokeServerMethod(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) {
// Handle server action interceptors
RestOperationTypeEnum operationType = getRestOperationType(theRequest);
if (operationType != null) {
for (IServerInterceptor next : theServer.getInterceptors()) {
ActionRequestDetails details = new ActionRequestDetails(theRequest);
populateActionRequestDetailsForInterceptor(theRequest, details, theMethodParams);
next.incomingRequestPreHandled(operationType, details);
}
}
// Actually invoke the method
try {
Method method = getMethod();
return method.invoke(getProvider(), theMethodParams);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof BaseServerResponseException) {
throw (BaseServerResponseException) e.getCause();
}
throw new InternalErrorException("Failed to call access method", e);
} catch (Exception e) {
throw new InternalErrorException("Failed to call access method", e);
}
}
/** /**
* Does this method have a parameter annotated with {@link ConditionalParamBinder}. Note that many operations don't actually support this paramter, so this will only return true occasionally. * Does this method have a parameter annotated with {@link ConditionalParamBinder}. Note that many operations don't actually support this paramter, so this will only return true occasionally.
*/ */
@ -280,21 +152,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
return mySupportsConditionalMultiple; return mySupportsConditionalMultiple;
} }
/**
* Subclasses may override this method (but should also call super.{@link #populateActionRequestDetailsForInterceptor(RequestDetails, ActionRequestDetails, Object[])} to provide method specifics to the
* interceptors.
*
* @param theRequestDetails
* The server request details
* @param theDetails
* The details object to populate
* @param theMethodParams
* The method params as generated by the specific method binding
*/
protected void populateActionRequestDetailsForInterceptor(RequestDetails theRequestDetails, ActionRequestDetails theDetails, Object[] theMethodParams) {
// nothing by default
}
protected BaseServerResponseException processNon2xxResponseAndReturnExceptionToThrow(int theStatusCode, String theResponseMimeType, Reader theResponseReader) { protected BaseServerResponseException processNon2xxResponseAndReturnExceptionToThrow(int theStatusCode, String theResponseMimeType, Reader theResponseReader) {
BaseServerResponseException ex; BaseServerResponseException ex;
switch (theStatusCode) { switch (theStatusCode) {
@ -333,30 +190,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
myParameters = theParameters; myParameters = theParameters;
} }
protected IBundleProvider toResourceList(Object response) throws InternalErrorException {
if (response == null) {
return BundleProviders.newEmptyList();
} else if (response instanceof IBundleProvider) {
return (IBundleProvider) response;
} else if (response instanceof IBaseResource) {
return BundleProviders.newList((IBaseResource) response);
} else if (response instanceof Collection) {
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
for (Object next : ((Collection<?>) response)) {
retVal.add((IBaseResource) next);
}
return BundleProviders.newList(retVal);
} else if (response instanceof MethodOutcome) {
IBaseResource retVal = ((MethodOutcome) response).getOperationOutcome();
if (retVal == null) {
retVal = getContext().getResourceDefinition("OperationOutcome").newInstance();
}
return BundleProviders.newList(retVal);
} else {
throw new InternalErrorException("Unexpected return type: " + response.getClass().getCanonicalName());
}
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static BaseMethodBinding<?> bindMethod(Method theMethod, FhirContext theContext, Object theProvider) { public static BaseMethodBinding<?> bindMethod(Method theMethod, FhirContext theContext, Object theProvider) {
Read read = theMethod.getAnnotation(Read.class); Read read = theMethod.getAnnotation(Read.class);
@ -376,24 +209,18 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
Patch patch = theMethod.getAnnotation(Patch.class); Patch patch = theMethod.getAnnotation(Patch.class);
// ** if you add another annotation above, also add it to the next line: // ** if you add another annotation above, also add it to the next line:
if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate, getTags, addTags, deleteTags, transaction, operation, getPage, patch)) { if (!verifyMethodHasZeroOrOneOperationAnnotation(theMethod, read, search, conformance, create, update, delete, history, validate, getTags, addTags, deleteTags, transaction, operation, getPage,
patch)) {
return null; return null;
} }
if (getPage != null) { if (getPage != null) {
return new PageMethodBinding(theContext, theMethod); return new PageMethodBinding(theContext, theMethod);
} }
Class<? extends IBaseResource> returnType; Class<? extends IBaseResource> returnType;
Class<? extends IBaseResource> returnTypeFromRp = null; Class<? extends IBaseResource> returnTypeFromRp = null;
if (theProvider instanceof IResourceProvider) {
returnTypeFromRp = ((IResourceProvider) theProvider).getResourceType();
if (!verifyIsValidResourceReturnType(returnTypeFromRp)) {
throw new ConfigurationException("getResourceType() from " + IResourceProvider.class.getSimpleName() + " type " + theMethod.getDeclaringClass().getCanonicalName() + " returned "
+ toLogString(returnTypeFromRp) + " - Must return a resource type");
}
}
Class<?> returnTypeFromMethod = theMethod.getReturnType(); Class<?> returnTypeFromMethod = theMethod.getReturnType();
if (getTags != null) { if (getTags != null) {
@ -403,8 +230,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
} }
} else if (MethodOutcome.class.isAssignableFrom(returnTypeFromMethod)) { } else if (MethodOutcome.class.isAssignableFrom(returnTypeFromMethod)) {
// returns a method outcome // returns a method outcome
} else if (IBundleProvider.class.equals(returnTypeFromMethod)) {
// returns a bundle provider
} else if (Bundle.class.equals(returnTypeFromMethod)) { } else if (Bundle.class.equals(returnTypeFromMethod)) {
// returns a bundle // returns a bundle
} else if (void.class.equals(returnTypeFromMethod)) { } else if (void.class.equals(returnTypeFromMethod)) {
@ -414,14 +239,14 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
if (returnTypeFromMethod == null) { if (returnTypeFromMethod == null) {
ourLog.trace("Method {} returns a non-typed list, can't verify return type", theMethod); ourLog.trace("Method {} returns a non-typed list, can't verify return type", theMethod);
} else if (!verifyIsValidResourceReturnType(returnTypeFromMethod) && !isResourceInterface(returnTypeFromMethod)) { } else if (!verifyIsValidResourceReturnType(returnTypeFromMethod) && !isResourceInterface(returnTypeFromMethod)) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' from " + IResourceProvider.class.getSimpleName() + " type " + theMethod.getDeclaringClass().getCanonicalName() throw new ConfigurationException("Method '" + theMethod.getName() + "' from client type " + theMethod.getDeclaringClass().getCanonicalName()
+ " returns a collection with generic type " + toLogString(returnTypeFromMethod) + " returns a collection with generic type " + toLogString(returnTypeFromMethod)
+ " - Must return a resource type or a collection (List, Set) with a resource type parameter (e.g. List<Patient> or List<IBaseResource> )"); + " - Must return a resource type or a collection (List, Set) with a resource type parameter (e.g. List<Patient> or List<IBaseResource> )");
} }
} else { } else {
if (!isResourceInterface(returnTypeFromMethod) && !verifyIsValidResourceReturnType(returnTypeFromMethod)) { if (!isResourceInterface(returnTypeFromMethod) && !verifyIsValidResourceReturnType(returnTypeFromMethod)) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' from " + IResourceProvider.class.getSimpleName() + " type " + theMethod.getDeclaringClass().getCanonicalName() throw new ConfigurationException("Method '" + theMethod.getName() + "' from client type " + theMethod.getDeclaringClass().getCanonicalName()
+ " returns " + toLogString(returnTypeFromMethod) + " - Must return a resource type (eg Patient, " + Bundle.class.getSimpleName() + ", " + IBundleProvider.class.getSimpleName() + " returns " + toLogString(returnTypeFromMethod) + " - Must return a resource type (eg Patient, " + Bundle.class.getSimpleName()
+ ", etc., see the documentation for more details)"); + ", etc., see the documentation for more details)");
} }
} }
@ -451,48 +276,26 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
returnTypeFromAnnotation = deleteTags.type(); returnTypeFromAnnotation = deleteTags.type();
} }
if (returnTypeFromRp != null) { if (!isResourceInterface(returnTypeFromAnnotation)) {
if (returnTypeFromAnnotation != null && !isResourceInterface(returnTypeFromAnnotation)) { if (!verifyIsValidResourceReturnType(returnTypeFromAnnotation)) {
if (!returnTypeFromRp.isAssignableFrom(returnTypeFromAnnotation)) { throw new ConfigurationException("Method '" + theMethod.getName() + "' from client type " + theMethod.getDeclaringClass().getCanonicalName()
//FIXME potential null access on retunrTypeFromMethod + " returns " + toLogString(returnTypeFromAnnotation) + " according to annotation - Must return a resource type");
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type " + theMethod.getDeclaringClass().getCanonicalName() + " returns type "
+ returnTypeFromMethod.getCanonicalName() + " - Must return " + returnTypeFromRp.getCanonicalName() + " (or a subclass of it) per IResourceProvider contract");
}
if (!returnTypeFromRp.isAssignableFrom(returnTypeFromAnnotation)) {
throw new ConfigurationException(
"Method '" + theMethod.getName() + "' in type " + theMethod.getDeclaringClass().getCanonicalName() + " claims to return type " + returnTypeFromAnnotation.getCanonicalName()
+ " per method annotation - Must return " + returnTypeFromRp.getCanonicalName() + " (or a subclass of it) per IResourceProvider contract");
}
returnType = returnTypeFromAnnotation;
} else {
returnType = returnTypeFromRp;
} }
returnType = returnTypeFromAnnotation;
} else { } else {
if (!isResourceInterface(returnTypeFromAnnotation)) { // if (IRestfulClient.class.isAssignableFrom(theMethod.getDeclaringClass())) {
if (!verifyIsValidResourceReturnType(returnTypeFromAnnotation)) { // Clients don't define their methods in resource specific types, so they can
throw new ConfigurationException("Method '" + theMethod.getName() + "' from " + IResourceProvider.class.getSimpleName() + " type " + theMethod.getDeclaringClass().getCanonicalName() // infer their resource type from the method return type.
+ " returns " + toLogString(returnTypeFromAnnotation) + " according to annotation - Must return a resource type"); returnType = (Class<? extends IBaseResource>) returnTypeFromMethod;
} // } else {
returnType = returnTypeFromAnnotation; // This is a plain provider method returning a resource, so it should be
} else { // an operation or global search presumably
// if (IRestfulClient.class.isAssignableFrom(theMethod.getDeclaringClass())) { // returnType = null;
// Clients don't define their methods in resource specific types, so they can
// infer their resource type from the method return type.
returnType = (Class<? extends IBaseResource>) returnTypeFromMethod;
// } else {
// This is a plain provider method returning a resource, so it should be
// an operation or global search presumably
// returnType = null;
}
} }
if (read != null) { if (read != null) {
return new ReadMethodBinding(returnType, theMethod, theContext, theProvider); return new ReadMethodBinding(returnType, theMethod, theContext, theProvider);
} else if (search != null) { } else if (search != null) {
if (search.dynamic()) {
IDynamicSearchResourceProvider provider = (IDynamicSearchResourceProvider) theProvider;
return new DynamicSearchMethodBinding(returnType, theMethod, theContext, provider);
}
return new SearchMethodBinding(returnType, theMethod, theContext, theProvider); return new SearchMethodBinding(returnType, theMethod, theContext, theProvider);
} else if (conformance != null) { } else if (conformance != null) {
return new ConformanceMethodBinding(theMethod, theContext, theProvider); return new ConformanceMethodBinding(theMethod, theContext, theProvider);
@ -602,31 +405,4 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
return true; return true;
} }
/**
* @see ServletRequestDetails#getByteStreamRequestContents()
*/
public static class ActiveRequestReader implements IRequestReader {
@Override
public InputStream getInputStream(RequestDetails theRequestDetails) throws IOException {
return theRequestDetails.getInputStream();
}
}
/**
* @see ServletRequestDetails#getByteStreamRequestContents()
*/
public static class InactiveRequestReader implements IRequestReader {
@Override
public InputStream getInputStream(RequestDetails theRequestDetails) {
throw new IllegalStateException("The servlet-api JAR is not found on the classpath. Please check that this library is available.");
}
}
/**
* @see ServletRequestDetails#getByteStreamRequestContents()
*/
public static interface IRequestReader {
InputStream getInputStream(RequestDetails theRequestDetails) throws IOException;
}
} }

View File

@ -1,61 +1,25 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.IRestfulResponse;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<MethodOutcome> { abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<MethodOutcome> {
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseOutcomeReturningMethodBinding.class); static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseOutcomeReturningMethodBinding.class);
@ -76,8 +40,6 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
} }
} }
protected abstract void addParametersForServerRequest(RequestDetails theRequest, Object[] theParams);
/** /**
* Subclasses may override to allow a void method return type, which is allowable for some methods (e.g. delete) * Subclasses may override to allow a void method return type, which is allowable for some methods (e.g. delete)
*/ */
@ -126,35 +88,6 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
} }
} }
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
Set<RequestTypeEnum> allowableRequestTypes = provideAllowableRequestTypes();
RequestTypeEnum requestType = theRequest.getRequestType();
if (!allowableRequestTypes.contains(requestType)) {
return false;
}
if (!getResourceName().equals(theRequest.getResourceName())) {
return false;
}
if (getMatchingOperation() == null && StringUtils.isNotBlank(theRequest.getOperation())) {
return false;
}
if (getMatchingOperation() != null && !getMatchingOperation().equals(theRequest.getOperation())) {
return false;
}
/*
* Note: Technically this will match an update (PUT) method even if
* there is no ID in the URL - We allow this here because there is no
* better match for that, and this allows the update/PUT method to give
* a helpful error if the client has forgotten to include the
* ID in the URL.
*
* It's also needed for conditional update..
*/
return true;
}
@Override @Override
public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException { public MethodOutcome invokeClient(String theResponseMimeType, Reader theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
@ -168,121 +101,13 @@ abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<Metho
throw processNon2xxResponseAndReturnExceptionToThrow(theResponseStatusCode, theResponseMimeType, theResponseReader); throw processNon2xxResponseAndReturnExceptionToThrow(theResponseStatusCode, theResponseMimeType, theResponseReader);
} }
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
Object[] params = createParametersForServerRequest(theRequest);
addParametersForServerRequest(theRequest, params);
/*
* No need to catch and handle exceptions here, we already handle them one level up including invoking interceptors
* on them
*/
MethodOutcome response;
Object methodReturn = invokeServerMethod(theServer, theRequest, params);
if (methodReturn instanceof IBaseOperationOutcome) {
response = new MethodOutcome();
response.setOperationOutcome((IBaseOperationOutcome) methodReturn);
} else {
response = (MethodOutcome) methodReturn;
}
if (response != null && response.getId() != null && response.getId().hasResourceType()) {
if (getContext().getResourceDefinition(response.getId().getResourceType()) == null) {
throw new InternalErrorException("Server method returned invalid resource ID: " + response.getId().getValue());
}
}
IBaseOperationOutcome outcome = response != null ? response.getOperationOutcome() : null;
IBaseResource resource = response != null ? response.getResource() : null;
return returnResponse(theServer, theRequest, response, outcome, resource);
}
public boolean isReturnVoid() { public boolean isReturnVoid() {
return myReturnVoid; return myReturnVoid;
} }
protected abstract Set<RequestTypeEnum> provideAllowableRequestTypes(); protected abstract Set<RequestTypeEnum> provideAllowableRequestTypes();
private Object returnResponse(IRestfulServer<?> theServer, RequestDetails theRequest, MethodOutcome response, IBaseResource originalOutcome, IBaseResource resource) throws IOException {
boolean allowPrefer = false;
int operationStatus = getOperationStatus(response);
IBaseResource outcome = originalOutcome;
if (ourOperationsWhichAllowPreferHeader.contains(getRestOperationType())) {
allowPrefer = true;
}
if (resource != null && allowPrefer) {
String prefer = theRequest.getHeader(Constants.HEADER_PREFER);
PreferReturnEnum preferReturn = RestfulServerUtils.parsePreferHeader(prefer);
if (preferReturn != null) {
if (preferReturn == PreferReturnEnum.REPRESENTATION) {
outcome = resource;
}
}
}
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = theServer.getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest, outcome);
if (!continueProcessing) {
return null;
}
}
IRestfulResponse restfulResponse = theRequest.getResponse();
if (response != null) {
if (response.getResource() != null) {
restfulResponse.setOperationResourceLastUpdated(RestfulServerUtils.extractLastUpdatedFromResource(response.getResource()));
}
IIdType responseId = response.getId();
if (responseId != null && responseId.getResourceType() == null && responseId.hasIdPart()) {
responseId = responseId.withResourceType(getResourceName());
}
if (responseId != null) {
String serverBase = theRequest.getFhirServerBase();
responseId = RestfulServerUtils.fullyQualifyResourceIdOrReturnNull(theServer, resource, serverBase, responseId);
restfulResponse.setOperationResourceId(responseId);
}
}
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
Set<SummaryEnum> summaryMode = Collections.emptySet();
return restfulResponse.streamResponseAsResource(outcome, prettyPrint, summaryMode, operationStatus, null, theRequest.isRespondGzip(), true);
// return theRequest.getResponse().returnResponse(ParseAction.create(outcome), operationStatus, allowPrefer, response, getResourceName());
}
protected void streamOperationOutcome(BaseServerResponseException theE, RestfulServer theServer, EncodingEnum theEncodingNotNull, HttpServletResponse theResponse, RequestDetails theRequest) throws IOException {
theResponse.setStatus(theE.getStatusCode());
theServer.addHeadersToResponse(theResponse);
if (theE.getOperationOutcome() != null) {
theResponse.setContentType(theEncodingNotNull.getResourceContentType());
IParser parser = theEncodingNotNull.newParser(theServer.getFhirContext());
parser.setPrettyPrint(RestfulServerUtils.prettyPrintResponse(theServer, theRequest));
Writer writer = theResponse.getWriter();
try {
parser.encodeResourceToWriter(theE.getOperationOutcome(), writer);
} finally {
writer.close();
}
} else {
theResponse.setContentType(Constants.CT_TEXT);
Writer writer = theResponse.getWriter();
try {
writer.append(theE.getMessage());
} finally {
writer.close();
}
}
}
protected static void parseContentLocation(FhirContext theContext, MethodOutcome theOutcomeToPopulate, String theLocationHeader) { protected static void parseContentLocation(FhirContext theContext, MethodOutcome theOutcomeToPopulate, String theLocationHeader) {
if (StringUtils.isBlank(theLocationHeader)) { if (StringUtils.isBlank(theLocationHeader)) {

View File

@ -34,6 +34,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;

View File

@ -0,0 +1,94 @@
package ca.uhn.fhir.rest.client.method;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public abstract class BaseQueryParameter implements IParameter {
public abstract List<QualifiedParamList> encode(FhirContext theContext, Object theObject) throws InternalErrorException;
public abstract String getName();
public abstract RestSearchParameterTypeEnum getParamType();
/**
* Parameter should return true if {@link #parse(FhirContext, List)} should be called even if the query string
* contained no values for the given parameter
*/
public abstract boolean handlesMissing();
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore for now
}
public abstract boolean isRequired();
public abstract Object parse(FhirContext theContext, List<QualifiedParamList> theString) throws InternalErrorException, InvalidRequestException;
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
if (theSourceClientArgument == null) {
if (isRequired()) {
throw new NullPointerException("SearchParameter '" + getName() + "' is required and may not be null");
}
} else {
List<QualifiedParamList> value = encode(theContext, theSourceClientArgument);
for (QualifiedParamList nextParamEntry : value) {
StringBuilder b = new StringBuilder();
for (String str : nextParamEntry) {
if (b.length() > 0) {
b.append(",");
}
b.append(str);
}
String qualifier = nextParamEntry.getQualifier();
String paramName = isNotBlank(qualifier) ? getName() + qualifier : getName();
List<String> paramValues = theTargetQueryArguments.get(paramName);
if (paramValues == null) {
paramValues = new ArrayList<String>(value.size());
theTargetQueryArguments.put(paramName, paramValues);
}
paramValues.add(b.toString());
}
}
}
}

View File

@ -1,61 +1,33 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome; import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException; import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.ReflectionUtil;
import ca.uhn.fhir.util.UrlUtil;
public abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Object> { public abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Object> {
protected static final Set<String> ALLOWED_PARAMS; protected static final Set<String> ALLOWED_PARAMS;
@ -72,7 +44,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
set.add(Constants.PARAM_COUNT); set.add(Constants.PARAM_COUNT);
set.add(Constants.PARAM_SUMMARY); set.add(Constants.PARAM_SUMMARY);
set.add(Constants.PARAM_ELEMENTS); set.add(Constants.PARAM_ELEMENTS);
set.add(ResponseHighlighterInterceptor.PARAM_RAW);
ALLOWED_PARAMS = Collections.unmodifiableSet(set); ALLOWED_PARAMS = Collections.unmodifiableSet(set);
} }
@ -107,8 +78,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
} }
} else if (Bundle.class.isAssignableFrom(methodReturnType)) { } else if (Bundle.class.isAssignableFrom(methodReturnType)) {
myMethodReturnType = MethodReturnTypeEnum.BUNDLE; myMethodReturnType = MethodReturnTypeEnum.BUNDLE;
} else if (IBundleProvider.class.isAssignableFrom(methodReturnType)) {
myMethodReturnType = MethodReturnTypeEnum.BUNDLE_PROVIDER;
} else if (MethodOutcome.class.isAssignableFrom(methodReturnType)) { } else if (MethodOutcome.class.isAssignableFrom(methodReturnType)) {
myMethodReturnType = MethodReturnTypeEnum.METHOD_OUTCOME; myMethodReturnType = MethodReturnTypeEnum.METHOD_OUTCOME;
} else { } else {
@ -195,8 +164,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
} else { } else {
throw new InvalidResponseException(theResponseStatusCode, "FHIR server call returned a bundle with multiple resources, but this method is only able to returns one."); throw new InvalidResponseException(theResponseStatusCode, "FHIR server call returned a bundle with multiple resources, but this method is only able to returns one.");
} }
case BUNDLE_PROVIDER:
throw new IllegalStateException("Return type of " + IBundleProvider.class.getSimpleName() + " is not supported in clients");
default: default:
break; break;
} }
@ -219,8 +186,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
return Collections.singletonList(resource); return Collections.singletonList(resource);
case RESOURCE: case RESOURCE:
return resource; return resource;
case BUNDLE_PROVIDER:
throw new IllegalStateException("Return type of " + IBundleProvider.class.getSimpleName() + " is not supported in clients");
case BUNDLE_RESOURCE: case BUNDLE_RESOURCE:
return resource; return resource;
case METHOD_OUTCOME: case METHOD_OUTCOME:
@ -248,176 +213,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
return preferTypes; return preferTypes;
} }
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
final ResourceOrDstu1Bundle responseObject = doInvokeServer(theServer, theRequest);
Set<SummaryEnum> summaryMode = RestfulServerUtils.determineSummaryMode(theRequest);
if (responseObject.getResource() != null) {
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = theServer.getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getResource());
if (!continueProcessing) {
return null;
}
}
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
return theRequest.getResponse().streamResponseAsResource(responseObject.getResource(), prettyPrint, summaryMode, Constants.STATUS_HTTP_200_OK, null, theRequest.isRespondGzip(),
isAddContentLocationHeader());
}
// Is this request coming from a browser
String uaHeader = theRequest.getHeader("user-agent");
boolean requestIsBrowser = false;
if (uaHeader != null && uaHeader.contains("Mozilla")) {
requestIsBrowser = true;
}
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = theServer.getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest, responseObject.getDstu1Bundle());
if (!continueProcessing) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return null;
}
}
return theRequest.getResponse().streamResponseAsBundle(responseObject.getDstu1Bundle(), summaryMode, theRequest.isRespondGzip(), requestIsBrowser);
}
public ResourceOrDstu1Bundle doInvokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) {
// Method params
Object[] params = new Object[getParameters().size()];
for (int i = 0; i < getParameters().size(); i++) {
IParameter param = getParameters().get(i);
if (param != null) {
params[i] = param.translateQueryParametersIntoServerArgument(theRequest, this);
}
}
Object resultObj = invokeServer(theServer, theRequest, params);
Integer count = RestfulServerUtils.extractCountParameter(theRequest);
final ResourceOrDstu1Bundle responseObject;
switch (getReturnType()) {
case BUNDLE: {
/*
* Figure out the self-link for this request
*/
String serverBase = theRequest.getServerBaseForRequest();
String linkSelf;
StringBuilder b = new StringBuilder();
b.append(serverBase);
if (isNotBlank(theRequest.getRequestPath())) {
b.append('/');
b.append(theRequest.getRequestPath());
}
// For POST the URL parameters get jumbled with the post body parameters so don't include them, they might be huge
if (theRequest.getRequestType() == RequestTypeEnum.GET) {
boolean first = true;
Map<String, String[]> parameters = theRequest.getParameters();
for (String nextParamName : new TreeSet<String>(parameters.keySet())) {
for (String nextParamValue : parameters.get(nextParamName)) {
if (first) {
b.append('?');
first = false;
} else {
b.append('&');
}
b.append(UrlUtil.escape(nextParamName));
b.append('=');
b.append(UrlUtil.escape(nextParamValue));
}
}
}
linkSelf = b.toString();
if (getMethodReturnType() == MethodReturnTypeEnum.BUNDLE_RESOURCE) {
IBaseResource resource;
IPrimitiveType<Date> lastUpdated;
if (resultObj instanceof IBundleProvider) {
IBundleProvider result = (IBundleProvider) resultObj;
resource = result.getResources(0, 1).get(0);
lastUpdated = result.getPublished();
} else {
resource = (IBaseResource) resultObj;
lastUpdated = theServer.getFhirContext().getVersion().getLastUpdated(resource);
}
/*
* We assume that the bundle we got back from the handling method may not have everything populated (e.g. self links, bundle type, etc) so we do that here.
*/
IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory();
bundleFactory.initializeWithBundleResource(resource);
bundleFactory.addRootPropertiesToBundle(null, theRequest.getFhirServerBase(), linkSelf, count, getResponseBundleType(), lastUpdated);
responseObject = new ResourceOrDstu1Bundle(resource);
} else {
Set<Include> includes = getRequestIncludesFromParams(params);
IBundleProvider result = (IBundleProvider) resultObj;
if (count == null) {
count = result.preferredPageSize();
}
Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET);
if (offsetI == null || offsetI < 0) {
offsetI = 0;
}
Integer resultSize = result.size();
int start;
if (resultSize != null) {
start = Math.max(0, Math.min(offsetI, resultSize - 1));
} else {
start = offsetI;
}
IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory();
ResponseEncoding responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest, theServer.getDefaultResponseEncoding());
EncodingEnum linkEncoding = theRequest.getParameters().containsKey(Constants.PARAM_FORMAT) && responseEncoding != null ? responseEncoding.getEncoding() : null;
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
bundleFactory.initializeBundleFromBundleProvider(theServer, result, linkEncoding, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, null, getResponseBundleType(),
includes);
Bundle bundle = bundleFactory.getDstu1Bundle();
if (bundle != null) {
responseObject = new ResourceOrDstu1Bundle(bundle);
} else {
IBaseResource resBundle = bundleFactory.getResourceBundle();
responseObject = new ResourceOrDstu1Bundle(resBundle);
}
}
break;
}
case RESOURCE: {
IBundleProvider result = (IBundleProvider) resultObj;
if (result.size() == 0) {
throw new ResourceNotFoundException(theRequest.getId());
} else if (result.size() > 1) {
throw new InternalErrorException("Method returned multiple resources");
}
IBaseResource resource = result.getResources(0, 1).get(0);
responseObject = new ResourceOrDstu1Bundle(resource);
break;
}
default:
throw new IllegalStateException(); // should not happen
}
return responseObject;
}
public abstract Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException;
/** /**
* Should the response include a Content-Location header. Search method bunding (and any others?) may override this to disable the content-location, since it doesn't make sense * Should the response include a Content-Location header. Search method bunding (and any others?) may override this to disable the content-location, since it doesn't make sense
*/ */
@ -430,7 +225,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
} }
public enum MethodReturnTypeEnum { public enum MethodReturnTypeEnum {
BUNDLE, BUNDLE_PROVIDER, BUNDLE_RESOURCE, LIST_OF_RESOURCES, METHOD_OUTCOME, RESOURCE BUNDLE, BUNDLE_RESOURCE, LIST_OF_RESOURCES, METHOD_OUTCOME, RESOURCE
} }
public static class ResourceOrDstu1Bundle { public static class ResourceOrDstu1Bundle {

View File

@ -32,6 +32,7 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam; import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -23,28 +23,18 @@ package ca.uhn.fhir.rest.client.method;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import org.hl7.fhir.instance.model.api.IBaseConformance; import org.hl7.fhir.instance.model.api.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding { public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding {
public ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) { public ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
super(theMethod.getReturnType(), theMethod, theContext, theProvider); super(theMethod.getReturnType(), theMethod, theContext, theProvider);
// if (Modifier.isAbstract(theMethod.getReturnType().getModifiers())) {
// throw new ConfigurationException("Conformance resource provider method '" + theMethod.getName() + "' must not be abstract");
// }
MethodReturnTypeEnum methodReturnType = getMethodReturnType(); MethodReturnTypeEnum methodReturnType = getMethodReturnType();
Class<?> genericReturnType = (Class<?>) theMethod.getGenericReturnType(); Class<?> genericReturnType = (Class<?>) theMethod.getGenericReturnType();
if (methodReturnType != MethodReturnTypeEnum.RESOURCE || !IBaseConformance.class.isAssignableFrom(genericReturnType)) { if (methodReturnType != MethodReturnTypeEnum.RESOURCE || !IBaseConformance.class.isAssignableFrom(genericReturnType)) {
@ -72,33 +62,6 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding
return retVal; return retVal;
} }
@Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws BaseServerResponseException {
IBaseResource conf = (IBaseResource) invokeServerMethod(theServer, theRequest, theMethodParams);
return new SimpleBundleProvider(conf);
}
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (theRequest.getRequestType() == RequestTypeEnum.OPTIONS) {
if (theRequest.getOperation() == null && theRequest.getResourceName() == null) {
return true;
}
}
if (theRequest.getResourceName() != null) {
return false;
}
if ("metadata".equals(theRequest.getOperation())) {
if (theRequest.getRequestType() == RequestTypeEnum.GET) {
return true;
}
throw new MethodNotAllowedException("/metadata request must use HTTP GET", RequestTypeEnum.GET);
}
return false;
}
@Override @Override
public RestOperationTypeEnum getRestOperationType() { public RestOperationTypeEnum getRestOperationType() {

View File

@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.client.method;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -26,25 +26,21 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IntegerDt; import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.Since; import ca.uhn.fhir.rest.annotation.Since;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.param.ParameterUtil; import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class CountParameter implements IParameter { public class CountParameter implements IParameter {
private Class<?> myType;
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException {
if (theSourceClientArgument != null) { if (theSourceClientArgument != null) {
IntegerDt since = ParameterUtil.toInteger(theSourceClientArgument); IntegerDt since = ParameterUtil.toInteger(theSourceClientArgument);
if (since.isEmpty() == false) { if (since.isEmpty() == false) {
@ -53,33 +49,16 @@ public class CountParameter implements IParameter {
} }
} }
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
String[] sinceParams = theRequest.getParameters().get(Constants.PARAM_COUNT);
if (sinceParams != null) {
if (sinceParams.length > 0) {
if (StringUtils.isNotBlank(sinceParams[0])) {
try {
IntegerDt since = new IntegerDt(sinceParams[0]);
return ParameterUtil.fromInteger(myType, since);
} catch (DataFormatException e) {
throw new InvalidRequestException("Invalid " + Constants.PARAM_COUNT + " value: " + sinceParams[0]);
}
}
}
}
return ParameterUtil.fromInteger(myType, null);
}
@Override @Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null) { if (theOuterCollectionType != null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + Since.class.getName() + " but can not be of collection type"); throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + Since.class.getName()
+ " but can not be of collection type");
} }
if (!ParameterUtil.getBindableIntegerTypes().contains(theParameterType)) { if (!ParameterUtil.getBindableIntegerTypes().contains(theParameterType)) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" +theMethod.getDeclaringClass().getCanonicalName()+ "' is annotated with @" + Since.class.getName() + " but type '" + theParameterType + "' is an invalid type, must be one of: " + ParameterUtil.getBindableIntegerTypes()); throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + Since.class.getName()
+ " but type '" + theParameterType + "' is an invalid type, must be one of: " + ParameterUtil.getBindableIntegerTypes());
} }
myType = theParameterType;
} }
} }

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam { public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {

View File

@ -94,10 +94,6 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
return retVal; return retVal;
} }
@Override
protected void addParametersForServerRequest(RequestDetails theRequest, Object[] theParams) {
theParams[getIdParameterIndex()] = theRequest.getId();
}
@Override @Override
protected String getMatchingOperation() { protected String getMatchingOperation() {

View File

@ -1,167 +0,0 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DynamicSearchMethodBinding extends BaseResourceReturningMethodBinding {
private IDynamicSearchResourceProvider myProvider;
private List<RuntimeSearchParam> mySearchParameters;
private HashSet<String> myParamNames;
private Integer myIdParamIndex;
public DynamicSearchMethodBinding(Class<? extends IBaseResource> theReturnResourceType, Method theMethod, FhirContext theContext, IDynamicSearchResourceProvider theProvider) {
super(theReturnResourceType, theMethod, theContext, theProvider);
myProvider = theProvider;
mySearchParameters = myProvider.getSearchParameters();
myParamNames = new HashSet<String>();
for (RuntimeSearchParam next : mySearchParameters) {
myParamNames.add(next.getName());
}
myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());
}
@Override
protected BundleTypeEnum getResponseBundleType() {
return BundleTypeEnum.SEARCHSET;
}
@Override
public List<IParameter> getParameters() {
List<IParameter> retVal = new ArrayList<IParameter>(super.getParameters());
for (RuntimeSearchParam next : mySearchParameters) {
// TODO: what is this?
}
return retVal;
}
@Override
public ReturnTypeEnum getReturnType() {
return ReturnTypeEnum.BUNDLE;
}
@Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
if (myIdParamIndex != null) {
theMethodParams[myIdParamIndex] = theRequest.getId();
}
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
return toResourceList(response);
}
@Override
public RestOperationTypeEnum getRestOperationType() {
return RestOperationTypeEnum.SEARCH_TYPE;
}
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DynamicSearchMethodBinding.class);
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (!theRequest.getResourceName().equals(getResourceName())) {
ourLog.trace("Method {} doesn't match because resource name {} != {}", new Object[] { getMethod().getName(), theRequest.getResourceName(), getResourceName() } );
return false;
}
if (theRequest.getId() != null && myIdParamIndex == null) {
ourLog.trace("Method {} doesn't match because ID is not null: {}", theRequest.getId());
return false;
}
if (theRequest.getRequestType() == RequestTypeEnum.GET && theRequest.getOperation() != null && !Constants.PARAM_SEARCH.equals(theRequest.getOperation())) {
ourLog.trace("Method {} doesn't match because request type is GET but operation is not null: {}", theRequest.getId(), theRequest.getOperation());
return false;
}
if (theRequest.getRequestType() == RequestTypeEnum.POST && !Constants.PARAM_SEARCH.equals(theRequest.getOperation())) {
ourLog.trace("Method {} doesn't match because request type is POST but operation is not _search: {}", theRequest.getId(), theRequest.getOperation());
return false;
}
if (theRequest.getRequestType() != RequestTypeEnum.GET && theRequest.getRequestType() != RequestTypeEnum.POST) {
ourLog.trace("Method {} doesn't match because request type is {}", getMethod());
return false;
}
if (theRequest.getCompartmentName() != null) {
ourLog.trace("Method {} doesn't match because it is for compartment {}", new Object[] { getMethod(), theRequest.getCompartmentName() });
return false;
}
for (String next : theRequest.getParameters().keySet()) {
if (next.charAt(0) == '_') {
continue;
}
String nextQualified = next;
int colonIndex = next.indexOf(':');
int dotIndex = next.indexOf('.');
if (colonIndex != -1 || dotIndex != -1) {
int index;
if (colonIndex != -1 && dotIndex != -1) {
index = Math.min(colonIndex, dotIndex);
} else {
index = (colonIndex != -1) ? colonIndex : dotIndex;
}
next = next.substring(0, index);
}
if (!myParamNames.contains(next)) {
ourLog.trace("Method {} doesn't match because has parameter {}", new Object[] { getMethod(), nextQualified });
return false;
}
}
return true;
}
@Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
// there should be no way to call this....
throw new UnsupportedOperationException("Dynamic search methods are only used for server implementations");
}
public Collection<? extends RuntimeSearchParam> getSearchParams() {
return mySearchParameters;
}
}

View File

@ -1,183 +0,0 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.param.CompositeOrListParam;
import ca.uhn.fhir.rest.param.DateOrListParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.NumberOrListParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.QuantityOrListParam;
import ca.uhn.fhir.rest.param.QuantityParam;
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenOrListParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriOrListParam;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
import ca.uhn.fhir.rest.server.SearchParameterMap;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DynamicSearchParameter implements IParameter {
private Map<String, RuntimeSearchParam> myNameToParam = new HashMap<String, RuntimeSearchParam>();
public DynamicSearchParameter(IDynamicSearchResourceProvider theProvider) {
for (RuntimeSearchParam next : theProvider.getSearchParameters()) {
myNameToParam.put(next.getName(), next);
}
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
throw new UnsupportedOperationException("Dynamic search is not supported in client mode (use fluent client for dynamic-like searches)");
}
@SuppressWarnings("unchecked")
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
SearchParameterMap retVal = new SearchParameterMap();
for (String next : theRequest.getParameters().keySet()) {
String qualifier = null;
String qualifiedParamName = next;
String unqualifiedParamName = next;
RuntimeSearchParam param = myNameToParam.get(next);
if (param == null) {
int colonIndex = next.indexOf(':');
int dotIndex = next.indexOf('.');
if (colonIndex != -1 || dotIndex != -1) {
int index;
if (colonIndex != -1 && dotIndex != -1) {
index = Math.min(colonIndex, dotIndex);
} else {
index = (colonIndex != -1) ? colonIndex : dotIndex;
}
qualifier = next.substring(index);
next = next.substring(0, index);
unqualifiedParamName = next;
param = myNameToParam.get(next);
}
}
if (param != null) {
for (String nextValue : theRequest.getParameters().get(qualifiedParamName)) {
QualifiedParamList paramList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, nextValue);
FhirContext ctx = theRequest.getServer().getFhirContext();
switch (param.getParamType()) {
case COMPOSITE:
Class<? extends IQueryParameterType> left = toParamType(param.getCompositeOf().get(0));
Class<? extends IQueryParameterType> right = toParamType(param.getCompositeOf().get(0));
@SuppressWarnings({ "rawtypes" })
CompositeOrListParam compositeOrListParam = new CompositeOrListParam(left, right);
compositeOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, compositeOrListParam);
break;
case DATE:
DateOrListParam dateOrListParam = new DateOrListParam();
dateOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, dateOrListParam);
break;
case NUMBER:
NumberOrListParam numberOrListParam = new NumberOrListParam();
numberOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, numberOrListParam);
break;
case QUANTITY:
QuantityOrListParam quantityOrListParam = new QuantityOrListParam();
quantityOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, quantityOrListParam);
break;
case REFERENCE:
ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam();
referenceOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, referenceOrListParam);
break;
case STRING:
StringOrListParam stringOrListParam = new StringOrListParam();
stringOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, stringOrListParam);
break;
case TOKEN:
TokenOrListParam tokenOrListParam = new TokenOrListParam();
tokenOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, tokenOrListParam);
break;
case URI:
UriOrListParam uriOrListParam = new UriOrListParam();
uriOrListParam.setValuesAsQueryTokens(ctx, unqualifiedParamName, paramList);
retVal.add(next, uriOrListParam);
break;
case HAS:
// Should not happen
break;
}
}
}
}
return retVal;
}
private Class<? extends IQueryParameterType> toParamType(RuntimeSearchParam theRuntimeSearchParam) {
switch (theRuntimeSearchParam.getParamType()) {
case COMPOSITE:
throw new IllegalStateException("Composite subtype");
case DATE:
return DateParam.class;
case NUMBER:
return NumberParam.class;
case QUANTITY:
return QuantityParam.class;
case REFERENCE:
return ReferenceParam.class;
case STRING:
return StringParam.class;
case TOKEN:
return TokenParam.class;
default:
throw new IllegalStateException("null type");
}
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// nothing
}
}

View File

@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.client.method;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -24,31 +24,23 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.param.CollectionBinder;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class ElementsParameter implements IParameter { public class ElementsParameter implements IParameter {
@SuppressWarnings("rawtypes")
private Class<? extends Collection> myInnerCollectionType;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException {
if (theSourceClientArgument instanceof Collection) { if (theSourceClientArgument instanceof Collection) {
StringBuilder values = new StringBuilder(); StringBuilder values = new StringBuilder();
for (String next : (Collection<String>) theSourceClientArgument) { for (String next : (Collection<String>) theSourceClientArgument) {
@ -68,62 +60,11 @@ public class ElementsParameter implements IParameter {
} }
} }
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
Set<String> value = getElementsValueOrNull(theRequest);
if (value == null || value.isEmpty()) {
return null;
}
if (myInnerCollectionType == null) {
return StringUtils.join(value, ',');
}
try {
Collection retVal = myInnerCollectionType.newInstance();
retVal.addAll(value);
return retVal;
} catch (InstantiationException e) {
throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
} catch (IllegalAccessException e) {
throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
}
}
public static Set<String> getElementsValueOrNull(RequestDetails theRequest) {
String[] summary = theRequest.getParameters().get(Constants.PARAM_ELEMENTS);
if (summary != null && summary.length > 0) {
Set<String> retVal = new HashSet<String>();
for (String next : summary) {
StringTokenizer tok = new StringTokenizer(next, ",");
while (tok.hasMoreTokens()) {
String token = tok.nextToken();
if (isNotBlank(token)) {
retVal.add(token);
}
}
}
if (retVal.isEmpty()) {
return null;
}
// Always include the meta element even for subsetted values
retVal.add("meta");
return retVal;
}
return null;
}
@Override @Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null) { if (theOuterCollectionType != null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class + " but can not be a collection of collections"); throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
} + " but can not be a collection of collections");
if (theInnerCollectionType != null) {
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
} }
} }

View File

@ -1,26 +1,5 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -37,15 +16,12 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.GetTags; import ca.uhn.fhir.rest.annotation.GetTags;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
public class GetTagsMethodBinding extends BaseMethodBinding<TagList> { public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
@ -57,11 +33,7 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
public GetTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, GetTags theAnnotation) { public GetTagsMethodBinding(Method theMethod, FhirContext theContext, Object theProvider, GetTags theAnnotation) {
super(theMethod, theContext, theProvider); super(theMethod, theContext, theProvider);
if (theProvider instanceof IResourceProvider) { myType = theAnnotation.type();
myType = ((IResourceProvider) theProvider).getResourceType();
} else {
myType = theAnnotation.type();
}
if (!Modifier.isInterface(myType.getModifiers())) { if (!Modifier.isInterface(myType.getModifiers())) {
myResourceName = theContext.getResourceDefinition(myType).getName(); myResourceName = theContext.getResourceDefinition(myType).getName();
@ -86,30 +58,6 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
return RestOperationTypeEnum.GET_TAGS; return RestOperationTypeEnum.GET_TAGS;
} }
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (theRequest.getRequestType() != RequestTypeEnum.GET) {
return false;
}
if (!Constants.PARAM_TAGS.equals(theRequest.getOperation())) {
return false;
}
if (myResourceName == null) {
if (getResourceName() != null) {
return false;
}
} else if (!myResourceName.equals(theRequest.getResourceName())) {
return false;
}
if ((myIdParamIndex != null) != (theRequest.getId() != null)) {
return false;
}
// if ((myVersionIdParamIndex != null) != (theRequest.getVersionId() != null)) {
// return false;
// }
return true;
}
@Override @Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
@ -159,28 +107,5 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
} }
throw processNon2xxResponseAndReturnExceptionToThrow(theResponseStatusCode, theResponseMimeType, theResponseReader); throw processNon2xxResponseAndReturnExceptionToThrow(theResponseStatusCode, theResponseMimeType, theResponseReader);
} }
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
Object[] params = createParametersForServerRequest(theRequest);
if (myIdParamIndex != null) {
params[myIdParamIndex] = theRequest.getId();
}
if (myVersionIdParamIndex != null) {
params[myVersionIdParamIndex] = theRequest.getId();
}
TagList resp = (TagList) invokeServerMethod(theServer, theRequest, params);
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = theServer.getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest, resp);
if (!continueProcessing) {
return null;
}
}
return theRequest.getResponse().returnResponse(ParseAction.create(resp), Constants.STATUS_HTTP_200_OK, false, null, null);
}
} }

View File

@ -10,7 +10,7 @@ package ca.uhn.fhir.rest.client.method;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -25,23 +25,20 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.Date; import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.History; import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class HistoryMethodBinding extends BaseResourceReturningMethodBinding { public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
@ -57,16 +54,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
History historyAnnotation = theMethod.getAnnotation(History.class); History historyAnnotation = theMethod.getAnnotation(History.class);
Class<? extends IBaseResource> type = historyAnnotation.type(); Class<? extends IBaseResource> type = historyAnnotation.type();
if (Modifier.isInterface(type.getModifiers())) { if (Modifier.isInterface(type.getModifiers())) {
if (theProvider instanceof IResourceProvider) { myResourceOperationType = RestOperationTypeEnum.HISTORY_SYSTEM;
type = ((IResourceProvider) theProvider).getResourceType();
if (myIdParamIndex != null) {
myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
} else {
myResourceOperationType = RestOperationTypeEnum.HISTORY_TYPE;
}
} else {
myResourceOperationType = RestOperationTypeEnum.HISTORY_SYSTEM;
}
} else { } else {
if (myIdParamIndex != null) { if (myIdParamIndex != null) {
myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE; myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
@ -98,34 +86,6 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
return ReturnTypeEnum.BUNDLE; return ReturnTypeEnum.BUNDLE;
} }
// ObjectUtils.equals is replaced by a JDK7 method..
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (!Constants.PARAM_HISTORY.equals(theRequest.getOperation())) {
return false;
}
if (theRequest.getResourceName() == null) {
return myResourceOperationType == RestOperationTypeEnum.HISTORY_SYSTEM;
}
if (!StringUtils.equals(theRequest.getResourceName(), myResourceName)) {
return false;
}
boolean haveIdParam = theRequest.getId() != null && !theRequest.getId().isEmpty();
boolean wantIdParam = myIdParamIndex != null;
if (haveIdParam != wantIdParam) {
return false;
}
if (theRequest.getId() == null) {
return myResourceOperationType == RestOperationTypeEnum.HISTORY_TYPE;
} else if (theRequest.getId().hasVersionIdPart()) {
return false;
}
return true;
}
@Override @Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
IdDt id = null; IdDt id = null;
@ -150,64 +110,6 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
return retVal; return retVal;
} }
@Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
if (myIdParamIndex != null) {
theMethodParams[myIdParamIndex] = theRequest.getId();
}
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
final IBundleProvider resources = toResourceList(response);
/*
* We wrap the response so we can verify that it has the ID and version set,
* as is the contract for history
*/
return new IBundleProvider() {
@Override
public IPrimitiveType<Date> getPublished() {
return resources.getPublished();
}
@Override
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
List<IBaseResource> retVal = resources.getResources(theFromIndex, theToIndex);
int index = theFromIndex;
for (IBaseResource nextResource : retVal) {
if (nextResource.getIdElement() == null || isBlank(nextResource.getIdElement().getIdPart())) {
throw new InternalErrorException("Server provided resource at index " + index + " with no ID set (using IResource#setId(IdDt))");
}
if (isBlank(nextResource.getIdElement().getVersionIdPart()) && nextResource instanceof IResource) {
//TODO: Use of a deprecated method should be resolved.
IdDt versionId = (IdDt) ResourceMetadataKeyEnum.VERSION_ID.get((IResource) nextResource);
if (versionId == null || versionId.isEmpty()) {
throw new InternalErrorException("Server provided resource at index " + index + " with no Version ID set (using IResource#setId(IdDt))");
}
}
index++;
}
return retVal;
}
@Override
public Integer size() {
return resources.size();
}
@Override
public Integer preferredPageSize() {
return resources.preferredPageSize();
}
@Override
public String getUuid() {
return resources.getUuid();
}
};
}
public static HttpGetClientInvocation createHistoryInvocation(FhirContext theContext, String theResourceName, String theId, IPrimitiveType<Date> theSince, Integer theLimit) { public static HttpGetClientInvocation createHistoryInvocation(FhirContext theContext, String theResourceName, String theId, IPrimitiveType<Date> theSince, Integer theLimit) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
if (theResourceName != null) { if (theResourceName != null) {
@ -237,9 +139,6 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
} }
private static Class<? extends IBaseResource> toReturnType(Method theMethod, Object theProvider) { private static Class<? extends IBaseResource> toReturnType(Method theMethod, Object theProvider) {
if (theProvider instanceof IResourceProvider) {
return ((IResourceProvider) theProvider).getResourceType();
}
History historyAnnotation = theMethod.getAnnotation(History.class); History historyAnnotation = theMethod.getAnnotation(History.class);
Class<? extends IBaseResource> type = historyAnnotation.type(); Class<? extends IBaseResource> type = historyAnnotation.type();
if (type != IBaseResource.class && type != IResource.class) { if (type != IBaseResource.class && type != IResource.class) {

View File

@ -26,10 +26,10 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.EncodingEnum;
public class HttpDeleteClientInvocation extends BaseHttpClientInvocation { public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {

View File

@ -31,10 +31,10 @@ import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.EncodingEnum;
/** /**
* @author James Agnew * @author James Agnew

View File

@ -26,11 +26,11 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpClient; import ca.uhn.fhir.rest.client.api.IHttpClient;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.EncodingEnum;
public class HttpPatchClientInvocation extends BaseHttpClientInvocation { public class HttpPatchClientInvocation extends BaseHttpClientInvocation {

View File

@ -24,10 +24,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.IHttpRequest; import ca.uhn.fhir.rest.client.api.IHttpRequest;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.EncodingEnum;
public class HttpSimpleGetClientInvocation extends BaseHttpClientInvocation { public class HttpSimpleGetClientInvocation extends BaseHttpClientInvocation {

View File

@ -24,6 +24,7 @@ import java.util.List;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -0,0 +1,40 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public interface IParameter {
void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType);
void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException;
}

View File

@ -32,9 +32,10 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.annotation.IncludeParam; import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.BaseQueryParameter; import ca.uhn.fhir.rest.param.BaseQueryParameter;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -8,31 +8,79 @@ import java.io.PushbackReader;
import java.io.Reader; import java.io.Reader;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.*; import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.*; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.IQueryParameterAnd;
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.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.api.annotation.Description;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt; import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.IParser; import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.annotation.At;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Count;
import ca.uhn.fhir.rest.annotation.Elements;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.IncludeParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.annotation.RawParam;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.ServerBase;
import ca.uhn.fhir.rest.annotation.Since;
import ca.uhn.fhir.rest.annotation.Sort;
import ca.uhn.fhir.rest.annotation.TagListParam;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.annotation.VersionIdParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.method.OperationParameter.IOperationParamConverter; import ca.uhn.fhir.rest.client.method.OperationParameter.IOperationParamConverter;
import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.param.CollectionBinder;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.server.EncodingEnum; import ca.uhn.fhir.rest.param.HasAndListParam;
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider; import ca.uhn.fhir.rest.param.NumberAndListParam;
import ca.uhn.fhir.rest.server.SearchParameterMap; import ca.uhn.fhir.rest.param.QuantityAndListParam;
import ca.uhn.fhir.rest.server.method.ResourceParameter; import ca.uhn.fhir.rest.param.ReferenceAndListParam;
import ca.uhn.fhir.rest.server.method.TransactionParameter; import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.server.method.ResourceParameter.Mode; import ca.uhn.fhir.rest.param.TokenAndListParam;
import ca.uhn.fhir.rest.param.UriAndListParam;
import ca.uhn.fhir.util.DateUtils; import ca.uhn.fhir.util.DateUtils;
import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.ReflectionUtil;
@ -323,14 +371,7 @@ public class MethodUtil {
Class<?> parameterType = parameterTypes[paramIndex]; Class<?> parameterType = parameterTypes[paramIndex];
Class<? extends java.util.Collection<?>> outerCollectionType = null; Class<? extends java.util.Collection<?>> outerCollectionType = null;
Class<? extends java.util.Collection<?>> innerCollectionType = null; Class<? extends java.util.Collection<?>> innerCollectionType = null;
if (SearchParameterMap.class.equals(parameterType)) { if (TagList.class.isAssignableFrom(parameterType)) {
if (theProvider instanceof IDynamicSearchResourceProvider) {
Search searchAnnotation = theMethod.getAnnotation(Search.class);
if (searchAnnotation != null && searchAnnotation.dynamic()) {
param = new DynamicSearchParameter((IDynamicSearchResourceProvider) theProvider);
}
}
} else if (TagList.class.isAssignableFrom(parameterType)) {
// TagList is handled directly within the method bindings // TagList is handled directly within the method bindings
param = new NullParameter(); param = new NullParameter();
} else { } else {
@ -348,20 +389,7 @@ public class MethodUtil {
} }
} }
/* if (parameterType.equals(SummaryEnum.class)) {
* Note: for the first two here, we're using strings instead of static binding
* so that we don't need the java.servlet JAR on the classpath in order to use
* this class
*/
if (ourServletRequestTypes.contains(parameterType.getName())) {
param = new ServletRequestParameter();
} else if (ourServletResponseTypes.contains(parameterType.getName())) {
param = new ServletResponseParameter();
} else if (parameterType.equals(RequestDetails.class)) {
param = new RequestDetailsParameter();
} else if (parameterType.equals(IRequestOperationCallback.class)) {
param = new RequestOperationCallbackParameter();
} else if (parameterType.equals(SummaryEnum.class)) {
param = new SummaryEnumParameter(); param = new SummaryEnumParameter();
} else if (parameterType.equals(PatchTypeEnum.class)) { } else if (parameterType.equals(PatchTypeEnum.class)) {
param = new PatchTypeParameter(); param = new PatchTypeParameter();
@ -407,15 +435,14 @@ public class MethodUtil {
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType); param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType);
} else if (nextAnnotation instanceof ResourceParam) { } else if (nextAnnotation instanceof ResourceParam) {
Mode mode;
if (IBaseResource.class.isAssignableFrom(parameterType)) { if (IBaseResource.class.isAssignableFrom(parameterType)) {
mode = Mode.RESOURCE; // good
} else if (String.class.equals(parameterType)) { } else if (String.class.equals(parameterType)) {
mode = ResourceParameter.Mode.BODY; // good
} else if (byte[].class.equals(parameterType)) { } else if (byte[].class.equals(parameterType)) {
mode = ResourceParameter.Mode.BODY_BYTE_ARRAY; // good
} else if (EncodingEnum.class.equals(parameterType)) { } else if (EncodingEnum.class.equals(parameterType)) {
mode = Mode.ENCODING; // good
} else { } else {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
b.append("Method '"); b.append("Method '");
@ -427,7 +454,7 @@ public class MethodUtil {
b.append(" or String or byte[]"); b.append(" or String or byte[]");
throw new ConfigurationException(b.toString()); throw new ConfigurationException(b.toString());
} }
param = new ResourceParameter((Class<? extends IResource>) parameterType, theProvider, mode); param = new ResourceParameter();
} else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) { } else if (nextAnnotation instanceof IdParam || nextAnnotation instanceof VersionIdParam) {
param = new NullParameter(); param = new NullParameter();
} else if (nextAnnotation instanceof ServerBase) { } else if (nextAnnotation instanceof ServerBase) {

View File

@ -28,6 +28,7 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -22,7 +22,6 @@ package ca.uhn.fhir.rest.client.method;
import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -49,16 +48,9 @@ import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.method.ResourceParameter;
import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.FhirTerser;
public class OperationMethodBinding extends BaseResourceReturningMethodBinding { public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
@ -134,11 +126,7 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
+ theMethod.getDeclaringClass().getName()); + theMethod.getDeclaringClass().getName());
} }
if (theMethod.getReturnType().equals(IBundleProvider.class)) { myReturnType = ReturnTypeEnum.RESOURCE;
myReturnType = ReturnTypeEnum.BUNDLE;
} else {
myReturnType = ReturnTypeEnum.RESOURCE;
}
if (getResourceName() == null) { if (getResourceName() == null) {
myOtherOperatiopnType = RestOperationTypeEnum.EXTENDED_OPERATION_SERVER; myOtherOperatiopnType = RestOperationTypeEnum.EXTENDED_OPERATION_SERVER;
@ -213,40 +201,6 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
return myReturnType; return myReturnType;
} }
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (getResourceName() == null) {
if (isNotBlank(theRequest.getResourceName())) {
return false;
}
} else if (!getResourceName().equals(theRequest.getResourceName())) {
return false;
}
if (!myName.equals(theRequest.getOperation())) {
return false;
}
RequestTypeEnum requestType = theRequest.getRequestType();
if (requestType != RequestTypeEnum.GET && requestType != RequestTypeEnum.POST) {
// Operations can only be invoked with GET and POST
return false;
}
boolean requestHasId = theRequest.getId() != null;
if (requestHasId) {
if (isCanOperateAtInstanceLevel() == false) {
return false;
}
} else {
if (myCanOperateAtTypeLevel == false) {
return false;
}
}
return true;
}
@Override @Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
String id = null; String id = null;
@ -266,42 +220,6 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
return createOperationInvocation(getContext(), getResourceName(), id, myName, parameters, false); return createOperationInvocation(getContext(), getResourceName(), id, myName, parameters, false);
} }
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
if (theRequest.getRequestType() == RequestTypeEnum.POST) {
IBaseResource requestContents = ResourceParameter.loadResourceFromRequest(theRequest, this, null);
theRequest.getUserData().put(OperationParameter.REQUEST_CONTENTS_USERDATA_KEY, requestContents);
}
return super.invokeServer(theServer, theRequest);
}
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws BaseServerResponseException {
if (theRequest.getRequestType() == RequestTypeEnum.POST) {
// all good
} else if (theRequest.getRequestType() == RequestTypeEnum.GET) {
if (!myIdempotent) {
String message = getContext().getLocalizer().getMessage(OperationMethodBinding.class, "methodNotSupported", theRequest.getRequestType(), RequestTypeEnum.POST.name());
throw new MethodNotAllowedException(message, RequestTypeEnum.POST);
}
} else {
if (!myIdempotent) {
String message = getContext().getLocalizer().getMessage(OperationMethodBinding.class, "methodNotSupported", theRequest.getRequestType(), RequestTypeEnum.POST.name());
throw new MethodNotAllowedException(message, RequestTypeEnum.POST);
}
String message = getContext().getLocalizer().getMessage(OperationMethodBinding.class, "methodNotSupported", theRequest.getRequestType(), RequestTypeEnum.GET.name(), RequestTypeEnum.POST.name());
throw new MethodNotAllowedException(message, RequestTypeEnum.GET, RequestTypeEnum.POST);
}
if (myIdParamIndex != null) {
theMethodParams[myIdParamIndex] = theRequest.getId();
}
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
IBundleProvider retVal = toResourceList(response);
return retVal;
}
public boolean isCanOperateAtInstanceLevel() { public boolean isCanOperateAtInstanceLevel() {
return this.myCanOperateAtInstanceLevel; return this.myCanOperateAtInstanceLevel;
} }
@ -318,12 +236,6 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
return myIdempotent; return myIdempotent;
} }
@Override
protected void populateActionRequestDetailsForInterceptor(RequestDetails theRequestDetails, ActionRequestDetails theDetails, Object[] theMethodParams) {
super.populateActionRequestDetailsForInterceptor(theRequestDetails, theDetails, theMethodParams);
theDetails.setResource((IBaseResource) theRequestDetails.getUserData().get(OperationParameter.REQUEST_CONTENTS_USERDATA_KEY));
}
public void setDescription(String theDescription) { public void setDescription(String theDescription) {
myDescription = theDescription; myDescription = theDescription;
} }

View File

@ -1,7 +1,5 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -24,8 +22,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -33,37 +29,22 @@ import java.util.Map;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IAccessor;
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.IRuntimeDatatypeDefinition;
import ca.uhn.fhir.context.RuntimeChildPrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.model.api.IDatatype; import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IQueryParameterAnd; import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.ValidationModeEnum; import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.param.BaseAndListParam;
import ca.uhn.fhir.rest.param.CollectionBinder;
import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.ParametersUtil;
import ca.uhn.fhir.util.ReflectionUtil;
public class OperationParameter implements IParameter { public class OperationParameter implements IParameter {
@ -72,16 +53,12 @@ public class OperationParameter implements IParameter {
static final String REQUEST_CONTENTS_USERDATA_KEY = OperationParam.class.getName() + "_PARSED_RESOURCE"; static final String REQUEST_CONTENTS_USERDATA_KEY = OperationParam.class.getName() + "_PARSED_RESOURCE";
private boolean myAllowGet;
private final FhirContext myContext; private final FhirContext myContext;
private IOperationParamConverter myConverter; private IOperationParamConverter myConverter;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
private Class<? extends Collection> myInnerCollectionType;
private int myMax; private int myMax;
private int myMin; private int myMin;
private final String myName; private final String myName;
private final String myOperationName;
private Class<?> myParameterType; private Class<?> myParameterType;
private String myParamType; private String myParamType;
private SearchParameter mySearchParameterBinding; private SearchParameter mySearchParameterBinding;
@ -91,39 +68,16 @@ public class OperationParameter implements IParameter {
} }
OperationParameter(FhirContext theCtx, String theOperationName, String theParameterName, int theMin, int theMax) { OperationParameter(FhirContext theCtx, String theOperationName, String theParameterName, int theMin, int theMax) {
myOperationName = theOperationName;
myName = theParameterName; myName = theParameterName;
myMin = theMin; myMin = theMin;
myMax = theMax; myMax = theMax;
myContext = theCtx; myContext = theCtx;
} }
@SuppressWarnings({ "rawtypes", "unchecked" })
private void addValueToList(List<Object> matchingParamValues, Object values) {
if (values != null) {
if (BaseAndListParam.class.isAssignableFrom(myParameterType) && matchingParamValues.size() > 0) {
BaseAndListParam existing = (BaseAndListParam<?>) matchingParamValues.get(0);
BaseAndListParam<?> newAndList = (BaseAndListParam<?>) values;
for (IQueryParameterOr nextAnd : newAndList.getValuesAsQueryTokens()) {
existing.addAnd(nextAnd);
}
} else {
matchingParamValues.add(values);
}
}
}
protected FhirContext getContext() { protected FhirContext getContext() {
return myContext; return myContext;
} }
public int getMax() {
return myMax;
}
public int getMin() {
return myMin;
}
public String getName() { public String getName() {
return myName; return myName;
@ -151,7 +105,6 @@ public class OperationParameter implements IParameter {
myParameterType = theParameterType; myParameterType = theParameterType;
if (theInnerCollectionType != null) { if (theInnerCollectionType != null) {
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, myName);
if (myMax == OperationParam.MAX_DEFAULT) { if (myMax == OperationParam.MAX_DEFAULT) {
myMax = OperationParam.MAX_UNLIMITED; myMax = OperationParam.MAX_UNLIMITED;
} }
@ -181,8 +134,6 @@ public class OperationParameter implements IParameter {
*/ */
isSearchParam &= typeIsConcrete && !IBase.class.isAssignableFrom(myParameterType); isSearchParam &= typeIsConcrete && !IBase.class.isAssignableFrom(myParameterType);
myAllowGet = IPrimitiveType.class.isAssignableFrom(myParameterType) || String.class.equals(myParameterType) || isSearchParam || ValidationModeEnum.class.equals(myParameterType);
/* /*
* The parameter can be of type string for validation methods - This is a bit weird. See ValidateDstu2Test. We * The parameter can be of type string for validation methods - This is a bit weird. See ValidateDstu2Test. We
* should probably clean this up.. * should probably clean this up..
@ -193,7 +144,6 @@ public class OperationParameter implements IParameter {
} else if (DateRangeParam.class.isAssignableFrom(myParameterType)) { } else if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
myParamType = "date"; myParamType = "date";
myMax = 2; myMax = 2;
myAllowGet = true;
} else if (myParameterType.equals(ValidationModeEnum.class)) { } else if (myParameterType.equals(ValidationModeEnum.class)) {
myParamType = "code"; myParamType = "code";
} else if (IBase.class.isAssignableFrom(myParameterType) && typeIsConcrete) { } else if (IBase.class.isAssignableFrom(myParameterType) && typeIsConcrete) {
@ -217,10 +167,6 @@ public class OperationParameter implements IParameter {
return this; return this;
} }
private void throwWrongParamType(Object nextValue) {
throw new InvalidRequestException("Request has parameter " + myName + " of type " + nextValue.getClass().getSimpleName() + " but method expects type " + myParameterType.getSimpleName());
}
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
assert theTargetResource != null; assert theTargetResource != null;
@ -236,185 +182,7 @@ public class OperationParameter implements IParameter {
ParametersUtil.addParameterToParameters(theContext, theTargetResource, sourceClientArgument, myName); ParametersUtil.addParameterToParameters(theContext, theTargetResource, sourceClientArgument, myName);
} }
@SuppressWarnings("unchecked")
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
List<Object> matchingParamValues = new ArrayList<Object>();
if (theRequest.getRequestType() == RequestTypeEnum.GET) {
translateQueryParametersIntoServerArgumentForGet(theRequest, matchingParamValues);
} else {
translateQueryParametersIntoServerArgumentForPost(theRequest, matchingParamValues);
}
if (matchingParamValues.isEmpty()) {
return null;
}
if (myInnerCollectionType == null) {
return matchingParamValues.get(0);
}
Collection<Object> retVal = ReflectionUtil.newInstance(myInnerCollectionType);
retVal.addAll(matchingParamValues);
return retVal;
}
private void translateQueryParametersIntoServerArgumentForGet(RequestDetails theRequest, List<Object> matchingParamValues) {
if (mySearchParameterBinding != null) {
List<QualifiedParamList> params = new ArrayList<QualifiedParamList>();
String nameWithQualifierColon = myName + ":";
for (String nextParamName : theRequest.getParameters().keySet()) {
String qualifier;
if (nextParamName.equals(myName)) {
qualifier = null;
} else if (nextParamName.startsWith(nameWithQualifierColon)) {
qualifier = nextParamName.substring(nextParamName.indexOf(':'));
} else {
// This is some other parameter, not the one bound by this instance
continue;
}
String[] values = theRequest.getParameters().get(nextParamName);
if (values != null) {
for (String nextValue : values) {
params.add(QualifiedParamList.splitQueryStringByCommasIgnoreEscape(qualifier, nextValue));
}
}
}
if (!params.isEmpty()) {
for (QualifiedParamList next : params) {
Object values = mySearchParameterBinding.parse(myContext, Collections.singletonList(next));
addValueToList(matchingParamValues, values);
}
}
} else {
String[] paramValues = theRequest.getParameters().get(myName);
if (paramValues != null && paramValues.length > 0) {
if (myAllowGet) {
if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
List<QualifiedParamList> parameters = new ArrayList<QualifiedParamList>();
parameters.add(QualifiedParamList.singleton(paramValues[0]));
if (paramValues.length > 1) {
parameters.add(QualifiedParamList.singleton(paramValues[1]));
}
DateRangeParam dateRangeParam = new DateRangeParam();
FhirContext ctx = theRequest.getServer().getFhirContext();
dateRangeParam.setValuesAsQueryTokens(ctx, myName, parameters);
matchingParamValues.add(dateRangeParam);
} else if (String.class.isAssignableFrom(myParameterType)) {
for (String next : paramValues) {
matchingParamValues.add(next);
}
} else if (ValidationModeEnum.class.equals(myParameterType)) {
if (isNotBlank(paramValues[0])) {
ValidationModeEnum validationMode = ValidationModeEnum.forCode(paramValues[0]);
if (validationMode != null) {
matchingParamValues.add(validationMode);
} else {
throwInvalidMode(paramValues[0]);
}
}
} else {
for (String nextValue : paramValues) {
FhirContext ctx = theRequest.getServer().getFhirContext();
RuntimePrimitiveDatatypeDefinition def = (RuntimePrimitiveDatatypeDefinition) ctx.getElementDefinition(myParameterType.asSubclass(IBase.class));
IPrimitiveType<?> instance = def.newInstance();
instance.setValueAsString(nextValue);
matchingParamValues.add(instance);
}
}
} else {
HapiLocalizer localizer = theRequest.getServer().getFhirContext().getLocalizer();
String msg = localizer.getMessage(OperationParameter.class, "urlParamNotPrimitive", myOperationName, myName);
throw new MethodNotAllowedException(msg, RequestTypeEnum.POST);
}
}
}
}
private void translateQueryParametersIntoServerArgumentForPost(RequestDetails theRequest, List<Object> matchingParamValues) {
IBaseResource requestContents = (IBaseResource) theRequest.getUserData().get(REQUEST_CONTENTS_USERDATA_KEY);
RuntimeResourceDefinition def = myContext.getResourceDefinition(requestContents);
if (def.getName().equals("Parameters")) {
BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
RuntimeChildPrimitiveDatatypeDefinition nameChild = (RuntimeChildPrimitiveDatatypeDefinition) paramChildElem.getChildByName("name");
BaseRuntimeChildDefinition valueChild = paramChildElem.getChildByName("value[x]");
BaseRuntimeChildDefinition resourceChild = paramChildElem.getChildByName("resource");
IAccessor paramChildAccessor = paramChild.getAccessor();
List<IBase> values = paramChildAccessor.getValues(requestContents);
for (IBase nextParameter : values) {
List<IBase> nextNames = nameChild.getAccessor().getValues(nextParameter);
if (nextNames != null && nextNames.size() > 0) {
IPrimitiveType<?> nextName = (IPrimitiveType<?>) nextNames.get(0);
if (myName.equals(nextName.getValueAsString())) {
if (myParameterType.isAssignableFrom(nextParameter.getClass())) {
matchingParamValues.add(nextParameter);
} else {
List<IBase> paramValues = valueChild.getAccessor().getValues(nextParameter);
List<IBase> paramResources = resourceChild.getAccessor().getValues(nextParameter);
if (paramValues != null && paramValues.size() > 0) {
tryToAddValues(paramValues, matchingParamValues);
} else if (paramResources != null && paramResources.size() > 0) {
tryToAddValues(paramResources, matchingParamValues);
}
}
}
}
}
} else {
if (myParameterType.isAssignableFrom(requestContents.getClass())) {
tryToAddValues(Arrays.asList((IBase) requestContents), matchingParamValues);
}
}
}
@SuppressWarnings("unchecked")
private void tryToAddValues(List<IBase> theParamValues, List<Object> theMatchingParamValues) {
for (Object nextValue : theParamValues) {
if (nextValue == null) {
continue;
}
if (myConverter != null) {
nextValue = myConverter.incomingServer(nextValue);
}
if (!myParameterType.isAssignableFrom(nextValue.getClass())) {
Class<? extends IBaseDatatype> sourceType = (Class<? extends IBaseDatatype>) nextValue.getClass();
Class<? extends IBaseDatatype> targetType = (Class<? extends IBaseDatatype>) myParameterType;
BaseRuntimeElementDefinition<?> sourceTypeDef = myContext.getElementDefinition(sourceType);
BaseRuntimeElementDefinition<?> targetTypeDef = myContext.getElementDefinition(targetType);
if (targetTypeDef instanceof IRuntimeDatatypeDefinition && sourceTypeDef instanceof IRuntimeDatatypeDefinition) {
IRuntimeDatatypeDefinition targetTypeDtDef = (IRuntimeDatatypeDefinition) targetTypeDef;
if (targetTypeDtDef.isProfileOf(sourceType)) {
FhirTerser terser = myContext.newTerser();
IBase newTarget = targetTypeDef.newInstance();
terser.cloneInto((IBase) nextValue, newTarget, true);
theMatchingParamValues.add(newTarget);
continue;
}
}
throwWrongParamType(nextValue);
}
addValueToList(theMatchingParamValues, nextValue);
}
}
public static void throwInvalidMode(String paramValues) { public static void throwInvalidMode(String paramValues) {
throw new InvalidRequestException("Invalid mode value: \"" + paramValues + "\""); throw new InvalidRequestException("Invalid mode value: \"" + paramValues + "\"");

View File

@ -1,47 +1,14 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.CoverageIgnore;
public class PageMethodBinding extends BaseResourceReturningMethodBinding { public class PageMethodBinding extends BaseResourceReturningMethodBinding {
@ -50,143 +17,19 @@ public class PageMethodBinding extends BaseResourceReturningMethodBinding {
super(null, theMethod, theContext, null); super(null, theMethod, theContext, null);
} }
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PageMethodBinding.class);
public IBaseResource provider() {
return null;
}
@Override @Override
protected BundleTypeEnum getResponseBundleType() { protected BundleTypeEnum getResponseBundleType() {
return null; return null;
} }
@Override
public ReturnTypeEnum getReturnType() {
return ReturnTypeEnum.BUNDLE;
}
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
return handlePagingRequest(theServer, theRequest, theRequest.getParameters().get(Constants.PARAM_PAGINGACTION)[0]);
}
@Override
public ResourceOrDstu1Bundle doInvokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) {
IBase bundle = handlePagingRequest(theServer, theRequest, theRequest.getParameters().get(Constants.PARAM_PAGINGACTION)[0]);
if (bundle instanceof Bundle) {
return new ResourceOrDstu1Bundle((Bundle) bundle);
}
return new ResourceOrDstu1Bundle((IBaseResource) bundle);
}
private IBase handlePagingRequest(IRestfulServer<?> theServer, RequestDetails theRequest, String thePagingAction) {
IPagingProvider pagingProvider = theServer.getPagingProvider();
if (pagingProvider == null) {
throw new InvalidRequestException("This server does not support paging");
}
IBundleProvider resultList = pagingProvider.retrieveResultList(thePagingAction);
if (resultList == null) {
ourLog.info("Client requested unknown paging ID[{}]", thePagingAction);
String msg = getContext().getLocalizer().getMessage(PageMethodBinding.class, "unknownSearchId", thePagingAction);
throw new ResourceGoneException(msg);
}
Integer count = RestfulServerUtils.extractCountParameter(theRequest);
if (count == null) {
count = pagingProvider.getDefaultPageSize();
} else if (count > pagingProvider.getMaximumPageSize()) {
count = pagingProvider.getMaximumPageSize();
}
Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET);
if (offsetI == null || offsetI < 0) {
offsetI = 0;
}
Integer totalNum = resultList.size();
int start = offsetI;
if (totalNum != null) {
start = Math.min(start, totalNum - 1);
}
ResponseEncoding responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest, theServer.getDefaultResponseEncoding());
boolean prettyPrint = RestfulServerUtils.prettyPrintResponse(theServer, theRequest);
IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory();
Set<Include> includes = new HashSet<Include>();
String[] reqIncludes = theRequest.getParameters().get(Constants.PARAM_INCLUDE);
if (reqIncludes != null) {
for (String nextInclude : reqIncludes) {
includes.add(new Include(nextInclude));
}
}
String linkSelfBase = theRequest.getFhirServerBase(); // myServerAddressStrategy.determineServerBase(getServletContext(),
// theRequest.getServletRequest());
String completeUrl = theRequest.getCompleteUrl();
String linkSelf = linkSelfBase + completeUrl.substring(theRequest.getCompleteUrl().indexOf('?'));
BundleTypeEnum bundleType = null;
String[] bundleTypeValues = theRequest.getParameters().get(Constants.PARAM_BUNDLETYPE);
if (bundleTypeValues != null) {
bundleType = BundleTypeEnum.VALUESET_BINDER.fromCodeString(bundleTypeValues[0]);
}
EncodingEnum encodingEnum = null;
if (responseEncoding != null) {
encodingEnum = responseEncoding.getEncoding();
}
bundleFactory.initializeBundleFromBundleProvider(theServer, resultList, encodingEnum, theRequest.getFhirServerBase(), linkSelf, prettyPrint, start, count, thePagingAction, bundleType, includes);
Bundle bundle = bundleFactory.getDstu1Bundle();
if (bundle != null) {
return bundle;
}
return bundleFactory.getResourceBundle();
// if (bundle != null) {
// for (int i = getInterceptors().size() - 1; i >= 0; i--) {
// IServerInterceptor next = getInterceptors().get(i);
// boolean continueProcessing = next.outgoingResponse(theRequest, bundle, theRequest.getServletRequest(),
// theRequest.getServletResponse());
// if (!continueProcessing) {
// ourLog.debug("Interceptor {} returned false, not continuing processing");
// return;
// }
// }
// theRequest.getResponse().streamResponseAsBundle(bundle, summaryMode, respondGzip, requestIsBrowser);
// } else {
// IBaseResource resBundle = bundleFactory.getResourceBundle();
// for (int i = getInterceptors().size() - 1; i >= 0; i--) {
// IServerInterceptor next = getInterceptors().get(i);
// boolean continueProcessing = next.outgoingResponse(theRequest, resBundle, theRequest.getServletRequest(),
// theRequest.getServletResponse());
// if (!continueProcessing) {
// ourLog.debug("Interceptor {} returned false, not continuing processing");
// return;
// }
// }
// theRequest.getResponse().streamResponseAsResource(resBundle, prettyPrint, summaryMode,
// Constants.STATUS_HTTP_200_OK, theRequest.isRespondGzip(), false);
// }
}
@Override @Override
public RestOperationTypeEnum getRestOperationType() { public RestOperationTypeEnum getRestOperationType() {
return RestOperationTypeEnum.GET_PAGE; return RestOperationTypeEnum.GET_PAGE;
} }
@Override @Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) { public ReturnTypeEnum getReturnType() {
String[] pageId = theRequest.getParameters().get(Constants.PARAM_PAGINGACTION); return ReturnTypeEnum.BUNDLE;
if (pageId == null || pageId.length == 0 || isBlank(pageId[0])) {
return false;
}
if (theRequest.getRequestType() != RequestTypeEnum.GET) {
return false;
}
return true;
} }
@CoverageIgnore @CoverageIgnore
@ -195,4 +38,8 @@ public class PageMethodBinding extends BaseResourceReturningMethodBinding {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public IBaseResource provider() {
return null;
}
} }

View File

@ -22,7 +22,12 @@ package ca.uhn.fhir.rest.client.method;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -35,6 +40,7 @@ import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -1,7 +1,5 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
import static org.apache.commons.lang3.StringUtils.defaultString;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -12,7 +10,7 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -30,42 +28,18 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.PatchTypeEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
class PatchTypeParameter implements IParameter { class PatchTypeParameter implements IParameter {
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException {
// nothing // nothing
} }
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
return getTypeForRequestOrThrowInvalidRequestException(theRequest);
}
@Override @Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore // ignore
} }
public static PatchTypeEnum getTypeForRequestOrThrowInvalidRequestException(RequestDetails theRequest) {
String contentTypeAll = defaultString(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE));
String contentType = contentTypeAll;
int semiColonIdx = contentType.indexOf(';');
if (semiColonIdx != -1) {
contentType = contentTypeAll.substring(0, semiColonIdx);
}
contentType = contentType.trim();
if (Constants.CT_JSON_PATCH.equals(contentType)) {
return PatchTypeEnum.JSON_PATCH;
} else if (Constants.CT_XML_PATCH.equals(contentType)) {
return PatchTypeEnum.XML_PATCH;
} else {
throw new InvalidRequestException("Invalid Content-Type for PATCH operation: " + contentTypeAll);
}
}
} }

View File

@ -26,6 +26,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterAnd; import ca.uhn.fhir.model.api.IQueryParameterAnd;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -26,6 +26,7 @@ import java.util.List;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -28,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IQueryParameterOr; import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -32,7 +32,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.annotation.RawParam; import ca.uhn.fhir.rest.annotation.RawParam;
import ca.uhn.fhir.rest.client.method.SearchMethodBinding.QualifierDetails; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.param.QualifierDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -1,7 +1,5 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
* #%L * #%L
* HAPI FHIR - Core Library * HAPI FHIR - Core Library
@ -12,7 +10,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
@ -25,29 +23,31 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.*; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.*; import org.hl7.fhir.instance.model.api.IBaseBinary;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.*; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.annotation.Elements;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.util.DateUtils;
public class ReadMethodBinding extends BaseResourceReturningMethodBinding implements IClientResponseHandlerHandlesBinary<Object> { public class ReadMethodBinding extends BaseResourceReturningMethodBinding implements IClientResponseHandlerHandlesBinary<Object> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReadMethodBinding.class);
private Integer myIdIndex; private Integer myIdIndex;
private boolean mySupportsVersion; private boolean mySupportsVersion;
private Integer myVersionIdIndex; private Integer myVersionIdIndex;
@ -69,7 +69,8 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
myVersionIdIndex = versionIdIndex; myVersionIdIndex = versionIdIndex;
if (myIdIndex == null) { if (myIdIndex == null) {
throw new ConfigurationException("@" + Read.class.getSimpleName() + " method " + theMethod.getName() + " on type \"" + theMethod.getDeclaringClass().getName() + "\" does not have a parameter annotated with @" + IdParam.class.getSimpleName()); throw new ConfigurationException("@" + Read.class.getSimpleName() + " method " + theMethod.getName() + " on type \"" + theMethod.getDeclaringClass().getName()
+ "\" does not have a parameter annotated with @" + IdParam.class.getSimpleName());
} }
myIdParameterType = (Class<? extends IIdType>) parameterTypes[myIdIndex]; myIdParameterType = (Class<? extends IIdType>) parameterTypes[myIdIndex];
@ -82,14 +83,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
} }
@Override
public RestOperationTypeEnum getRestOperationType(RequestDetails theRequestDetails) {
if (mySupportsVersion && theRequestDetails.getId().hasVersionIdPart()) {
return RestOperationTypeEnum.VREAD;
}
return RestOperationTypeEnum.READ;
}
@Override @Override
public List<Class<?>> getAllowableParamAnnotations() { public List<Class<?>> getAllowableParamAnnotations() {
ArrayList<Class<?>> retVal = new ArrayList<Class<?>>(); ArrayList<Class<?>> retVal = new ArrayList<Class<?>>();
@ -108,44 +101,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
return ReturnTypeEnum.RESOURCE; return ReturnTypeEnum.RESOURCE;
} }
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (!theRequest.getResourceName().equals(getResourceName())) {
return false;
}
for (String next : theRequest.getParameters().keySet()) {
if (!ALLOWED_PARAMS.contains(next)) {
return false;
}
}
if (theRequest.getId() == null) {
return false;
}
if (mySupportsVersion == false) {
if (theRequest.getId().hasVersionIdPart()) {
return false;
}
}
if (isNotBlank(theRequest.getCompartmentName())) {
return false;
}
if (theRequest.getRequestType() != RequestTypeEnum.GET) {
ourLog.trace("Method {} doesn't match because request type is not GET: {}", theRequest.getId(), theRequest.getRequestType());
return false;
}
if (Constants.PARAM_HISTORY.equals(theRequest.getOperation())) {
if (mySupportsVersion == false && myVersionIdIndex == null) {
return false;
}
if (theRequest.getId().hasVersionIdPart() == false) {
return false;
}
} else if (!StringUtils.isBlank(theRequest.getOperation())) {
return false;
}
return true;
}
@Override @Override
public HttpGetClientInvocation invokeClient(Object[] theArgs) { public HttpGetClientInvocation invokeClient(Object[] theArgs) {
HttpGetClientInvocation retVal; HttpGetClientInvocation retVal;
@ -173,7 +128,8 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
} }
@Override @Override
public Object invokeClient(String theResponseMimeType, InputStream theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws IOException, BaseServerResponseException { public Object invokeClient(String theResponseMimeType, InputStream theResponseReader, int theResponseStatusCode, Map<String, List<String>> theHeaders)
throws IOException, BaseServerResponseException {
byte[] contents = IOUtils.toByteArray(theResponseReader); byte[] contents = IOUtils.toByteArray(theResponseReader);
IBaseBinary resource = (IBaseBinary) getContext().getResourceDefinition("Binary").newInstance(); IBaseBinary resource = (IBaseBinary) getContext().getResourceDefinition("Binary").newInstance();
@ -187,8 +143,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
return Collections.singletonList(resource); return Collections.singletonList(resource);
case RESOURCE: case RESOURCE:
return resource; return resource;
case BUNDLE_PROVIDER:
return new SimpleBundleProvider(resource);
case BUNDLE_RESOURCE: case BUNDLE_RESOURCE:
case METHOD_OUTCOME: case METHOD_OUTCOME:
break; break;
@ -197,61 +151,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
throw new IllegalStateException("" + getMethodReturnType()); // should not happen throw new IllegalStateException("" + getMethodReturnType()); // should not happen
} }
@Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
theMethodParams[myIdIndex] = MethodUtil.convertIdToType(theRequest.getId(), myIdParameterType);
if (myVersionIdIndex != null) {
theMethodParams[myVersionIdIndex] = new IdDt(theRequest.getId().getVersionIdPart());
}
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
IBundleProvider retVal = toResourceList(response);
if (retVal.size() == 1) {
List<IBaseResource> responseResources = retVal.getResources(0, 1);
IBaseResource responseResource = responseResources.get(0);
// If-None-Match
if (theRequest.getServer().getETagSupport() == ETagSupportEnum.ENABLED) {
String ifNoneMatch = theRequest.getHeader(Constants.HEADER_IF_NONE_MATCH_LC);
if (StringUtils.isNotBlank(ifNoneMatch)) {
ifNoneMatch = MethodUtil.parseETagValue(ifNoneMatch);
if (responseResource.getIdElement() != null && responseResource.getIdElement().hasVersionIdPart()) {
if (responseResource.getIdElement().getVersionIdPart().equals(ifNoneMatch)) {
ourLog.debug("Returning HTTP 301 because request specified {}={}", Constants.HEADER_IF_NONE_MATCH, ifNoneMatch);
throw new NotModifiedException("Not Modified");
}
}
}
}
// If-Modified-Since
String ifModifiedSince = theRequest.getHeader(Constants.HEADER_IF_MODIFIED_SINCE_LC);
if (isNotBlank(ifModifiedSince)) {
Date ifModifiedSinceDate = DateUtils.parseDate(ifModifiedSince);
Date lastModified = null;
if (responseResource instanceof IResource) {
InstantDt lastModifiedDt = ResourceMetadataKeyEnum.UPDATED.get((IResource) responseResource);
if (lastModifiedDt != null) {
lastModified = lastModifiedDt.getValue();
}
} else {
lastModified = ((IAnyResource)responseResource).getMeta().getLastUpdated();
}
if (lastModified != null && lastModified.getTime() > ifModifiedSinceDate.getTime()) {
ourLog.debug("Returning HTTP 301 because If-Modified-Since does not match");
throw new NotModifiedException("Not Modified");
}
}
} // if we have at least 1 result
return retVal;
}
@Override @Override
public boolean isBinary() { public boolean isBinary() {
return "Binary".equals(getResourceName()); return "Binary".equals(getResourceName());

View File

@ -1,54 +0,0 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.CoverageIgnore;
class RequestOperationCallbackParameter implements IParameter {
// private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServletRequestParameter.class);
@CoverageIgnore
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
// nothing
}
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
return theRequest.getRequestOperationCallback();
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore
}
}

View File

@ -0,0 +1,40 @@
package ca.uhn.fhir.rest.client.method;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class ResourceParameter implements IParameter {
/**
* Constructor
*/
public ResourceParameter() {
super();
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore for now
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException {
// ignore, as this is handles as a special case
}
public enum Mode {
BODY,
BODY_BYTE_ARRAY,
ENCODING,
RESOURCE
}
}

View File

@ -23,14 +23,11 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -41,24 +38,19 @@ import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SearchStyleEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.param.BaseQueryParameter; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class SearchMethodBinding extends BaseResourceReturningMethodBinding { public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchMethodBinding.class);
private String myCompartmentName; private String myCompartmentName;
private String myDescription; private String myDescription;
private Integer myIdParamIndex; private Integer myIdParamIndex;
private String myQueryName; private String myQueryName;
private boolean myAllowUnknownParams;
public SearchMethodBinding(Class<? extends IBaseResource> theReturnResourceType, Method theMethod, FhirContext theContext, Object theProvider) { public SearchMethodBinding(Class<? extends IBaseResource> theReturnResourceType, Method theMethod, FhirContext theContext, Object theProvider) {
super(theReturnResourceType, theMethod, theContext, theProvider); super(theReturnResourceType, theMethod, theContext, theProvider);
@ -66,7 +58,6 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
this.myQueryName = StringUtils.defaultIfBlank(search.queryName(), null); this.myQueryName = StringUtils.defaultIfBlank(search.queryName(), null);
this.myCompartmentName = StringUtils.defaultIfBlank(search.compartmentName(), null); this.myCompartmentName = StringUtils.defaultIfBlank(search.compartmentName(), null);
this.myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext()); this.myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());
this.myAllowUnknownParams = search.allowUnknownParams();
Description desc = theMethod.getAnnotation(Description.class); Description desc = theMethod.getAnnotation(Description.class);
if (desc != null) { if (desc != null) {
@ -119,13 +110,13 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
} }
@Override @Override
public RestOperationTypeEnum getRestOperationType() { protected BundleTypeEnum getResponseBundleType() {
return RestOperationTypeEnum.SEARCH_TYPE; return BundleTypeEnum.SEARCHSET;
} }
@Override @Override
protected BundleTypeEnum getResponseBundleType() { public RestOperationTypeEnum getRestOperationType() {
return BundleTypeEnum.SEARCHSET; return RestOperationTypeEnum.SEARCH_TYPE;
} }
@Override @Override
@ -133,129 +124,6 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return ReturnTypeEnum.BUNDLE; return ReturnTypeEnum.BUNDLE;
} }
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
String clientPreference = theRequest.getHeader(Constants.HEADER_PREFER);
boolean lenientHandling = false;
if(clientPreference != null)
{
String[] preferences = clientPreference.split(";");
for( String p : preferences){
if("handling:lenient".equalsIgnoreCase(p))
{
lenientHandling = true;
break;
}
}
}
if (theRequest.getId() != null && myIdParamIndex == null) {
ourLog.trace("Method {} doesn't match because ID is not null: {}", theRequest.getId());
return false;
}
if (theRequest.getRequestType() == RequestTypeEnum.GET && theRequest.getOperation() != null && !Constants.PARAM_SEARCH.equals(theRequest.getOperation())) {
ourLog.trace("Method {} doesn't match because request type is GET but operation is not null: {}", theRequest.getId(), theRequest.getOperation());
return false;
}
if (theRequest.getRequestType() == RequestTypeEnum.POST && !Constants.PARAM_SEARCH.equals(theRequest.getOperation())) {
ourLog.trace("Method {} doesn't match because request type is POST but operation is not _search: {}", theRequest.getId(), theRequest.getOperation());
return false;
}
if (theRequest.getRequestType() != RequestTypeEnum.GET && theRequest.getRequestType() != RequestTypeEnum.POST) {
ourLog.trace("Method {} doesn't match because request type is {}", getMethod());
return false;
}
if (!StringUtils.equals(myCompartmentName, theRequest.getCompartmentName())) {
ourLog.trace("Method {} doesn't match because it is for compartment {} but request is compartment {}", new Object[] { getMethod(), myCompartmentName, theRequest.getCompartmentName() });
return false;
}
// This is used to track all the parameters so we can reject queries that
// have additional params we don't understand
Set<String> methodParamsTemp = new HashSet<String>();
Set<String> unqualifiedNames = theRequest.getUnqualifiedToQualifiedNames().keySet();
Set<String> qualifiedParamNames = theRequest.getParameters().keySet();
for (int i = 0; i < this.getParameters().size(); i++) {
if (!(getParameters().get(i) instanceof BaseQueryParameter)) {
continue;
}
BaseQueryParameter temp = (BaseQueryParameter) getParameters().get(i);
String name = temp.getName();
if (temp.isRequired()) {
if (qualifiedParamNames.contains(name)) {
QualifierDetails qualifiers = extractQualifiersFromParameterName(name);
if (qualifiers.passes(temp.getQualifierWhitelist(), temp.getQualifierBlacklist())) {
methodParamsTemp.add(name);
}
}
if (unqualifiedNames.contains(name)) {
List<String> qualifiedNames = theRequest.getUnqualifiedToQualifiedNames().get(name);
qualifiedNames = processWhitelistAndBlacklist(qualifiedNames, temp.getQualifierWhitelist(), temp.getQualifierBlacklist());
methodParamsTemp.addAll(qualifiedNames);
}
if (!qualifiedParamNames.contains(name) && !unqualifiedNames.contains(name))
{
ourLog.trace("Method {} doesn't match param '{}' is not present", getMethod().getName(), name);
return false;
}
} else {
if (qualifiedParamNames.contains(name)) {
QualifierDetails qualifiers = extractQualifiersFromParameterName(name);
if (qualifiers.passes(temp.getQualifierWhitelist(), temp.getQualifierBlacklist())) {
methodParamsTemp.add(name);
}
}
if (unqualifiedNames.contains(name)) {
List<String> qualifiedNames = theRequest.getUnqualifiedToQualifiedNames().get(name);
qualifiedNames = processWhitelistAndBlacklist(qualifiedNames, temp.getQualifierWhitelist(), temp.getQualifierBlacklist());
methodParamsTemp.addAll(qualifiedNames);
}
if (!qualifiedParamNames.contains(name)) {
methodParamsTemp.add(name);
}
}
}
if (myQueryName != null) {
String[] queryNameValues = theRequest.getParameters().get(Constants.PARAM_QUERY);
if (queryNameValues != null && StringUtils.isNotBlank(queryNameValues[0])) {
String queryName = queryNameValues[0];
if (!myQueryName.equals(queryName)) {
ourLog.trace("Query name does not match {}", myQueryName);
return false;
}
methodParamsTemp.add(Constants.PARAM_QUERY);
} else {
ourLog.trace("Query name does not match {}", myQueryName);
return false;
}
} else {
String[] queryNameValues = theRequest.getParameters().get(Constants.PARAM_QUERY);
if (queryNameValues != null && StringUtils.isNotBlank(queryNameValues[0])) {
ourLog.trace("Query has name");
return false;
}
}
for (String next : theRequest.getParameters().keySet()) {
if (ALLOWED_PARAMS.contains(next)) {
methodParamsTemp.add(next);
}
}
Set<String> keySet = theRequest.getParameters().keySet();
if(lenientHandling == true)
return true;
if (myAllowUnknownParams == false) {
for (String next : keySet) {
if (!methodParamsTemp.contains(next)) {
return false;
}
}
}
return true;
}
@Override @Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
@ -282,43 +150,23 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return retVal; return retVal;
} }
@Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
if (myIdParamIndex != null) {
theMethodParams[myIdParamIndex] = theRequest.getId();
}
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
return toResourceList(response);
}
@Override @Override
protected boolean isAddContentLocationHeader() { protected boolean isAddContentLocationHeader() {
return false; return false;
} }
private List<String> processWhitelistAndBlacklist(List<String> theQualifiedNames, Set<String> theQualifierWhitelist, Set<String> theQualifierBlacklist) {
if (theQualifierWhitelist == null && theQualifierBlacklist == null) {
return theQualifiedNames;
}
ArrayList<String> retVal = new ArrayList<String>(theQualifiedNames.size());
for (String next : theQualifiedNames) {
QualifierDetails qualifiers = extractQualifiersFromParameterName(next);
if (!qualifiers.passes(theQualifierWhitelist, theQualifierBlacklist)) {
continue;
}
retVal.add(next);
}
return retVal;
}
@Override @Override
public String toString() { public String toString() {
return getMethod().toString(); return getMethod().toString();
} }
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theSearchUrl, Map<String, List<String>> theParams) {
return new HttpGetClientInvocation(theContext, theParams, theSearchUrl);
}
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map<String, List<String>> theParameters, IdDt theId, String theCompartmentName, public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theResourceName, Map<String, List<String>> theParameters, IdDt theId, String theCompartmentName,
SearchStyleEnum theSearchStyle) { SearchStyleEnum theSearchStyle) {
SearchStyleEnum searchStyle = theSearchStyle; SearchStyleEnum searchStyle = theSearchStyle;
@ -379,9 +227,4 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
return invocation; return invocation;
} }
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theSearchUrl, Map<String, List<String>> theParams) {
return new HttpGetClientInvocation(theContext, theParams, theSearchUrl);
}
} }

View File

@ -45,6 +45,8 @@ import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
import ca.uhn.fhir.model.base.composite.BaseQuantityDt; import ca.uhn.fhir.model.base.composite.BaseQuantityDt;
import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.OptionalParam;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.QualifiedParamList;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.BaseQueryParameter; import ca.uhn.fhir.rest.param.BaseQueryParameter;
import ca.uhn.fhir.rest.param.CompositeAndListParam; import ca.uhn.fhir.rest.param.CompositeAndListParam;
@ -75,7 +77,6 @@ import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriAndListParam; import ca.uhn.fhir.rest.param.UriAndListParam;
import ca.uhn.fhir.rest.param.UriOrListParam; import ca.uhn.fhir.rest.param.UriOrListParam;
import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.CollectionUtil; import ca.uhn.fhir.util.CollectionUtil;

View File

@ -28,6 +28,7 @@ import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;

View File

@ -1,60 +0,0 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
class ServletRequestParameter implements IParameter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServletRequestParameter.class);
ServletRequestParameter() {
super();
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
/*
* Does nothing, since we just ignore HttpServletRequest arguments
*/
ourLog.trace("Ignoring HttpServletRequest argument: {}", theSourceClientArgument);
}
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
return ((ServletRequestDetails) theRequest).getServletRequest();
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore
}
}

View File

@ -1,57 +0,0 @@
package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
class ServletResponseParameter implements IParameter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServletResponseParameter.class);
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
/*
* Does nothing, since we just ignore HttpServletResponse arguments
*/
ourLog.trace("Ignoring HttpServletResponse argument: {}", theSourceClientArgument);
}
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
return ((ServletRequestDetails) theRequest).getServletResponse();
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore
}
}

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.rest.client.method;
*/ */
import ca.uhn.fhir.rest.annotation.Since; import ca.uhn.fhir.rest.annotation.Since;
import ca.uhn.fhir.rest.server.Constants;
class SinceParameter extends SinceOrAtParameter { class SinceParameter extends SinceOrAtParameter {

View File

@ -26,7 +26,6 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -34,12 +33,11 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.annotation.Sort; import ca.uhn.fhir.rest.annotation.Sort;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SortOrderEnum; import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.ParameterUtil; import ca.uhn.fhir.rest.param.ParameterUtil;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class SortParameter implements IParameter { public class SortParameter implements IParameter {
@ -97,81 +95,6 @@ public class SortParameter implements IParameter {
} }
} }
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
if (!theRequest.getParameters().containsKey(Constants.PARAM_SORT)) {
if (!theRequest.getParameters().containsKey(Constants.PARAM_SORT_ASC)) {
if (!theRequest.getParameters().containsKey(Constants.PARAM_SORT_DESC)) {
return null;
}
}
}
SortSpec outerSpec = null;
SortSpec innerSpec = null;
for (String nextParamName : theRequest.getParameters().keySet()) {
SortOrderEnum order;
if (Constants.PARAM_SORT.equals(nextParamName)) {
order = null;
} else if (Constants.PARAM_SORT_ASC.equals(nextParamName)) {
order = SortOrderEnum.ASC;
} else if (Constants.PARAM_SORT_DESC.equals(nextParamName)) {
order = SortOrderEnum.DESC;
} else {
continue;
}
String[] values = theRequest.getParameters().get(nextParamName);
if (values != null) {
for (String nextValue : values) {
if (myContext.getVersion().getVersion().isNewerThan(FhirVersionEnum.DSTU2) && order == null) {
StringTokenizer tok = new StringTokenizer(nextValue, ",");
while (tok.hasMoreTokens()) {
String next = tok.nextToken();
if (isNotBlank(next) && !next.equals("-")) {
order = SortOrderEnum.ASC;
if (next.startsWith("-")) {
order = SortOrderEnum.DESC;
next = next.substring(1);
}
SortSpec spec = new SortSpec();
spec.setOrder(order);
spec.setParamName(next);
if (innerSpec == null) {
outerSpec = spec;
innerSpec = spec;
} else {
innerSpec.setChain(spec);
innerSpec = spec;
}
}
}
} else {
if (isNotBlank(nextValue)) {
SortSpec spec = new SortSpec();
spec.setOrder(order);
spec.setParamName(nextValue);
if (innerSpec == null) {
outerSpec = spec;
innerSpec = spec;
} else {
innerSpec.setChain(spec);
innerSpec = spec;
}
}
}
}
}
}
return outerSpec;
}
public static String createSortStringDstu3(SortSpec ss) { public static String createSortStringDstu3(SortSpec ss) {
StringBuilder val = new StringBuilder(); StringBuilder val = new StringBuilder();

View File

@ -1,53 +1,26 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SummaryEnum; import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.param.CollectionBinder;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class SummaryEnumParameter implements IParameter { public class SummaryEnumParameter implements IParameter {
@SuppressWarnings("rawtypes")
private Class<? extends Collection> myInnerCollectionType;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException { public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException {
if (theSourceClientArgument instanceof Collection) { if (theSourceClientArgument instanceof Collection) {
List<String> values = new ArrayList<String>(); List<String> values = new ArrayList<String>();
for (SummaryEnum next : (Collection<SummaryEnum>) theSourceClientArgument) { for (SummaryEnum next : (Collection<SummaryEnum>) theSourceClientArgument) {
@ -64,81 +37,11 @@ public class SummaryEnumParameter implements IParameter {
} }
} }
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
Set<SummaryEnum> value = getSummaryValueOrNull(theRequest);
if (value == null || value.isEmpty()) {
return null;
}
if (myInnerCollectionType == null) {
return value.iterator().next();
}
try {
Collection retVal = myInnerCollectionType.newInstance();
retVal.addAll(value);
return retVal;
} catch (InstantiationException e) {
throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
} catch (IllegalAccessException e) {
throw new InternalErrorException("Failed to instantiate " + myInnerCollectionType, e);
}
}
public static Set<SummaryEnum> getSummaryValueOrNull(RequestDetails theRequest) {
String[] summary = theRequest.getParameters().get(Constants.PARAM_SUMMARY);
Set<SummaryEnum> retVal;
if (summary == null || summary.length == 0) {
retVal = null;
} else if (isBlank(summary[0])) {
retVal = null;
} else if (summary.length == 1) {
retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0]));
if (retVal == null) {
retVal = toCollectionOrNull(SummaryEnum.fromCode(summary[0].toLowerCase()));
}
} else {
retVal = new HashSet<SummaryEnum>();
for (String next : summary) {
SummaryEnum value = SummaryEnum.fromCode(next);
if (value == null) {
value = SummaryEnum.fromCode(next.toLowerCase());
}
if (value != null) {
retVal.add(value);
}
}
}
if (retVal != null) {
if (retVal.contains(SummaryEnum.TEXT)) {
if (retVal.size() > 1) {
String msg = theRequest.getServer().getFhirContext().getLocalizer().getMessage(SummaryEnumParameter.class, "cantCombineText");
throw new InvalidRequestException(msg);
}
}
}
return retVal;
}
private static Set<SummaryEnum> toCollectionOrNull(SummaryEnum theFromCode) {
if (theFromCode == null) {
return null;
}
return Collections.singleton(theFromCode);
}
@Override @Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) { public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null) { if (theOuterCollectionType != null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class + " but can not be a collection of collections"); throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
} + " but can not be a collection of collections");
if (theInnerCollectionType != null) {
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
} }
} }

View File

@ -1,28 +1,6 @@
package ca.uhn.fhir.rest.client.method; package ca.uhn.fhir.rest.client.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseBundle;
@ -31,29 +9,16 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.Transaction; import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam; import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.IRestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.method.ResourceParameter;
import ca.uhn.fhir.rest.server.method.TransactionParameter;
import ca.uhn.fhir.rest.server.method.TransactionParameter.ParamStyle;
public class TransactionMethodBinding extends BaseResourceReturningMethodBinding { public class TransactionMethodBinding extends BaseResourceReturningMethodBinding {
private int myTransactionParamIndex; private int myTransactionParamIndex;
private ParamStyle myTransactionParamStyle;
public TransactionMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) { public TransactionMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
super(null, theMethod, theContext, theProvider); super(null, theMethod, theContext, theProvider);
@ -67,7 +32,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
+ " methods"); + " methods");
} }
myTransactionParamIndex = index; myTransactionParamIndex = index;
myTransactionParamStyle = ((TransactionParameter) next).getParamStyle();
} }
index++; index++;
} }
@ -92,19 +56,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
return ReturnTypeEnum.BUNDLE; return ReturnTypeEnum.BUNDLE;
} }
@Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (theRequest.getRequestType() != RequestTypeEnum.POST) {
return false;
}
if (isNotBlank(theRequest.getOperation())) {
return false;
}
if (isNotBlank(theRequest.getResourceName())) {
return false;
}
return true;
}
@Override @Override
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException { public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
@ -118,81 +69,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
return createTransactionInvocation(resources, context); return createTransactionInvocation(resources, context);
} }
@SuppressWarnings("unchecked")
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws InvalidRequestException, InternalErrorException {
/*
* The design of HAPI's transaction method for DSTU1 support assumed that a transaction was just an update on a
* bunch of resources (because that's what it was), but in DSTU2 transaction has become much more broad, so we
* no longer hold the user's hand much here.
*/
if (myTransactionParamStyle == ParamStyle.RESOURCE_BUNDLE) {
// This is the DSTU2 style
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
return response;
}
// Grab the IDs of all of the resources in the transaction
List<IResource> resources;
if (theMethodParams[myTransactionParamIndex] instanceof Bundle) {
resources = ((Bundle) theMethodParams[myTransactionParamIndex]).toListOfResources();
} else {
resources = (List<IResource>) theMethodParams[myTransactionParamIndex];
}
IdentityHashMap<IResource, IdDt> oldIds = new IdentityHashMap<IResource, IdDt>();
for (IResource next : resources) {
oldIds.put(next, next.getId());
}
// Call the server implementation method
Object response = invokeServerMethod(theServer, theRequest, theMethodParams);
IBundleProvider retVal = toResourceList(response);
/*
* int offset = 0; if (retVal.size() != resources.size()) { if (retVal.size() > 0 && retVal.getResources(0,
* 1).get(0) instanceof OperationOutcome) { offset = 1; } else { throw new
* InternalErrorException("Transaction bundle contained " + resources.size() +
* " entries, but server method response contained " + retVal.size() + " entries (must be the same)"); } }
*/
List<IBaseResource> retResources = retVal.getResources(0, retVal.size());
for (int i = 0; i < retResources.size(); i++) {
IdDt oldId = oldIds.get(retResources.get(i));
IBaseResource newRes = retResources.get(i);
if (newRes.getIdElement() == null || newRes.getIdElement().isEmpty()) {
if (!(newRes instanceof BaseOperationOutcome)) {
throw new InternalErrorException("Transaction method returned resource at index " + i + " with no id specified - IResource#setId(IdDt)");
}
}
if (oldId != null && !oldId.isEmpty()) {
if (!oldId.equals(newRes.getIdElement()) && newRes instanceof IResource) {
((IResource)newRes).getResourceMetadata().put(ResourceMetadataKeyEnum.PREVIOUS_ID, oldId);
}
}
}
return retVal;
}
@Override
protected void populateActionRequestDetailsForInterceptor(RequestDetails theRequestDetails, ActionRequestDetails theDetails, Object[] theMethodParams) {
super.populateActionRequestDetailsForInterceptor(theRequestDetails, theDetails, theMethodParams);
/*
* If the method has no parsed resource parameter, we parse here in order to have something for the interceptor.
*/
if (myTransactionParamIndex != -1) {
theDetails.setResource((IBaseResource) theMethodParams[myTransactionParamIndex]);
} else {
Class<? extends IBaseResource> resourceType = getContext().getResourceDefinition("Bundle").getImplementingClass();
theDetails.setResource(ResourceParameter.parseResourceFromRequest(theRequestDetails, this, resourceType));
}
}
public static BaseHttpClientInvocation createTransactionInvocation(Bundle theBundle, FhirContext theContext) { public static BaseHttpClientInvocation createTransactionInvocation(Bundle theBundle, FhirContext theContext) {
return new HttpPostClientInvocation(theContext, theBundle); return new HttpPostClientInvocation(theContext, theBundle);

View File

@ -0,0 +1,85 @@
package ca.uhn.fhir.rest.client.method;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
public class TransactionParameter implements IParameter {
// private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionParameter.class);
private FhirContext myContext;
private ParamStyle myParamStyle;
public TransactionParameter(FhirContext theContext) {
myContext = theContext;
}
private String createParameterTypeError(Method theMethod) {
return "Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @" + TransactionParam.class.getName()
+ " but is not of type List<" + IResource.class.getCanonicalName() + "> or Bundle";
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
if (theOuterCollectionType != null) {
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is annotated with @"
+ TransactionParam.class.getName() + " but can not be a collection of collections");
}
if (theParameterType.equals(Bundle.class)) {
myParamStyle = ParamStyle.DSTU1_BUNDLE;
if (theInnerCollectionType != null) {
throw new ConfigurationException(createParameterTypeError(theMethod));
}
} else if (Modifier.isInterface(theParameterType.getModifiers()) == false && IBaseResource.class.isAssignableFrom(theParameterType)) {
@SuppressWarnings("unchecked")
Class<? extends IBaseResource> parameterType = (Class<? extends IBaseResource>) theParameterType;
RuntimeResourceDefinition def = myContext.getResourceDefinition(parameterType);
if ("Bundle".equals(def.getName())) {
myParamStyle = ParamStyle.RESOURCE_BUNDLE;
} else {
throw new ConfigurationException(createParameterTypeError(theMethod));
}
} else {
if (theInnerCollectionType.equals(List.class) == false) {
throw new ConfigurationException(createParameterTypeError(theMethod));
}
if (theParameterType.equals(IResource.class) == false) {
throw new ConfigurationException(createParameterTypeError(theMethod));
}
myParamStyle = ParamStyle.RESOURCE_LIST;
}
}
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource)
throws InternalErrorException {
// nothing
}
public ParamStyle getParamStyle() {
return myParamStyle;
}
public enum ParamStyle {
/** Old style bundle (defined in hapi-fhir-base) */
DSTU1_BUNDLE,
/** New style bundle (defined in hapi-fhir-structures-* as a resource definition itself */
RESOURCE_BUNDLE,
/** List of resources */
RESOURCE_LIST
}
}

View File

@ -37,7 +37,7 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam { public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {

View File

@ -33,7 +33,7 @@ import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.RequestTypeEnum; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.param.IParameter;
public class ValidateMethodBindingDstu1 extends BaseOutcomeReturningMethodBindingWithResourceParam { public class ValidateMethodBindingDstu1 extends BaseOutcomeReturningMethodBindingWithResourceParam {

View File

@ -31,9 +31,9 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.valueset.BundleTypeEnum; import ca.uhn.fhir.model.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Validate; import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.server.Constants; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.method.ResourceParameter; import ca.uhn.fhir.rest.server.method.ResourceParameter;
import ca.uhn.fhir.util.ParametersUtil; import ca.uhn.fhir.util.ParametersUtil;

View File

@ -2,7 +2,6 @@ package ca.uhn.fhir.rest.api.server;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IFhirVersion; import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.server.IServerConformanceProvider;
@ -17,6 +16,4 @@ public interface IFhirVersionServer {
IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer); IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer);
IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext);
} }

View File

@ -1,26 +1,5 @@
package ca.uhn.fhir.rest.server.method; package ca.uhn.fhir.rest.server.method;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.IOException;
import java.io.Reader; import java.io.Reader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
@ -33,17 +12,18 @@ import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.TagListParam; import ca.uhn.fhir.rest.annotation.TagListParam;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IRestfulServer; import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation; import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
import ca.uhn.fhir.rest.client.method.RequestDetails;
import ca.uhn.fhir.rest.param.IParameter; import ca.uhn.fhir.rest.param.IParameter;
import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.*; import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> { abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> {
@ -147,37 +127,6 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
return retVal; return retVal;
} }
@Override
public Object invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest) throws BaseServerResponseException, IOException {
Object[] params = createParametersForServerRequest(theRequest);
params[myIdParamIndex] = theRequest.getId();
if (myVersionIdParamIndex != null) {
params[myVersionIdParamIndex] = theRequest.getId();
}
IParser parser = createAppropriateParserForParsingServerRequest(theRequest);
Reader reader = theRequest.getReader();
try {
TagList tagList = parser.parseTagList(reader);
params[myTagListParamIndex] = tagList;
} finally {
reader.close();
}
invokeServerMethod(theServer, theRequest, params);
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = theServer.getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest);
if (!continueProcessing) {
return null;
}
}
return theRequest.getResponse().returnResponse(null, Constants.STATUS_HTTP_200_OK, false, null, null);
}
@Override @Override
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) { public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
if (theRequest.getRequestType() != RequestTypeEnum.POST) { if (theRequest.getRequestType() != RequestTypeEnum.POST) {

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.rest.param; package ca.uhn.fhir.rest.server.method;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.rest.param; package ca.uhn.fhir.rest.server.method;
/* /*
* #%L * #%L