Continue work on refactor
This commit is contained in:
parent
fbe2f98a02
commit
ea1264cd8e
|
@ -37,6 +37,7 @@ import ca.uhn.fhir.model.api.*;
|
|||
import ca.uhn.fhir.model.view.ViewGenerator;
|
||||
import ca.uhn.fhir.narrative.INarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.*;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.util.*;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
|
@ -460,6 +461,10 @@ public class FhirContext {
|
|||
return !myDefaultTypeForProfile.isEmpty();
|
||||
}
|
||||
|
||||
public IVersionSpecificBundleFactory newBundleFactory() {
|
||||
return myVersion.newBundleFactory(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FluentPath engine which can be used to exvaluate
|
||||
* path expressions over FHIR resources. Note that this engine will use the
|
||||
|
@ -818,7 +823,7 @@ public class FhirContext {
|
|||
public void setValidationSupport(IContextValidationSupport<?, ?, ?, ?, ?, ?> theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({ "cast" })
|
||||
private List<Class<? extends IElement>> toElementList(Collection<Class<? extends IBaseResource>> theResourceTypes) {
|
||||
if (theResourceTypes == null) {
|
||||
|
@ -830,7 +835,7 @@ public class FhirContext {
|
|||
}
|
||||
return resTypes;
|
||||
}
|
||||
|
||||
|
||||
private void validateInitialized() {
|
||||
// See #610
|
||||
if (!myInitialized) {
|
||||
|
|
|
@ -10,7 +10,7 @@ package ca.uhn.fhir.model.api;
|
|||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -33,6 +33,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
|
||||
/**
|
||||
* Each structure version JAR will have an implementation of this interface.
|
||||
|
@ -44,7 +45,7 @@ import ca.uhn.fhir.fluentpath.IFluentPath;
|
|||
public interface IFhirVersion {
|
||||
|
||||
IFluentPath createFluentPathExecutor(FhirContext theFhirContext);
|
||||
|
||||
|
||||
IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport();
|
||||
|
||||
IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase);
|
||||
|
@ -61,6 +62,8 @@ public interface IFhirVersion {
|
|||
|
||||
FhirVersionEnum getVersion();
|
||||
|
||||
IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext);
|
||||
|
||||
IBase newCodingDt();
|
||||
|
||||
IIdType newIdType();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.rest.api.server;
|
||||
package ca.uhn.fhir.rest.api;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -19,7 +19,9 @@ package ca.uhn.fhir.rest.api.server;
|
|||
* limitations under the License.
|
||||
* #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.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.Include;
|
||||
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!
|
||||
|
@ -39,8 +40,8 @@ public interface IVersionSpecificBundleFactory {
|
|||
|
||||
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,
|
||||
int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
|
||||
// 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);
|
||||
|
||||
Bundle getDstu1Bundle();
|
||||
|
|
@ -21,20 +21,29 @@ package ca.uhn.fhir.rest.client.apache;
|
|||
*/
|
||||
|
||||
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 org.apache.http.HttpEntity;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.HttpClient;
|
||||
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.message.BasicNameValuePair;
|
||||
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
/**
|
||||
|
|
|
@ -28,7 +28,6 @@ import java.io.Reader;
|
|||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -41,7 +40,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
|||
import org.apache.http.entity.ContentType;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,7 +31,10 @@ import org.apache.http.auth.UsernamePasswordCredentials;
|
|||
import org.apache.http.client.CredentialsProvider;
|
||||
import org.apache.http.client.HttpClient;
|
||||
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 ca.uhn.fhir.context.FhirContext;
|
||||
|
|
|
@ -26,10 +26,13 @@ import java.util.Map;
|
|||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
|
||||
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.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.server.*;
|
||||
|
||||
public abstract class BaseHttpClient implements IHttpClient {
|
||||
|
||||
|
|
|
@ -29,8 +29,9 @@ import org.apache.http.HttpEntityEnclosingRequest;
|
|||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.ByteArrayEntity;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
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
|
||||
|
|
|
@ -22,25 +22,51 @@ package ca.uhn.fhir.rest.client.impl;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.io.IOException;
|
||||
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.lang3.StringUtils;
|
||||
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.IParser;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.client.*;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.client.exceptions.*;
|
||||
import ca.uhn.fhir.rest.method.HttpGetClientInvocation;
|
||||
import ca.uhn.fhir.rest.method.IClientResponseHandler;
|
||||
import ca.uhn.fhir.rest.method.IClientResponseHandlerHandlesBinary;
|
||||
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
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.util.OperationOutcomeUtil;
|
||||
import ca.uhn.fhir.util.XmlUtil;
|
||||
|
|
|
@ -28,9 +28,12 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
|
||||
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.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.Header;
|
||||
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 {
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import java.util.Map;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
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 {
|
||||
|
||||
|
|
|
@ -28,10 +28,12 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
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.client.api.*;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.client.method.BaseMethodBinding;
|
||||
|
||||
public class ClientInvocationHandlerFactory {
|
||||
|
||||
|
|
|
@ -71,15 +71,35 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
|||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
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.PatchTypeEnum;
|
||||
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.SortSpec;
|
||||
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.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.ICreate;
|
||||
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.IValidate;
|
||||
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.DateRangeParam;
|
||||
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.InvalidRequestException;
|
||||
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());
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
final String resourceName = def.getName();
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler();
|
||||
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
|
||||
return resp;
|
||||
|
||||
|
@ -239,8 +237,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
final String resourceName = myContext.getResourceDefinition(theType).getName();
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler();
|
||||
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
|
||||
return resp;
|
||||
}
|
||||
|
@ -555,10 +552,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
final String resourceName = def.getName();
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler();
|
||||
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
|
||||
return resp;
|
||||
}
|
||||
|
@ -586,10 +580,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
myLastRequest = invocation.asHttpRequest(getServerBase(), createExtraParams(), getEncoding(), isPrettyPrint());
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
|
||||
final String resourceName = def.getName();
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName);
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler();
|
||||
MethodOutcome resp = invokeClient(myContext, binding, invocation, myLogRequestAndResponse);
|
||||
return resp;
|
||||
}
|
||||
|
@ -742,7 +733,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
}
|
||||
|
||||
protected IBaseResource parseResourceBody(String theResourceBody) {
|
||||
EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(theResourceBody);
|
||||
EncodingEnum encoding = EncodingEnum.detectEncodingNoDefault(theResourceBody);
|
||||
if (encoding == null) {
|
||||
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
|
||||
}
|
||||
|
@ -853,9 +844,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
addPreferHeader(myPrefer, invocation);
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
|
||||
final String resourceName = def.getName();
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName, myPrefer);
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(myPrefer);
|
||||
|
||||
Map<String, List<String>> params = new HashMap<String, List<String>>();
|
||||
return invoke(params, binding, invocation);
|
||||
|
@ -1765,14 +1754,13 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
private final class OutcomeResponseHandler implements IClientResponseHandler<MethodOutcome> {
|
||||
private PreferReturnEnum myPrefer;
|
||||
// private final String myResourceName;
|
||||
|
||||
private OutcomeResponseHandler(String theResourceName) {
|
||||
// myResourceName = theResourceName;
|
||||
private OutcomeResponseHandler() {
|
||||
super();
|
||||
}
|
||||
|
||||
private OutcomeResponseHandler(String theResourceName, PreferReturnEnum thePrefer) {
|
||||
this(theResourceName);
|
||||
private OutcomeResponseHandler(PreferReturnEnum thePrefer) {
|
||||
this();
|
||||
myPrefer = thePrefer;
|
||||
}
|
||||
|
||||
|
@ -2357,7 +2345,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
public TransactionExecutable(String theBundle) {
|
||||
myRawBundle = theBundle;
|
||||
myRawBundleEncoding = MethodUtil.detectEncodingNoDefault(myRawBundle);
|
||||
myRawBundleEncoding = EncodingEnum.detectEncodingNoDefault(myRawBundle);
|
||||
if (myRawBundleEncoding == null) {
|
||||
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 (getParamEncoding() != null) {
|
||||
if (MethodUtil.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) {
|
||||
if (EncodingEnum.detectEncodingNoDefault(myRawBundle) != getParamEncoding()) {
|
||||
IBaseResource parsed = parseResourceBody(myRawBundle);
|
||||
myRawBundle = getParamEncoding().newParser(getFhirContext()).encodeResourceToString(parsed);
|
||||
}
|
||||
|
@ -2480,7 +2468,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
addPreferHeader(myPrefer, invocation);
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(null, myPrefer);
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(myPrefer);
|
||||
|
||||
Map<String, List<String>> params = new HashMap<String, List<String>>();
|
||||
return invoke(params, binding, invocation);
|
||||
|
@ -2529,7 +2517,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
|
||||
myPatchBody = thePatchBody;
|
||||
|
||||
EncodingEnum encoding = MethodUtil.detectEncodingNoDefault(thePatchBody);
|
||||
EncodingEnum encoding = EncodingEnum.detectEncodingNoDefault(thePatchBody);
|
||||
if (encoding == EncodingEnum.XML) {
|
||||
myPatchType = PatchTypeEnum.XML_PATCH;
|
||||
} else if (encoding == EncodingEnum.JSON) {
|
||||
|
@ -2607,9 +2595,7 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
addPreferHeader(myPrefer, invocation);
|
||||
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(myResource);
|
||||
final String resourceName = def.getName();
|
||||
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(resourceName, myPrefer);
|
||||
OutcomeResponseHandler binding = new OutcomeResponseHandler(myPrefer);
|
||||
|
||||
Map<String, List<String>> params = new HashMap<String, List<String>>();
|
||||
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");
|
||||
myResource = parseResourceBody(theResourceRaw);
|
||||
|
||||
EncodingEnum enc = MethodUtil.detectEncodingNoDefault(theResourceRaw);
|
||||
EncodingEnum enc = EncodingEnum.detectEncodingNoDefault(theResourceRaw);
|
||||
if (enc == null) {
|
||||
throw new IllegalArgumentException(myContext.getLocalizer().getMessage(GenericClient.class, "cantDetermineRequestType"));
|
||||
}
|
||||
|
|
|
@ -12,7 +12,9 @@ import org.apache.http.client.protocol.HttpClientContext;
|
|||
import org.apache.http.impl.auth.BasicScheme;
|
||||
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
|
||||
|
|
|
@ -23,42 +23,31 @@ package ca.uhn.fhir.rest.client.impl;
|
|||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.client.*;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientInappropriateForServerException;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpClient;
|
||||
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.method.BaseMethodBinding;
|
||||
|
||||
/**
|
||||
* Base class for a REST client factory implementation
|
||||
*/
|
||||
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 myConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
|
||||
private FhirContext myContext;
|
||||
private Map<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory> myInvocationHandlers = new HashMap<Class<? extends IRestfulClient>, ClientInvocationHandlerFactory>();
|
||||
private ServerValidationModeEnum myServerValidationMode = DEFAULT_SERVER_VALIDATION_MODE;
|
||||
private int mySocketTimeout = DEFAULT_SOCKET_TIMEOUT;
|
||||
private Set<String> myValidatedServerBaseUrls = Collections.synchronizedSet(new HashSet<String>());
|
||||
private String myProxyUsername;
|
||||
private String myProxyPassword;
|
||||
private int myPoolMaxTotal = DEFAULT_POOL_MAX;
|
||||
|
@ -192,21 +181,6 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
|||
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) {
|
||||
String serverBase = theServerBase;
|
||||
|
@ -270,84 +244,6 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
|||
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
|
||||
@Override
|
||||
|
|
|
@ -26,8 +26,9 @@ import java.io.UnsupportedEncodingException;
|
|||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -22,8 +22,9 @@ package ca.uhn.fhir.rest.client.interceptor;
|
|||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
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.util.CoverageIgnore;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.http.HttpEntity;
|
||||
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
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
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 Cookie to requests.
|
||||
|
|
|
@ -30,7 +30,9 @@ import org.apache.commons.io.IOUtils;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
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;
|
||||
|
||||
public class LoggingInterceptor implements IClientInterceptor {
|
||||
|
|
|
@ -23,14 +23,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
|
||||
/**
|
||||
* This interceptor adds an arbitrary header to requests made by this client. Both the
|
||||
|
|
|
@ -22,7 +22,9 @@ package ca.uhn.fhir.rest.client.interceptor;
|
|||
|
||||
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
|
||||
|
|
|
@ -21,7 +21,7 @@ package ca.uhn.fhir.rest.client.method;
|
|||
*/
|
||||
|
||||
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 {
|
||||
|
||||
|
|
|
@ -1,26 +1,5 @@
|
|||
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.lang.reflect.Method;
|
||||
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.model.api.TagList;
|
||||
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.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.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
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) {
|
||||
super(theMethod, theContext, theProvider);
|
||||
|
||||
if (theProvider instanceof IResourceProvider) {
|
||||
myType = ((IResourceProvider) theProvider).getResourceType();
|
||||
} else {
|
||||
myType = theTypeFromMethodAnnotation;
|
||||
}
|
||||
myType = theTypeFromMethodAnnotation;
|
||||
|
||||
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");
|
||||
|
@ -145,65 +120,6 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,12 +38,12 @@ import ca.uhn.fhir.model.api.TagList;
|
|||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
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.server.IVersionSpecificBundleFactory;
|
||||
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.server.EncodingEnum;
|
||||
|
||||
/**
|
||||
* @author James Agnew
|
||||
|
@ -194,7 +194,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
|||
|
||||
EncodingEnum encoding = theEncoding;
|
||||
if (myContents != null) {
|
||||
encoding = MethodUtil.detectEncoding(myContents);
|
||||
encoding = EncodingEnum.detectEncoding(myContents);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.List;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
|
|
@ -1,34 +1,9 @@
|
|||
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.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
@ -42,22 +17,31 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
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.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.BundleProviders;
|
||||
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.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
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.UnclassifiedServerFailureException;
|
||||
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;
|
||||
|
||||
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());
|
||||
|
||||
|
||||
parser.setPreferTypes(thePreferTypes);
|
||||
|
||||
|
||||
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() {
|
||||
return null;
|
||||
}
|
||||
|
@ -181,43 +129,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
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
|
||||
*/
|
||||
|
@ -225,47 +136,8 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
|
||||
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 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.
|
||||
*/
|
||||
|
@ -280,21 +152,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
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) {
|
||||
BaseServerResponseException ex;
|
||||
switch (theStatusCode) {
|
||||
|
@ -333,30 +190,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
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")
|
||||
public static BaseMethodBinding<?> bindMethod(Method theMethod, FhirContext theContext, Object theProvider) {
|
||||
Read read = theMethod.getAnnotation(Read.class);
|
||||
|
@ -376,24 +209,18 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
Patch patch = theMethod.getAnnotation(Patch.class);
|
||||
|
||||
// ** 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;
|
||||
}
|
||||
|
||||
if (getPage != null) {
|
||||
return new PageMethodBinding(theContext, theMethod);
|
||||
}
|
||||
|
||||
|
||||
Class<? extends IBaseResource> returnType;
|
||||
|
||||
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();
|
||||
if (getTags != null) {
|
||||
|
@ -403,8 +230,6 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
}
|
||||
} else if (MethodOutcome.class.isAssignableFrom(returnTypeFromMethod)) {
|
||||
// returns a method outcome
|
||||
} else if (IBundleProvider.class.equals(returnTypeFromMethod)) {
|
||||
// returns a bundle provider
|
||||
} else if (Bundle.class.equals(returnTypeFromMethod)) {
|
||||
// returns a bundle
|
||||
} else if (void.class.equals(returnTypeFromMethod)) {
|
||||
|
@ -414,14 +239,14 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
if (returnTypeFromMethod == null) {
|
||||
ourLog.trace("Method {} returns a non-typed list, can't verify return type", theMethod);
|
||||
} 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)
|
||||
+ " - Must return a resource type or a collection (List, Set) with a resource type parameter (e.g. List<Patient> or List<IBaseResource> )");
|
||||
}
|
||||
} else {
|
||||
if (!isResourceInterface(returnTypeFromMethod) && !verifyIsValidResourceReturnType(returnTypeFromMethod)) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' from " + IResourceProvider.class.getSimpleName() + " type " + theMethod.getDeclaringClass().getCanonicalName()
|
||||
+ " returns " + toLogString(returnTypeFromMethod) + " - Must return a resource type (eg Patient, " + Bundle.class.getSimpleName() + ", " + IBundleProvider.class.getSimpleName()
|
||||
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()
|
||||
+ ", etc., see the documentation for more details)");
|
||||
}
|
||||
}
|
||||
|
@ -451,48 +276,26 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
returnTypeFromAnnotation = deleteTags.type();
|
||||
}
|
||||
|
||||
if (returnTypeFromRp != null) {
|
||||
if (returnTypeFromAnnotation != null && !isResourceInterface(returnTypeFromAnnotation)) {
|
||||
if (!returnTypeFromRp.isAssignableFrom(returnTypeFromAnnotation)) {
|
||||
//FIXME potential null access on retunrTypeFromMethod
|
||||
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;
|
||||
if (!isResourceInterface(returnTypeFromAnnotation)) {
|
||||
if (!verifyIsValidResourceReturnType(returnTypeFromAnnotation)) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' from client type " + theMethod.getDeclaringClass().getCanonicalName()
|
||||
+ " returns " + toLogString(returnTypeFromAnnotation) + " according to annotation - Must return a resource type");
|
||||
}
|
||||
returnType = returnTypeFromAnnotation;
|
||||
} else {
|
||||
if (!isResourceInterface(returnTypeFromAnnotation)) {
|
||||
if (!verifyIsValidResourceReturnType(returnTypeFromAnnotation)) {
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' from " + IResourceProvider.class.getSimpleName() + " type " + theMethod.getDeclaringClass().getCanonicalName()
|
||||
+ " returns " + toLogString(returnTypeFromAnnotation) + " according to annotation - Must return a resource type");
|
||||
}
|
||||
returnType = returnTypeFromAnnotation;
|
||||
} else {
|
||||
// if (IRestfulClient.class.isAssignableFrom(theMethod.getDeclaringClass())) {
|
||||
// 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 (IRestfulClient.class.isAssignableFrom(theMethod.getDeclaringClass())) {
|
||||
// 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) {
|
||||
return new ReadMethodBinding(returnType, theMethod, theContext, theProvider);
|
||||
} 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);
|
||||
} else if (conformance != null) {
|
||||
return new ConformanceMethodBinding(theMethod, theContext, theProvider);
|
||||
|
@ -602,31 +405,4 @@ public abstract class BaseMethodBinding<T> implements IClientResponseHandler<T>
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,61 +1,25 @@
|
|||
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.Writer;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
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 ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
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.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.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
abstract class BaseOutcomeReturningMethodBinding extends BaseMethodBinding<MethodOutcome> {
|
||||
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)
|
||||
*/
|
||||
|
@ -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
|
||||
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);
|
||||
}
|
||||
|
||||
@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() {
|
||||
return myReturnVoid;
|
||||
}
|
||||
|
||||
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) {
|
||||
if (StringUtils.isBlank(theLocationHeader)) {
|
||||
|
|
|
@ -34,6 +34,7 @@ import ca.uhn.fhir.context.FhirVersionEnum;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
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.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,61 +1,33 @@
|
|||
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.lang.reflect.Method;
|
||||
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.IBaseOperationOutcome;
|
||||
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.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
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.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.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.ReflectionUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Object> {
|
||||
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_SUMMARY);
|
||||
set.add(Constants.PARAM_ELEMENTS);
|
||||
set.add(ResponseHighlighterInterceptor.PARAM_RAW);
|
||||
ALLOWED_PARAMS = Collections.unmodifiableSet(set);
|
||||
}
|
||||
|
||||
|
@ -107,8 +78,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
}
|
||||
} else if (Bundle.class.isAssignableFrom(methodReturnType)) {
|
||||
myMethodReturnType = MethodReturnTypeEnum.BUNDLE;
|
||||
} else if (IBundleProvider.class.isAssignableFrom(methodReturnType)) {
|
||||
myMethodReturnType = MethodReturnTypeEnum.BUNDLE_PROVIDER;
|
||||
} else if (MethodOutcome.class.isAssignableFrom(methodReturnType)) {
|
||||
myMethodReturnType = MethodReturnTypeEnum.METHOD_OUTCOME;
|
||||
} else {
|
||||
|
@ -195,8 +164,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
} else {
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -219,8 +186,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
return Collections.singletonList(resource);
|
||||
case RESOURCE:
|
||||
return resource;
|
||||
case BUNDLE_PROVIDER:
|
||||
throw new IllegalStateException("Return type of " + IBundleProvider.class.getSimpleName() + " is not supported in clients");
|
||||
case BUNDLE_RESOURCE:
|
||||
return resource;
|
||||
case METHOD_OUTCOME:
|
||||
|
@ -248,176 +213,6 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
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
|
||||
*/
|
||||
|
@ -430,7 +225,7 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.context.ConfigurationException;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -23,28 +23,18 @@ package ca.uhn.fhir.rest.client.method;
|
|||
import java.lang.reflect.Method;
|
||||
|
||||
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.FhirContext;
|
||||
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.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.MethodNotAllowedException;
|
||||
|
||||
public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
|
||||
public ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object 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();
|
||||
Class<?> genericReturnType = (Class<?>) theMethod.getGenericReturnType();
|
||||
if (methodReturnType != MethodReturnTypeEnum.RESOURCE || !IBaseConformance.class.isAssignableFrom(genericReturnType)) {
|
||||
|
@ -72,33 +62,6 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding
|
|||
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
|
||||
public RestOperationTypeEnum getRestOperationType() {
|
||||
|
|
|
@ -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 obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -26,25 +26,21 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.api.Constants;
|
||||
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.InvalidRequestException;
|
||||
|
||||
public class CountParameter implements IParameter {
|
||||
|
||||
private Class<?> myType;
|
||||
|
||||
@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) {
|
||||
IntegerDt since = ParameterUtil.toInteger(theSourceClientArgument);
|
||||
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
|
||||
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 @" + 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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import ca.uhn.fhir.rest.annotation.Create;
|
|||
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.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class CreateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {
|
||||
|
|
|
@ -94,10 +94,6 @@ public class DeleteMethodBinding extends BaseOutcomeReturningMethodBindingWithRe
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addParametersForServerRequest(RequestDetails theRequest, Object[] theParams) {
|
||||
theParams[getIdParameterIndex()] = theRequest.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMatchingOperation() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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 obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -24,31 +24,23 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
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 ca.uhn.fhir.context.ConfigurationException;
|
||||
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.param.CollectionBinder;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class ElementsParameter implements IParameter {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Class<? extends Collection> myInnerCollectionType;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@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) {
|
||||
StringBuilder values = new StringBuilder();
|
||||
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
|
||||
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 of type " + SummaryEnum.class + " but can not be a collection of collections");
|
||||
}
|
||||
if (theInnerCollectionType != null) {
|
||||
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
|
||||
+ " but can not be a collection of collections");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,5 @@
|
|||
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.lang.reflect.Method;
|
||||
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.rest.annotation.GetTags;
|
||||
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.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IRestfulServer;
|
||||
import ca.uhn.fhir.rest.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
||||
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) {
|
||||
super(theMethod, theContext, theProvider);
|
||||
|
||||
if (theProvider instanceof IResourceProvider) {
|
||||
myType = ((IResourceProvider) theProvider).getResourceType();
|
||||
} else {
|
||||
myType = theAnnotation.type();
|
||||
}
|
||||
myType = theAnnotation.type();
|
||||
|
||||
if (!Modifier.isInterface(myType.getModifiers())) {
|
||||
myResourceName = theContext.getResourceDefinition(myType).getName();
|
||||
|
@ -86,30 +58,6 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
|
|||
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
|
||||
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
|
@ -159,28 +107,5 @@ public class GetTagsMethodBinding extends BaseMethodBinding<TagList> {
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -25,23 +25,20 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
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.IPrimitiveType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.valueset.BundleTypeEnum;
|
||||
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.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.InvalidRequestException;
|
||||
|
||||
public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
|
||||
|
@ -57,16 +54,7 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
History historyAnnotation = theMethod.getAnnotation(History.class);
|
||||
Class<? extends IBaseResource> type = historyAnnotation.type();
|
||||
if (Modifier.isInterface(type.getModifiers())) {
|
||||
if (theProvider instanceof IResourceProvider) {
|
||||
type = ((IResourceProvider) theProvider).getResourceType();
|
||||
if (myIdParamIndex != null) {
|
||||
myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
|
||||
} else {
|
||||
myResourceOperationType = RestOperationTypeEnum.HISTORY_TYPE;
|
||||
}
|
||||
} else {
|
||||
myResourceOperationType = RestOperationTypeEnum.HISTORY_SYSTEM;
|
||||
}
|
||||
myResourceOperationType = RestOperationTypeEnum.HISTORY_SYSTEM;
|
||||
} else {
|
||||
if (myIdParamIndex != null) {
|
||||
myResourceOperationType = RestOperationTypeEnum.HISTORY_INSTANCE;
|
||||
|
@ -98,34 +86,6 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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
|
||||
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
IdDt id = null;
|
||||
|
@ -150,64 +110,6 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
if (theResourceName != null) {
|
||||
|
@ -237,9 +139,6 @@ public class HistoryMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
}
|
||||
|
||||
private static Class<? extends IBaseResource> toReturnType(Method theMethod, Object theProvider) {
|
||||
if (theProvider instanceof IResourceProvider) {
|
||||
return ((IResourceProvider) theProvider).getResourceType();
|
||||
}
|
||||
History historyAnnotation = theMethod.getAnnotation(History.class);
|
||||
Class<? extends IBaseResource> type = historyAnnotation.type();
|
||||
if (type != IBaseResource.class && type != IResource.class) {
|
||||
|
|
|
@ -26,10 +26,10 @@ import java.util.Map;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
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.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
||||
public class HttpDeleteClientInvocation extends BaseHttpClientInvocation {
|
||||
|
||||
|
|
|
@ -31,10 +31,10 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
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.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
||||
/**
|
||||
* @author James Agnew
|
||||
|
|
|
@ -26,11 +26,11 @@ import java.util.Map;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
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.client.api.IHttpClient;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
||||
public class HttpPatchClientInvocation extends BaseHttpClientInvocation {
|
||||
|
||||
|
|
|
@ -24,10 +24,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
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.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
|
||||
public class HttpSimpleGetClientInvocation extends BaseHttpClientInvocation {
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -32,9 +32,10 @@ import ca.uhn.fhir.context.ConfigurationException;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
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.param.BaseQueryParameter;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -8,31 +8,79 @@ import java.io.PushbackReader;
|
|||
import java.io.Reader;
|
||||
import java.lang.annotation.Annotation;
|
||||
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.Set;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
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.model.api.*;
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
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.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.annotation.At;
|
||||
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.method.OperationParameter.IOperationParamConverter;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.IDynamicSearchResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.server.method.ResourceParameter;
|
||||
import ca.uhn.fhir.rest.server.method.TransactionParameter;
|
||||
import ca.uhn.fhir.rest.server.method.ResourceParameter.Mode;
|
||||
import ca.uhn.fhir.rest.param.CollectionBinder;
|
||||
import ca.uhn.fhir.rest.param.DateAndListParam;
|
||||
import ca.uhn.fhir.rest.param.HasAndListParam;
|
||||
import ca.uhn.fhir.rest.param.NumberAndListParam;
|
||||
import ca.uhn.fhir.rest.param.QuantityAndListParam;
|
||||
import ca.uhn.fhir.rest.param.ReferenceAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
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.ParametersUtil;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
|
@ -323,14 +371,7 @@ public class MethodUtil {
|
|||
Class<?> parameterType = parameterTypes[paramIndex];
|
||||
Class<? extends java.util.Collection<?>> outerCollectionType = null;
|
||||
Class<? extends java.util.Collection<?>> innerCollectionType = null;
|
||||
if (SearchParameterMap.class.equals(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)) {
|
||||
if (TagList.class.isAssignableFrom(parameterType)) {
|
||||
// TagList is handled directly within the method bindings
|
||||
param = new NullParameter();
|
||||
} else {
|
||||
|
@ -348,20 +389,7 @@ public class MethodUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)) {
|
||||
if (parameterType.equals(SummaryEnum.class)) {
|
||||
param = new SummaryEnumParameter();
|
||||
} else if (parameterType.equals(PatchTypeEnum.class)) {
|
||||
param = new PatchTypeParameter();
|
||||
|
@ -407,15 +435,14 @@ public class MethodUtil {
|
|||
|
||||
param = new IncludeParameter((IncludeParam) nextAnnotation, instantiableCollectionType, specType);
|
||||
} else if (nextAnnotation instanceof ResourceParam) {
|
||||
Mode mode;
|
||||
if (IBaseResource.class.isAssignableFrom(parameterType)) {
|
||||
mode = Mode.RESOURCE;
|
||||
// good
|
||||
} else if (String.class.equals(parameterType)) {
|
||||
mode = ResourceParameter.Mode.BODY;
|
||||
// good
|
||||
} else if (byte[].class.equals(parameterType)) {
|
||||
mode = ResourceParameter.Mode.BODY_BYTE_ARRAY;
|
||||
// good
|
||||
} else if (EncodingEnum.class.equals(parameterType)) {
|
||||
mode = Mode.ENCODING;
|
||||
// good
|
||||
} else {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Method '");
|
||||
|
@ -427,7 +454,7 @@ public class MethodUtil {
|
|||
b.append(" or String or byte[]");
|
||||
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) {
|
||||
param = new NullParameter();
|
||||
} else if (nextAnnotation instanceof ServerBase) {
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -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.isNotBlank;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
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.Operation;
|
||||
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.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.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.method.ResourceParameter;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
|
||||
public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
|
@ -134,11 +126,7 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
+ theMethod.getDeclaringClass().getName());
|
||||
}
|
||||
|
||||
if (theMethod.getReturnType().equals(IBundleProvider.class)) {
|
||||
myReturnType = ReturnTypeEnum.BUNDLE;
|
||||
} else {
|
||||
myReturnType = ReturnTypeEnum.RESOURCE;
|
||||
}
|
||||
myReturnType = ReturnTypeEnum.RESOURCE;
|
||||
|
||||
if (getResourceName() == null) {
|
||||
myOtherOperatiopnType = RestOperationTypeEnum.EXTENDED_OPERATION_SERVER;
|
||||
|
@ -213,40 +201,6 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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
|
||||
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
String id = null;
|
||||
|
@ -266,42 +220,6 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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() {
|
||||
return this.myCanOperateAtInstanceLevel;
|
||||
}
|
||||
|
@ -318,12 +236,6 @@ public class OperationMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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) {
|
||||
myDescription = theDescription;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package ca.uhn.fhir.rest.client.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* 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.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -33,37 +29,22 @@ import java.util.Map;
|
|||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
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.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.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.IQueryParameterAnd;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
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.param.BaseAndListParam;
|
||||
import ca.uhn.fhir.rest.param.CollectionBinder;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
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.ReflectionUtil;
|
||||
|
||||
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";
|
||||
|
||||
private boolean myAllowGet;
|
||||
|
||||
private final FhirContext myContext;
|
||||
private IOperationParamConverter myConverter;
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Class<? extends Collection> myInnerCollectionType;
|
||||
private int myMax;
|
||||
private int myMin;
|
||||
private final String myName;
|
||||
private final String myOperationName;
|
||||
private Class<?> myParameterType;
|
||||
private String myParamType;
|
||||
private SearchParameter mySearchParameterBinding;
|
||||
|
@ -91,39 +68,16 @@ public class OperationParameter implements IParameter {
|
|||
}
|
||||
|
||||
OperationParameter(FhirContext theCtx, String theOperationName, String theParameterName, int theMin, int theMax) {
|
||||
myOperationName = theOperationName;
|
||||
myName = theParameterName;
|
||||
myMin = theMin;
|
||||
myMax = theMax;
|
||||
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() {
|
||||
return myContext;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
return myMax;
|
||||
}
|
||||
|
||||
public int getMin() {
|
||||
return myMin;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
|
@ -151,7 +105,6 @@ public class OperationParameter implements IParameter {
|
|||
|
||||
myParameterType = theParameterType;
|
||||
if (theInnerCollectionType != null) {
|
||||
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, myName);
|
||||
if (myMax == OperationParam.MAX_DEFAULT) {
|
||||
myMax = OperationParam.MAX_UNLIMITED;
|
||||
}
|
||||
|
@ -181,8 +134,6 @@ public class OperationParameter implements IParameter {
|
|||
*/
|
||||
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
|
||||
* should probably clean this up..
|
||||
|
@ -193,7 +144,6 @@ public class OperationParameter implements IParameter {
|
|||
} else if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
||||
myParamType = "date";
|
||||
myMax = 2;
|
||||
myAllowGet = true;
|
||||
} else if (myParameterType.equals(ValidationModeEnum.class)) {
|
||||
myParamType = "code";
|
||||
} else if (IBase.class.isAssignableFrom(myParameterType) && typeIsConcrete) {
|
||||
|
@ -217,10 +167,6 @@ public class OperationParameter implements IParameter {
|
|||
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
|
||||
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map<String, List<String>> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
|
||||
assert theTargetResource != null;
|
||||
|
@ -236,185 +182,7 @@ public class OperationParameter implements IParameter {
|
|||
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) {
|
||||
throw new InvalidRequestException("Invalid mode value: \"" + paramValues + "\"");
|
||||
|
|
|
@ -1,47 +1,14 @@
|
|||
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.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
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.rest.api.RequestTypeEnum;
|
||||
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.server.*;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils.ResponseEncoding;
|
||||
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;
|
||||
|
||||
public class PageMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
|
@ -50,143 +17,19 @@ public class PageMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
super(null, theMethod, theContext, null);
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PageMethodBinding.class);
|
||||
|
||||
public IBaseResource provider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BundleTypeEnum getResponseBundleType() {
|
||||
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
|
||||
public RestOperationTypeEnum getRestOperationType() {
|
||||
return RestOperationTypeEnum.GET_PAGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean incomingServerRequestMatchesMethod(RequestDetails theRequest) {
|
||||
String[] pageId = theRequest.getParameters().get(Constants.PARAM_PAGINGACTION);
|
||||
if (pageId == null || pageId.length == 0 || isBlank(pageId[0])) {
|
||||
return false;
|
||||
}
|
||||
if (theRequest.getRequestType() != RequestTypeEnum.GET) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
public ReturnTypeEnum getReturnType() {
|
||||
return ReturnTypeEnum.BUNDLE;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
|
@ -195,4 +38,8 @@ public class PageMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public IBaseResource provider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,12 @@ package ca.uhn.fhir.rest.client.method;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
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;
|
||||
|
||||
|
@ -35,6 +40,7 @@ import ca.uhn.fhir.rest.api.PatchTypeEnum;
|
|||
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.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package ca.uhn.fhir.rest.client.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* 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 obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -30,42 +28,18 @@ import java.util.Map;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
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.InvalidRequestException;
|
||||
|
||||
class PatchTypeParameter implements IParameter {
|
||||
@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
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
|
||||
return getTypeForRequestOrThrowInvalidRequestException(theRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
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.rest.api.QualifiedParamList;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.List;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||
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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterOr;
|
||||
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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.annotation.RawParam;
|
||||
import ca.uhn.fhir.rest.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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package ca.uhn.fhir.rest.client.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* 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 obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
@ -25,29 +23,31 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
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.lang3.StringUtils;
|
||||
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.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.InstantDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.annotation.Elements;
|
||||
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.server.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.util.DateUtils;
|
||||
import ca.uhn.fhir.rest.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
|
||||
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 boolean mySupportsVersion;
|
||||
private Integer myVersionIdIndex;
|
||||
|
@ -69,7 +69,8 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
|
|||
myVersionIdIndex = versionIdIndex;
|
||||
|
||||
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];
|
||||
|
||||
|
@ -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
|
||||
public List<Class<?>> getAllowableParamAnnotations() {
|
||||
ArrayList<Class<?>> retVal = new ArrayList<Class<?>>();
|
||||
|
@ -108,44 +101,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
|
|||
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
|
||||
public HttpGetClientInvocation invokeClient(Object[] theArgs) {
|
||||
HttpGetClientInvocation retVal;
|
||||
|
@ -173,7 +128,8 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
|
|||
}
|
||||
|
||||
@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);
|
||||
|
||||
IBaseBinary resource = (IBaseBinary) getContext().getResourceDefinition("Binary").newInstance();
|
||||
|
@ -187,8 +143,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
|
|||
return Collections.singletonList(resource);
|
||||
case RESOURCE:
|
||||
return resource;
|
||||
case BUNDLE_PROVIDER:
|
||||
return new SimpleBundleProvider(resource);
|
||||
case BUNDLE_RESOURCE:
|
||||
case METHOD_OUTCOME:
|
||||
break;
|
||||
|
@ -197,61 +151,6 @@ public class ReadMethodBinding extends BaseResourceReturningMethodBinding implem
|
|||
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
|
||||
public boolean isBinary() {
|
||||
return "Binary".equals(getResourceName());
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -23,14 +23,11 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.valueset.BundleTypeEnum;
|
||||
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.SearchStyleEnum;
|
||||
import ca.uhn.fhir.rest.client.impl.BaseHttpClientInvocation;
|
||||
import ca.uhn.fhir.rest.param.BaseQueryParameter;
|
||||
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.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchMethodBinding.class);
|
||||
|
||||
private String myCompartmentName;
|
||||
private String myDescription;
|
||||
private Integer myIdParamIndex;
|
||||
private String myQueryName;
|
||||
private boolean myAllowUnknownParams;
|
||||
|
||||
public SearchMethodBinding(Class<? extends IBaseResource> theReturnResourceType, Method theMethod, FhirContext theContext, Object theProvider) {
|
||||
super(theReturnResourceType, theMethod, theContext, theProvider);
|
||||
|
@ -66,7 +58,6 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
this.myQueryName = StringUtils.defaultIfBlank(search.queryName(), null);
|
||||
this.myCompartmentName = StringUtils.defaultIfBlank(search.compartmentName(), null);
|
||||
this.myIdParamIndex = MethodUtil.findIdParameterIndex(theMethod, getContext());
|
||||
this.myAllowUnknownParams = search.allowUnknownParams();
|
||||
|
||||
Description desc = theMethod.getAnnotation(Description.class);
|
||||
if (desc != null) {
|
||||
|
@ -119,13 +110,13 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
}
|
||||
|
||||
@Override
|
||||
public RestOperationTypeEnum getRestOperationType() {
|
||||
return RestOperationTypeEnum.SEARCH_TYPE;
|
||||
protected BundleTypeEnum getResponseBundleType() {
|
||||
return BundleTypeEnum.SEARCHSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BundleTypeEnum getResponseBundleType() {
|
||||
return BundleTypeEnum.SEARCHSET;
|
||||
public RestOperationTypeEnum getRestOperationType() {
|
||||
return RestOperationTypeEnum.SEARCH_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -133,129 +124,6 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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
|
||||
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
|
@ -282,43 +150,23 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
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
|
||||
protected boolean isAddContentLocationHeader() {
|
||||
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
|
||||
public String 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,
|
||||
SearchStyleEnum theSearchStyle) {
|
||||
SearchStyleEnum searchStyle = theSearchStyle;
|
||||
|
@ -379,9 +227,4 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
|
|||
return invocation;
|
||||
}
|
||||
|
||||
|
||||
public static BaseHttpClientInvocation createSearchInvocation(FhirContext theContext, String theSearchUrl, Map<String, List<String>> theParams) {
|
||||
return new HttpGetClientInvocation(theContext, theParams, theSearchUrl);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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.primitive.StringDt;
|
||||
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.param.BaseQueryParameter;
|
||||
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.UriOrListParam;
|
||||
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.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.CollectionUtil;
|
||||
|
|
|
@ -28,6 +28,7 @@ import java.util.Map;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
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.InvalidRequestException;
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -21,7 +21,6 @@ package ca.uhn.fhir.rest.client.method;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.rest.annotation.Since;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
|
||||
class SinceParameter extends SinceOrAtParameter {
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
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.FhirVersionEnum;
|
||||
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.SortSpec;
|
||||
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.InvalidRequestException;
|
||||
|
||||
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) {
|
||||
StringBuilder val = new StringBuilder();
|
||||
|
|
|
@ -1,53 +1,26 @@
|
|||
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.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
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.param.CollectionBinder;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class SummaryEnumParameter implements IParameter {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Class<? extends Collection> myInnerCollectionType;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@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) {
|
||||
List<String> values = new ArrayList<String>();
|
||||
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
|
||||
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 of type " + SummaryEnum.class + " but can not be a collection of collections");
|
||||
}
|
||||
if (theInnerCollectionType != null) {
|
||||
myInnerCollectionType = CollectionBinder.getInstantiableCollectionType(theInnerCollectionType, SummaryEnum.class.getSimpleName());
|
||||
throw new ConfigurationException("Method '" + theMethod.getName() + "' in type '" + theMethod.getDeclaringClass().getCanonicalName() + "' is of type " + SummaryEnum.class
|
||||
+ " but can not be a collection of collections");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,6 @@
|
|||
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.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
|
||||
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.FhirContext;
|
||||
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.rest.annotation.Transaction;
|
||||
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.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.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 {
|
||||
|
||||
private int myTransactionParamIndex;
|
||||
private ParamStyle myTransactionParamStyle;
|
||||
|
||||
public TransactionMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
|
||||
super(null, theMethod, theContext, theProvider);
|
||||
|
@ -67,7 +32,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
|
|||
+ " methods");
|
||||
}
|
||||
myTransactionParamIndex = index;
|
||||
myTransactionParamStyle = ((TransactionParameter) next).getParamStyle();
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
@ -92,19 +56,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
|
|||
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
|
||||
public BaseHttpClientInvocation invokeClient(Object[] theArgs) throws InternalErrorException {
|
||||
|
@ -118,81 +69,6 @@ public class TransactionMethodBinding extends BaseResourceReturningMethodBinding
|
|||
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) {
|
||||
return new HttpPostClientInvocation(theContext, theBundle);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
|
@ -37,7 +37,7 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
|
|||
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.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class UpdateMethodBinding extends BaseOutcomeReturningMethodBindingWithResourceParam {
|
||||
|
|
|
@ -33,7 +33,7 @@ import ca.uhn.fhir.rest.annotation.Validate;
|
|||
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.param.IParameter;
|
||||
|
||||
public class ValidateMethodBindingDstu1 extends BaseOutcomeReturningMethodBindingWithResourceParam {
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.annotation.Validate;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
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.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.method.ResourceParameter;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package ca.uhn.fhir.rest.api.server;
|
|||
|
||||
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.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||
|
@ -17,6 +16,4 @@ public interface IFhirVersionServer {
|
|||
|
||||
IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer);
|
||||
|
||||
IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,26 +1,5 @@
|
|||
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.lang.reflect.Method;
|
||||
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.model.api.TagList;
|
||||
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.TagListParam;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.api.server.IRestfulServer;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
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.client.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.IParameter;
|
||||
import ca.uhn.fhir.rest.server.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void> {
|
||||
|
||||
|
@ -147,37 +127,6 @@ abstract class BaseAddOrDeleteTagsMethodBinding extends BaseMethodBinding<Void>
|
|||
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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.rest.param;
|
||||
package ca.uhn.fhir.rest.server.method;
|
||||
|
||||
/*
|
||||
* #%L
|
Loading…
Reference in New Issue