Refactor ServerConformanceProvider so that it no longer keeps any state

This commit is contained in:
James Agnew 2019-07-07 12:57:31 -04:00
parent 4bd60a8447
commit 34f7d4ddbd
25 changed files with 885 additions and 911 deletions

View File

@ -33,7 +33,6 @@ import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.LoggerFactory;
@ -62,7 +61,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/** the resource bindings */
private ConcurrentHashMap<String, ResourceBinding> myResourceNameToBinding = new ConcurrentHashMap<String, ResourceBinding>();
/** the server configuration */
private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration();
private RestfulServerConfiguration serverConfiguration = new RestfulServerConfiguration();
/** the conformance. It is created once during startup */
private org.hl7.fhir.r4.model.CapabilityStatement myR4CapabilityStatement;
@ -135,28 +134,23 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
switch (fhirContextVersion) {
case R4:
org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider r4ServerCapabilityStatementProvider = new org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration);
r4ServerCapabilityStatementProvider.initializeOperations();
myR4CapabilityStatement = r4ServerCapabilityStatementProvider.getServerConformance(null);
myR4CapabilityStatement = r4ServerCapabilityStatementProvider.getServerConformance(null, null);
break;
case DSTU3:
org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider dstu3ServerCapabilityStatementProvider = new org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration);
dstu3ServerCapabilityStatementProvider.initializeOperations();
myDstu3CapabilityStatement = dstu3ServerCapabilityStatementProvider.getServerConformance(null);
myDstu3CapabilityStatement = dstu3ServerCapabilityStatementProvider.getServerConformance(null, null);
break;
case DSTU2_1:
org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider dstu2_1ServerConformanceProvider = new org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider(serverConfiguration);
dstu2_1ServerConformanceProvider.initializeOperations();
myDstu2_1Conformance = dstu2_1ServerConformanceProvider.getServerConformance(null);
myDstu2_1Conformance = dstu2_1ServerConformanceProvider.getServerConformance(null, null);
break;
case DSTU2_HL7ORG:
org.hl7.fhir.instance.conf.ServerConformanceProvider dstu2Hl7OrgServerConformanceProvider = new org.hl7.fhir.instance.conf.ServerConformanceProvider(serverConfiguration);
dstu2Hl7OrgServerConformanceProvider.initializeOperations();
myDstu2Hl7OrgConformance = dstu2Hl7OrgServerConformanceProvider.getServerConformance(null);
myDstu2Hl7OrgConformance = dstu2Hl7OrgServerConformanceProvider.getServerConformance(null, null);
break;
case DSTU2:
ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider dstu2ServerConformanceProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration);
dstu2ServerConformanceProvider.initializeOperations();
myDstu2Conformance = dstu2ServerConformanceProvider.getServerConformance(null);
myDstu2Conformance = dstu2ServerConformanceProvider.getServerConformance(null, null);
break;
default:
throw new ConfigurationException("Unsupported Fhir version: " + fhirContextVersion);
@ -228,14 +222,14 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
}
/**
* This method will add a provider to the conformance. This method is almost an exact copy of {@link ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods }
* This method will add a provider to the conformance. This method is almost an exact copy of {@link ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods(Object, Class)} }
*
* @param theProvider
* an instance of the provider interface
* @param theProviderInterface
* the class describing the providers interface
* @return the numbers of basemethodbindings added
* @see ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods
* @see ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods(Object)
*/
public int addProvider(IResourceProvider theProvider, Class<? extends IResourceProvider> theProviderInterface) throws ConfigurationException {
int count = 0;

View File

@ -29,7 +29,6 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.jpa.util.SingleItemLoadingCache;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
@ -44,12 +43,12 @@ import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider;
import ca.uhn.fhir.util.CoverageIgnore;
import ca.uhn.fhir.util.ExtensionConstants;
import org.hl7.fhir.instance.model.Subscription;
import org.hl7.fhir.r4.model.Extension;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -87,7 +86,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
}
@Override
public Conformance getServerConformance(HttpServletRequest theRequest) {
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
Conformance retVal = myCachedValue;
Map<String, Long> counts = null;
@ -98,7 +97,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
FhirContext ctx = myRestfulServer.getFhirContext();
retVal = super.getServerConformance(theRequest);
retVal = super.getServerConformance(theRequest, theRequestDetails);
for (Rest nextRest : retVal.getRest()) {
for (RestResource nextResource : nextRest.getResource()) {

View File

@ -25,9 +25,8 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.util.CoverageIgnore;
import ca.uhn.fhir.util.ExtensionConstants;
@ -80,7 +79,7 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
}
@Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
CapabilityStatement retVal = myCachedValue;
Map<String, Long> counts = null;
@ -89,7 +88,7 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
}
counts = defaultIfNull(counts, Collections.emptyMap());
retVal = super.getServerConformance(theRequest);
retVal = super.getServerConformance(theRequest, theRequestDetails);
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) {

View File

@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.CapabilityStatement.*;
import org.hl7.fhir.r4.model.Enumerations.SearchParamType;
@ -78,7 +79,7 @@ public class JpaConformanceProviderR4 extends org.hl7.fhir.r4.hapi.rest.server.S
}
@Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
CapabilityStatement retVal = myCachedValue;
Map<String, Long> counts = null;
@ -87,7 +88,7 @@ public class JpaConformanceProviderR4 extends org.hl7.fhir.r4.hapi.rest.server.S
}
counts = defaultIfNull(counts, Collections.emptyMap());
retVal = super.getServerConformance(theRequest);
retVal = super.getServerConformance(theRequest, theRequestDetails);
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) {

View File

@ -0,0 +1,38 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
public class Bindings {
private final IdentityHashMap<SearchMethodBinding, String> myNamedSearchMethodBindingToName;
private final HashMap<String, List<SearchMethodBinding>> mySearchNameToBindings;
private final HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
private final IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
public Bindings(IdentityHashMap<SearchMethodBinding, String> theNamedSearchMethodBindingToName, HashMap<String, List<SearchMethodBinding>> theSearchNameToBindings, HashMap<String, List<OperationMethodBinding>> theOperationNameToBindings, IdentityHashMap<OperationMethodBinding, String> theOperationBindingToName) {
myNamedSearchMethodBindingToName = theNamedSearchMethodBindingToName;
mySearchNameToBindings = theSearchNameToBindings;
myOperationNameToBindings = theOperationNameToBindings;
myOperationBindingToName = theOperationBindingToName;
}
public IdentityHashMap<SearchMethodBinding, String> getNamedSearchMethodBindingToName() {
return myNamedSearchMethodBindingToName;
}
public HashMap<String, List<SearchMethodBinding>> getSearchNameToBindings() {
return mySearchNameToBindings;
}
public HashMap<String, List<OperationMethodBinding>> getOperationNameToBindings() {
return myOperationNameToBindings;
}
public IdentityHashMap<OperationMethodBinding, String> getOperationBindingToName() {
return myOperationBindingToName;
}
}

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.server;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
public interface IServerConformanceProvider<T extends IBaseResource> {
@ -31,7 +32,7 @@ public interface IServerConformanceProvider<T extends IBaseResource> {
*
* See the class documentation for an important note if you are extending this class
*/
T getServerConformance(HttpServletRequest theRequest);
T getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails);
/**
* This setter is needed in implementation classes (along with

View File

@ -190,8 +190,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
}
public RestulfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration result = new RestulfulServerConfiguration();
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration result = new RestfulServerConfiguration();
result.setResourceBindings(getResourceBindings());
result.setServerBindings(getServerBindings());
result.setImplementationDescription(getImplementationDescription());

View File

@ -0,0 +1,304 @@
package ca.uhn.fhir.rest.server;
/*
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import ca.uhn.fhir.util.VersionUtil;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class RestfulServerConfiguration {
private static final Logger ourLog = LoggerFactory.getLogger(RestfulServerConfiguration.class);
private Collection<ResourceBinding> resourceBindings;
private List<BaseMethodBinding<?>> serverBindings;
private String implementationDescription;
private String serverVersion = VersionUtil.getVersion();
private String serverName = "HAPI FHIR";
private FhirContext fhirContext;
private IServerAddressStrategy serverAddressStrategy;
private IPrimitiveType<Date> myConformanceDate;
/**
* Constructor
*/
public RestfulServerConfiguration() {
super();
}
/**
* Get the resourceBindings
*
* @return the resourceBindings
*/
public Collection<ResourceBinding> getResourceBindings() {
return resourceBindings;
}
/**
* Set the resourceBindings
*
* @param resourceBindings the resourceBindings to set
*/
public RestfulServerConfiguration setResourceBindings(Collection<ResourceBinding> resourceBindings) {
this.resourceBindings = resourceBindings;
return this;
}
/**
* Get the serverBindings
*
* @return the serverBindings
*/
public List<BaseMethodBinding<?>> getServerBindings() {
return serverBindings;
}
/**
* Set the theServerBindings
*/
public RestfulServerConfiguration setServerBindings(List<BaseMethodBinding<?>> theServerBindings) {
this.serverBindings = theServerBindings;
return this;
}
/**
* Get the implementationDescription
*
* @return the implementationDescription
*/
public String getImplementationDescription() {
if (isBlank(implementationDescription)) {
return "HAPI FHIR";
}
return implementationDescription;
}
/**
* Set the implementationDescription
*
* @param implementationDescription the implementationDescription to set
*/
public RestfulServerConfiguration setImplementationDescription(String implementationDescription) {
this.implementationDescription = implementationDescription;
return this;
}
/**
* Get the serverVersion
*
* @return the serverVersion
*/
public String getServerVersion() {
return serverVersion;
}
/**
* Set the serverVersion
*
* @param serverVersion the serverVersion to set
*/
public RestfulServerConfiguration setServerVersion(String serverVersion) {
this.serverVersion = serverVersion;
return this;
}
/**
* Get the serverName
*
* @return the serverName
*/
public String getServerName() {
return serverName;
}
/**
* Set the serverName
*
* @param serverName the serverName to set
*/
public RestfulServerConfiguration setServerName(String serverName) {
this.serverName = serverName;
return this;
}
/**
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain providers should generally use this context if one is needed, as opposed to
* creating their own.
*/
public FhirContext getFhirContext() {
return this.fhirContext;
}
/**
* Set the fhirContext
*
* @param fhirContext the fhirContext to set
*/
public RestfulServerConfiguration setFhirContext(FhirContext fhirContext) {
this.fhirContext = fhirContext;
return this;
}
/**
* Get the serverAddressStrategy
*
* @return the serverAddressStrategy
*/
public IServerAddressStrategy getServerAddressStrategy() {
return serverAddressStrategy;
}
/**
* Set the serverAddressStrategy
*
* @param serverAddressStrategy the serverAddressStrategy to set
*/
public void setServerAddressStrategy(IServerAddressStrategy serverAddressStrategy) {
this.serverAddressStrategy = serverAddressStrategy;
}
/**
* Get the date that will be specified in the conformance profile
* exported by this server. Typically this would be populated with
* an InstanceType.
*/
public IPrimitiveType<Date> getConformanceDate() {
return myConformanceDate;
}
/**
* Set the date that will be specified in the conformance profile
* exported by this server. Typically this would be populated with
* an InstanceType.
*/
public void setConformanceDate(IPrimitiveType<Date> theConformanceDate) {
myConformanceDate = theConformanceDate;
}
public Bindings provideBindings() {
IdentityHashMap<SearchMethodBinding, String> myNamedSearchMethodBindingToName = new IdentityHashMap<>();
HashMap<String, List<SearchMethodBinding>> mySearchNameToBindings = new HashMap<>();
IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName = new IdentityHashMap<>();
HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings = new HashMap<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
for (Map.Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
List<BaseMethodBinding<?>> nextMethodBindings = nextEntry.getValue();
for (BaseMethodBinding<?> nextMethodBinding : nextMethodBindings) {
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
if (myOperationBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createOperationName(methodBinding);
ourLog.debug("Detected operation: {}", name);
myOperationBindingToName.put(methodBinding, name);
if (myOperationNameToBindings.containsKey(name) == false) {
myOperationNameToBindings.put(name, new ArrayList<>());
}
myOperationNameToBindings.get(name).add(methodBinding);
} else if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (myNamedSearchMethodBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createNamedQueryName(methodBinding);
ourLog.debug("Detected named query: {}", name);
myNamedSearchMethodBindingToName.put(methodBinding, name);
if (!mySearchNameToBindings.containsKey(name)) {
mySearchNameToBindings.put(name, new ArrayList<>());
}
mySearchNameToBindings.get(name).add(methodBinding);
}
}
}
return new Bindings(myNamedSearchMethodBindingToName, mySearchNameToBindings, myOperationNameToBindings, myOperationBindingToName);
}
public Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
for (ResourceBinding next : getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>());
}
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
}
for (BaseMethodBinding<?> nextMethodBinding : getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>());
}
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
return resourceToMethods;
}
private String createOperationName(OperationMethodBinding theMethodBinding) {
StringBuilder retVal = new StringBuilder();
if (theMethodBinding.getResourceName() != null) {
retVal.append(theMethodBinding.getResourceName());
}
retVal.append('-');
if (theMethodBinding.isCanOperateAtInstanceLevel()) {
retVal.append('i');
}
if (theMethodBinding.isCanOperateAtServerLevel()) {
retVal.append('s');
}
retVal.append('-');
// Exclude the leading $
retVal.append(theMethodBinding.getName(), 1, theMethodBinding.getName().length());
return retVal.toString();
}
private String createNamedQueryName(SearchMethodBinding searchMethodBinding) {
StringBuilder retVal = new StringBuilder();
if (searchMethodBinding.getResourceName() != null) {
retVal.append(searchMethodBinding.getResourceName());
}
retVal.append("-query-");
retVal.append(searchMethodBinding.getQueryName());
return retVal.toString();
}
}

View File

@ -911,4 +911,6 @@ public class RestfulServerUtils {
}
}
}

View File

@ -1,191 +0,0 @@
package ca.uhn.fhir.rest.server;
/*
* #%L
* HAPI FHIR - Server Framework
* %%
* Copyright (C) 2014 - 2019 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collection;
import java.util.Date;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.util.VersionUtil;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class RestulfulServerConfiguration {
private Collection<ResourceBinding> resourceBindings;
private List<BaseMethodBinding<?>> serverBindings;
private String implementationDescription;
private String serverVersion = VersionUtil.getVersion();
private String serverName = "HAPI FHIR";
private FhirContext fhirContext;
private IServerAddressStrategy serverAddressStrategy;
private IPrimitiveType<Date> myConformanceDate;
/**
* Constructor
*/
public RestulfulServerConfiguration() {
super();
}
/**
* Get the resourceBindings
* @return the resourceBindings
*/
public Collection<ResourceBinding> getResourceBindings() {
return resourceBindings;
}
/**
* Set the resourceBindings
* @param resourceBindings the resourceBindings to set
*/
public RestulfulServerConfiguration setResourceBindings(Collection<ResourceBinding> resourceBindings) {
this.resourceBindings = resourceBindings;
return this;
}
/**
* Get the serverBindings
* @return the serverBindings
*/
public List<BaseMethodBinding<?>> getServerBindings() {
return serverBindings;
}
/**
* Set the theServerBindings
*/
public RestulfulServerConfiguration setServerBindings(List<BaseMethodBinding<?>> theServerBindings) {
this.serverBindings = theServerBindings;
return this;
}
/**
* Get the implementationDescription
* @return the implementationDescription
*/
public String getImplementationDescription() {
if (isBlank(implementationDescription)) {
return "HAPI FHIR";
}
return implementationDescription;
}
/**
* Set the implementationDescription
* @param implementationDescription the implementationDescription to set
*/
public RestulfulServerConfiguration setImplementationDescription(String implementationDescription) {
this.implementationDescription = implementationDescription;
return this;
}
/**
* Get the serverVersion
* @return the serverVersion
*/
public String getServerVersion() {
return serverVersion;
}
/**
* Set the serverVersion
* @param serverVersion the serverVersion to set
*/
public RestulfulServerConfiguration setServerVersion(String serverVersion) {
this.serverVersion = serverVersion;
return this;
}
/**
* Get the serverName
* @return the serverName
*/
public String getServerName() {
return serverName;
}
/**
* Set the serverName
* @param serverName the serverName to set
*/
public RestulfulServerConfiguration setServerName(String serverName) {
this.serverName = serverName;
return this;
}
/**
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain providers should generally use this context if one is needed, as opposed to
* creating their own.
*/
public FhirContext getFhirContext() {
return this.fhirContext;
}
/**
* Set the fhirContext
* @param fhirContext the fhirContext to set
*/
public RestulfulServerConfiguration setFhirContext(FhirContext fhirContext) {
this.fhirContext = fhirContext;
return this;
}
/**
* Get the serverAddressStrategy
* @return the serverAddressStrategy
*/
public IServerAddressStrategy getServerAddressStrategy() {
return serverAddressStrategy;
}
/**
* Set the serverAddressStrategy
* @param serverAddressStrategy the serverAddressStrategy to set
*/
public void setServerAddressStrategy(IServerAddressStrategy serverAddressStrategy) {
this.serverAddressStrategy = serverAddressStrategy;
}
/**
* Get the date that will be specified in the conformance profile
* exported by this server. Typically this would be populated with
* an InstanceType.
*/
public IPrimitiveType<Date> getConformanceDate() {
return myConformanceDate;
}
/**
* Set the date that will be specified in the conformance profile
* exported by this server. Typically this would be populated with
* an InstanceType.
*/
public void setConformanceDate(IPrimitiveType<Date> theConformanceDate) {
myConformanceDate = theConformanceDate;
}
}

View File

@ -21,6 +21,8 @@ package ca.uhn.fhir.rest.server.method;
*/
import java.lang.reflect.Method;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import org.hl7.fhir.instance.model.api.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -40,13 +42,20 @@ import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import javax.annotation.Nonnull;
public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding {
private static final long CACHE_MILLIS = 60 * 1000;
public ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) {
/*
* Note: This caching mechanism should probably be configurable and maybe
* even applicable to other bindings. It's particularly important for this
* operation though, so a one-off is fine for now
*/
private final AtomicReference<IBaseResource> myCachedResponse = new AtomicReference<>();
private final AtomicLong myCachedResponseExpires = new AtomicLong(0L);
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)) {
@ -62,7 +71,22 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding
@Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws BaseServerResponseException {
IBaseResource conf = (IBaseResource) invokeServerMethod(theServer, theRequest, theMethodParams);
IBaseResource conf;
conf = myCachedResponse.get();
if (conf != null) {
long expires = myCachedResponseExpires.get();
if (expires < System.currentTimeMillis()) {
conf = null;
}
}
if (conf == null) {
conf = (IBaseResource) invokeServerMethod(theServer, theRequest, theMethodParams);
myCachedResponse.set(conf);
myCachedResponseExpires.set(System.currentTimeMillis() + CACHE_MILLIS);
}
return new SimpleBundleProvider(conf);
}

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.rest.server.util;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.IRestfulServerDefaults;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestfulServerConfiguration;
import org.apache.commons.lang3.Validate;
public class BaseServerCapabilityStatementProvider {
private RestfulServerConfiguration myConfiguration;
protected BaseServerCapabilityStatementProvider() {
super();
}
protected BaseServerCapabilityStatementProvider(RestfulServerConfiguration theServerConfiguration) {
myConfiguration = theServerConfiguration;
}
protected RestfulServerConfiguration getServerConfiguration(RequestDetails theRequestDetails) {
RestfulServerConfiguration retVal;
if (theRequestDetails != null && theRequestDetails.getServer() instanceof RestfulServer) {
retVal = ((RestfulServer) theRequestDetails.getServer()).createConfiguration();
Validate.isTrue(myConfiguration == null);
} else {
retVal = myConfiguration;
Validate.notNull(retVal);
}
return retVal;
}
}

View File

@ -1,6 +1,41 @@
package org.hl7.fhir.dstu2016may.hapi.rest.server;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu2016may.model.*;
import org.hl7.fhir.dstu2016may.model.Conformance.*;
import org.hl7.fhir.dstu2016may.model.Enumerations.ConformanceResourceStatus;
import org.hl7.fhir.dstu2016may.model.Enumerations.ResourceType;
import org.hl7.fhir.dstu2016may.model.OperationDefinition.OperationDefinitionParameterComponent;
import org.hl7.fhir.dstu2016may.model.OperationDefinition.OperationKind;
import org.hl7.fhir.dstu2016may.model.OperationDefinition.OperationParameterUse;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.Map.Entry;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
@ -20,54 +55,14 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu2016may.model.*;
import org.hl7.fhir.dstu2016may.model.Conformance.*;
import org.hl7.fhir.dstu2016may.model.Enumerations.ConformanceResourceStatus;
import org.hl7.fhir.dstu2016may.model.Enumerations.ResourceType;
import org.hl7.fhir.dstu2016may.model.OperationDefinition.*;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.*;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
/**
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
*
* <p>
* Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is always returned unless {@link #setCache(boolean)} is called with a value of
* <code>false</code>. This means that if you are adding anything to the returned conformance instance on each call you should call <code>setCache(false)</code> in your provider constructor.
* </p>
*/
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
public class ServerConformanceProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider<Conformance> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProvider.class);
private boolean myCache = true;
private volatile Conformance myConformance;
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
private String myPublisher = "Not provided";
private Callable<RestulfulServerConfiguration> myServerConfiguration;
/**
* No-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
@ -78,16 +73,19 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
/**
* Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/
@Deprecated
public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration;
this();
}
/**
* Constructor
*/
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration;
public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) {
super(theServerConfiguration);
}
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) {
@ -111,9 +109,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings(RequestDetails theRequestDetails) {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<>();
for (ResourceBinding next : getServerConfiguration().getResourceBindings()) {
for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
@ -122,7 +120,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
}
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) {
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>());
@ -132,8 +130,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return resourceToMethods;
}
private DateTimeType conformanceDate() {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate();
private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) {
try {
return new DateTimeType(buildDate.getValueAsString());
@ -173,32 +171,32 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return myPublisher;
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override
@Metadata
public Conformance getServerConformance(HttpServletRequest theRequest) {
if (myConformance != null && myCache) {
return myConformance;
}
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate());
retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU2_1.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big
// effort since the parser
// needs to be modified to actually allow it
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
String serverBase = getServerConfiguration().getServerAddressStrategy().determineServerBase(servletContext, theRequest);
String serverBase = serverConfiguration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
retVal
.getImplementation()
.setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription());
.setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(ConformanceStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion());
retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML);
retVal.addFormat(Constants.CT_FHIR_JSON);
retVal.setStatus(ConformanceResourceStatus.ACTIVE);
@ -209,14 +207,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings(theRequestDetails);
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
ConformanceRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference((def.getResourceProfile(serverBase)));
@ -274,10 +272,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof SearchMethodBinding) {
handleSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding);
handleSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
} else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
// Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName));
@ -312,7 +310,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
ourLog.debug("Found bound operation: {}", opName);
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName));
@ -322,12 +320,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
myConformance = retVal;
return retVal;
}
private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) {
SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters();
@ -395,7 +392,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
}
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget);
RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) {
ResourceType code;
try {
@ -412,40 +409,17 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
@Initialize
public void initializeOperations() {
myOperationBindingToName = new IdentityHashMap<OperationMethodBinding, String>();
myOperationNameToBindings = new HashMap<String, List<OperationMethodBinding>>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
List<BaseMethodBinding<?>> nextMethodBindings = nextEntry.getValue();
for (BaseMethodBinding<?> nextMethodBinding : nextMethodBindings) {
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
if (myOperationBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createOperationName(methodBinding);
ourLog.debug("Detected operation: {}", name);
myOperationBindingToName.put(methodBinding, name);
if (myOperationNameToBindings.containsKey(name) == false) {
myOperationNameToBindings.put(name, new ArrayList<OperationMethodBinding>());
}
myOperationNameToBindings.get(name).add(methodBinding);
}
}
}
}
@Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) {
public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId);
}
List<OperationMethodBinding> sharedDescriptions = myOperationNameToBindings.get(theId.getIdPart());
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
List<OperationMethodBinding> sharedDescriptions = bindings.getOperationNameToBindings().get(theId.getIdPart());
if (sharedDescriptions == null || sharedDescriptions.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
@ -457,8 +431,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
op.setInstance(false);
op.setSystem(false);
Set<String> inParams = new HashSet<String>();
Set<String> outParams = new HashSet<String>();
Set<String> inParams = new HashSet<>();
Set<String> outParams = new HashSet<>();
for (OperationMethodBinding sharedDescription : sharedDescriptions) {
if (isNotBlank(sharedDescription.getDescription())) {
@ -542,9 +516,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
* <p>
* See the class documentation for an important note if you are extending this class
* </p>
* @deprecated Since 4.0.0 this does not do anything
*/
public void setCache(boolean theCache) {
myCache = theCache;
// nothing
}
/**
@ -557,24 +532,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
@Override
public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration;
}
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
@Override
public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) {
return theO1.getName().compareTo(theO2.getName());
}
});
// ignore
}
private void sortSearchParameters(List<SearchParameter> searchParameters) {

View File

@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
@ -152,7 +154,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -178,7 +180,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
/*
* Check the operation definitions themselves
*/
OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"));
OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"), createRequestDetails(rs));
String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def);
//@formatter:off
@ -194,7 +196,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
));
//@formatter:on
andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"));
andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"), createRequestDetails(rs));
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def);
//@formatter:off
@ -210,7 +212,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
));
//@formatter:on
OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"));
OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"), createRequestDetails(rs));
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def);
//@formatter:off
@ -226,7 +228,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
));
//@formatter:on
orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"));
orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"), createRequestDetails(rs));
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def);
//@formatter:off
@ -488,4 +490,12 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
}

View File

@ -15,19 +15,16 @@ import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Initialize;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -36,7 +33,6 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -63,23 +59,13 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
/**
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
*
* <p>
* Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is always returned unless {@link #setCache(boolean)} is called with a value of
* <code>false</code>. This means that if you are adding anything to the returned conformance instance on each call you should call <code>setCache(false)</code> in your provider constructor.
* </p>
*/
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
public class ServerConformanceProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider<Conformance> {
private boolean myCache = true;
private volatile Conformance myConformance;
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
private String myPublisher = "Not provided";
private Callable<RestulfulServerConfiguration> myServerConfiguration;
/**
* No-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
* No-arg constructor and setter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
*/
public ServerConformanceProvider() {
super();
@ -87,16 +73,19 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
/**
* Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/
@Deprecated
public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration;
this();
}
/**
* Constructor
*/
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration;
public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) {
super(theServerConfiguration);
}
private void checkBindingForSystemOps(Rest rest, Set<SystemRestfulInteractionEnum> systemOps, BaseMethodBinding<?> nextMethodBinding) {
@ -115,9 +104,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings(RequestDetails theRequestDetails) {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
for (ResourceBinding next : getServerConfiguration().getResourceBindings()) {
for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
@ -126,7 +115,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
}
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) {
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
@ -136,8 +125,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return resourceToMethods;
}
private DateTimeDt conformanceDate() {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate();
private DateTimeDt conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) {
try {
return new DateTimeDt(buildDate.getValueAsString());
@ -185,39 +174,31 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
myPublisher = thePublisher;
}
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override
@Metadata
public Conformance getServerConformance(HttpServletRequest theRequest) {
if (myConformance != null && myCache) {
return myConformance;
}
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDate(conformanceDate());
retVal.setDate(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU2.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCodeEnum.UNKNOWN_EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
// needs to be modified to actually allow it
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
String serverBase = getServerConfiguration().getServerAddressStrategy().determineServerBase(servletContext, theRequest);
String serverBase = serverConfiguration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
retVal
.getImplementation()
.setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription());
.setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(ConformanceStatementKindEnum.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion());
retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML);
retVal.addFormat(Constants.CT_FHIR_JSON);
@ -227,14 +208,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Set<SystemRestfulInteractionEnum> systemOps = new HashSet<>();
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings(theRequestDetails);
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteractionEnum> resourceOps = new HashSet<>();
RestResource resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference(new IdDt(def.getResourceProfile(serverBase)));
@ -287,10 +268,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof SearchMethodBinding) {
handleSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding);
handleSearchMethodBinding(resource, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
} else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
// Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).getDefinition().setReference("OperationDefinition/" + opName);
@ -325,7 +306,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
rest.addOperation().setName(methodBinding.getName().substring(1)).getDefinition().setReference("OperationDefinition/" + opName);
}
@ -334,15 +315,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
myConformance = retVal;
return retVal;
}
private void handleSearchMethodBinding(Rest rest, RestResource resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, SearchMethodBinding searchMethodBinding) {
private void handleSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>();
List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter);
@ -401,7 +381,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.addChain(chain);
} else {
if (nextParameter.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
for (String nextWhitelist : new TreeSet<String>(nextParameter.getQualifierWhitelist())) {
for (String nextWhitelist : new TreeSet<>(nextParameter.getQualifierWhitelist())) {
if (nextWhitelist.startsWith(".")) {
param.addChain(nextWhitelist.substring(1));
}
@ -414,7 +394,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
}
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget);
RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) {
ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName());
if (code != null) {
@ -426,38 +406,16 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
@Initialize
public void initializeOperations() {
myOperationBindingToName = new IdentityHashMap<OperationMethodBinding, String>();
myOperationNameToBindings = new HashMap<String, List<OperationMethodBinding>>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
List<BaseMethodBinding<?>> nextMethodBindings = nextEntry.getValue();
for (BaseMethodBinding<?> nextMethodBinding : nextMethodBindings) {
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
if (myOperationBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createOperationName(methodBinding);
myOperationBindingToName.put(methodBinding, name);
if (myOperationNameToBindings.containsKey(name) == false) {
myOperationNameToBindings.put(name, new ArrayList<OperationMethodBinding>());
}
myOperationNameToBindings.get(name).add(methodBinding);
}
}
}
}
@Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdDt theId) {
public OperationDefinition readOperationDefinition(@IdParam IdDt theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId);
}
List<OperationMethodBinding> sharedDescriptions = myOperationNameToBindings.get(theId.getIdPart());
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
List<OperationMethodBinding> sharedDescriptions = bindings.getOperationNameToBindings().get(theId.getIdPart());
if (sharedDescriptions == null || sharedDescriptions.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
@ -467,8 +425,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
op.setKind(OperationKindEnum.OPERATION);
op.setIdempotent(true);
Set<String> inParams = new HashSet<String>();
Set<String> outParams = new HashSet<String>();
Set<String> inParams = new HashSet<>();
Set<String> outParams = new HashSet<>();
for (OperationMethodBinding sharedDescription : sharedDescriptions) {
if (isNotBlank(sharedDescription.getDescription())) {
@ -543,23 +501,16 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
* <p>
* See the class documentation for an important note if you are extending this class
* </p>
* @deprecated Since 4.0.0 this does nothing
*/
@Deprecated
public void setCache(boolean theCache) {
myCache = theCache;
// nothing
}
@Override
public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration;
}
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
@Override
public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) {
return theO1.getName().compareTo(theO2.getName());
}
});
// nothing
}
private void sortSearchParameters(List<SearchParameter> searchParameters) {

View File

@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
@ -145,7 +147,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -170,7 +172,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
/*
* Check the operation definitions themselves
*/
OperationDefinition andListDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient--andlist"));
OperationDefinition andListDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient--andlist"), createRequestDetails(rs));
String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def);
//@formatter:off
@ -405,4 +407,11 @@ public class OperationServerWithSearchParamTypesDstu2Test {
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
}

View File

@ -16,6 +16,8 @@ import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Test;
@ -104,7 +106,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -127,7 +129,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -149,7 +151,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-everything"));
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-everything"), createRequestDetails(rs));
validate(opDef);
assertEquals("everything", opDef.getCode());
@ -167,7 +169,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -200,7 +202,7 @@ public class ServerConformanceProviderDstu2Test {
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -220,7 +222,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -243,7 +245,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -256,7 +258,7 @@ public class ServerConformanceProviderDstu2Test {
assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp","Encounter-i-someOp","Patient-i-validate","Encounter-i-validate"));
{
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-someOp"));
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-someOp"), createRequestDetails(rs));
validate(opDef);
Set<String> types = toStrings(opDef.getType());
@ -271,7 +273,7 @@ public class ServerConformanceProviderDstu2Test {
assertEquals("Patient", opDef.getParameter().get(1).getType());
}
{
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter-i-someOp"));
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter-i-someOp"), createRequestDetails(rs));
validate(opDef);
Set<String> types = toStrings(opDef.getType());
@ -286,7 +288,7 @@ public class ServerConformanceProviderDstu2Test {
assertEquals("Encounter", opDef.getParameter().get(1).getType());
}
{
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-validate"));
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-validate"), createRequestDetails(rs));
validate(opDef);
Set<String> types = toStrings(opDef.getType());
@ -311,7 +313,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info("AAAAAA" + conf);
@ -328,18 +330,18 @@ public class ServerConformanceProviderDstu2Test {
ServerConformanceProvider sc = new ServerConformanceProvider(rs) {
@Override
public Conformance getServerConformance(HttpServletRequest theRequest) {
return super.getServerConformance(theRequest);
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest, theRequestDetails);
}
};
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
Conformance sconf = sc.getServerConformance(createHttpServletRequest());
Conformance sconf = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
assertEquals("OperationDefinition/-is-plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue());
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/-is-plain"));
OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/-is-plain"), createRequestDetails(rs));
validate(opDef);
assertEquals("plain", opDef.getCode());
@ -366,8 +368,8 @@ public class ServerConformanceProviderDstu2Test {
ServerConformanceProvider sc = new ServerConformanceProvider(rs) {
@Override
public Conformance getServerConformance(HttpServletRequest theRequest) {
Conformance conformance = super.getServerConformance(theRequest);
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
Conformance conformance = super.getServerConformance(theRequest, theRequestDetails);
ExtensionDt extensionDt = new ExtensionDt();
ExtensionDt extensionDtToken = new ExtensionDt();
ExtensionDt extensionDtAuthorize = new ExtensionDt();
@ -392,7 +394,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -410,7 +412,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -440,7 +442,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -460,7 +462,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -496,7 +498,7 @@ public class ServerConformanceProviderDstu2Test {
}
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -532,7 +534,7 @@ public class ServerConformanceProviderDstu2Test {
}
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -566,7 +568,7 @@ public class ServerConformanceProviderDstu2Test {
}
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -602,7 +604,7 @@ public class ServerConformanceProviderDstu2Test {
}
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -629,7 +631,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -648,7 +650,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -667,7 +669,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
@ -943,4 +945,11 @@ public class ServerConformanceProviderDstu2Test {
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
}

View File

@ -5,19 +5,16 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Initialize;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.CapabilityStatement.*;
@ -33,7 +30,6 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -66,17 +62,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* <code>false</code>. This means that if you are adding anything to the returned conformance instance on each call you should call <code>setCache(false)</code> in your provider constructor.
* </p>
*/
public class ServerCapabilityStatementProvider implements IServerConformanceProvider<CapabilityStatement> {
public class ServerCapabilityStatementProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider<CapabilityStatement> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerCapabilityStatementProvider.class);
private boolean myCache = true;
private volatile CapabilityStatement myCapabilityStatement;
private IdentityHashMap<SearchMethodBinding, String> myNamedSearchMethodBindingToName;
private HashMap<String, List<SearchMethodBinding>> mySearchNameToBindings;
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
private String myPublisher = "Not provided";
private Callable<RestulfulServerConfiguration> myServerConfiguration;
/**
* No-arg constructor and setter so that the ServerConformanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
@ -87,16 +76,19 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
/**
* Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/
@Deprecated
public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration;
this();
}
/**
* Constructor
* Constructor - This is intended only for JAX-RS server
*/
public ServerCapabilityStatementProvider(RestulfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration;
public ServerCapabilityStatementProvider(RestfulServerConfiguration theServerConfiguration) {
super(theServerConfiguration);
}
private void checkBindingForSystemOps(CapabilityStatementRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) {
@ -120,9 +112,9 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
}
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings(RequestDetails theRequestDetails) {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
for (ResourceBinding next : getServerConfiguration().getResourceBindings()) {
for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
@ -131,7 +123,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
}
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) {
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>());
@ -141,8 +133,8 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
return resourceToMethods;
}
private DateTimeType conformanceDate() {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate();
private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) {
try {
return new DateTimeType(buildDate.getValueAsString());
@ -201,40 +193,33 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
myPublisher = thePublisher;
}
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override
@Metadata
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
if (myCapabilityStatement != null && myCache) {
return myCapabilityStatement;
}
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
CapabilityStatement retVal = new CapabilityStatement();
retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate());
retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU3.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big
// effort since the parser
// needs to be modified to actually allow it
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
String serverBase = getServerConfiguration().getServerAddressStrategy().determineServerBase(servletContext, theRequest);
String serverBase = serverConfiguration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
retVal
.getImplementation()
.setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription());
.setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(CapabilityStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion());
retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML_NEW);
retVal.addFormat(Constants.CT_FHIR_JSON_NEW);
retVal.setStatus(PublicationStatus.ACTIVE);
@ -245,14 +230,14 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings(theRequestDetails);
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference((def.getResourceProfile(serverBase)));
@ -312,16 +297,16 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (methodBinding.getQueryName() != null) {
String queryName = myNamedSearchMethodBindingToName.get(methodBinding);
String queryName = bindings.getNamedSearchMethodBindingToName().get(methodBinding);
if (operationNames.add(queryName)) {
rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(new Reference("OperationDefinition/" + queryName));
}
} else {
handleNamelessSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding);
handleNamelessSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
}
} else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
// Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName));
@ -356,7 +341,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
ourLog.debug("Found bound operation: {}", opName);
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName));
@ -366,16 +351,17 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
}
myCapabilityStatement = retVal;
return retVal;
}
private void handleNamelessSearchMethodBinding(CapabilityStatementRestComponent rest, CapabilityStatementRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) {
SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>();
List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter);
@ -440,7 +426,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
}
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget);
RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) {
ResourceType code;
try {
@ -457,60 +443,22 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
}
@Initialize
public void initializeOperations() {
myNamedSearchMethodBindingToName = new IdentityHashMap<>();
mySearchNameToBindings = new HashMap<>();
myOperationBindingToName = new IdentityHashMap<>();
myOperationNameToBindings = new HashMap<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
List<BaseMethodBinding<?>> nextMethodBindings = nextEntry.getValue();
for (BaseMethodBinding<?> nextMethodBinding : nextMethodBindings) {
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
if (myOperationBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createOperationName(methodBinding);
ourLog.debug("Detected operation: {}", name);
myOperationBindingToName.put(methodBinding, name);
if (myOperationNameToBindings.containsKey(name) == false) {
myOperationNameToBindings.put(name, new ArrayList<>());
}
myOperationNameToBindings.get(name).add(methodBinding);
} else if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (myNamedSearchMethodBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createNamedQueryName(methodBinding);
ourLog.debug("Detected named query: {}", name);
myNamedSearchMethodBindingToName.put(methodBinding, name);
if (!mySearchNameToBindings.containsKey(name)) {
mySearchNameToBindings.put(name, new ArrayList<>());
}
mySearchNameToBindings.get(name).add(methodBinding);
}
}
}
}
@Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) {
public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId);
}
List<OperationMethodBinding> operationBindings = myOperationNameToBindings.get(theId.getIdPart());
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
List<OperationMethodBinding> operationBindings = bindings.getOperationNameToBindings().get(theId.getIdPart());
if (operationBindings != null && !operationBindings.isEmpty()) {
return readOperationDefinitionForOperation(operationBindings);
}
List<SearchMethodBinding> searchBindings = mySearchNameToBindings.get(theId.getIdPart());
List<SearchMethodBinding> searchBindings = bindings.getSearchNameToBindings().get(theId.getIdPart());
if (searchBindings != null && !searchBindings.isEmpty()) {
return readOperationDefinitionForNamedSearch(searchBindings);
}
@ -667,24 +615,16 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
* <p>
* See the class documentation for an important note if you are extending this class
* </p>
*
* @deprecated Since 4.0.0 this doesn't do anything
*/
public ServerCapabilityStatementProvider setCache(boolean theCache) {
myCache = theCache;
return this;
}
@Override
public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration;
}
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
@Override
public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) {
return theO1.getName().compareTo(theO2.getName());
}
});
// ignore
}
private void sortSearchParameters(List<SearchParameter> searchParameters) {

View File

@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
@ -152,7 +154,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -178,7 +180,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
/*
* Check the operation definitions themselves
*/
OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"));
OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"), createRequestDetails(rs));
String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def);
//@formatter:off
@ -194,7 +196,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
));
//@formatter:on
andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"));
andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"), createRequestDetails(rs));
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def);
//@formatter:off
@ -210,7 +212,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
));
//@formatter:on
OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"));
OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"), createRequestDetails(rs));
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def);
//@formatter:off
@ -226,7 +228,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
));
//@formatter:on
orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"));
orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"), createRequestDetails(rs));
def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def);
//@formatter:off
@ -488,4 +490,11 @@ public class OperationServerWithSearchParamTypesDstu3Test {
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
}

View File

@ -8,15 +8,17 @@ import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
import ca.uhn.fhir.rest.server.RestfulServerConfiguration;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.method.IParameter;
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
@ -106,7 +108,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -134,7 +136,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -157,7 +159,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -165,7 +167,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertEquals(1, conformance.getRest().get(0).getOperation().size());
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs));
validate(opDef);
assertEquals("everything", opDef.getCode());
assertThat(opDef.getSystem(), is(false));
@ -185,7 +187,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs));
validate(opDef);
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
@ -206,7 +208,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -238,7 +240,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -258,7 +260,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -283,7 +285,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -296,7 +298,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp", "Encounter-i-someOp", "Patient-i-validate", "Encounter-i-validate"));
{
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp"), createRequestDetails(rs));
validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource());
@ -311,7 +313,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertEquals("Patient", opDef.getParameter().get(1).getType());
}
{
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp"), createRequestDetails(rs));
validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource());
@ -326,7 +328,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertEquals("Encounter", opDef.getParameter().get(1).getType());
}
{
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate"), createRequestDetails(rs));
validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource());
@ -351,7 +353,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
@ -367,15 +369,15 @@ public class ServerCapabilityStatementProviderDstu3Test {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
@Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
return super.getServerConformance(theRequest);
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest, createRequestDetails(rs));
}
};
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"), createRequestDetails(rs));
validate(opDef);
assertEquals("plain", opDef.getCode());
@ -410,7 +412,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -440,7 +442,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -460,7 +462,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -496,7 +498,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -532,7 +534,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -565,7 +567,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -583,8 +585,8 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rsNoType = new RestfulServer(ourCtx) {
@Override
public RestulfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration();
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal;
}
@ -594,14 +596,14 @@ public class ServerCapabilityStatementProviderDstu3Test {
rsNoType.setServerConformanceProvider(scNoType);
rsNoType.init(createServletConfig());
CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsNoType));
String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(confNoType);
RestfulServer rsWithType = new RestfulServer(ourCtx) {
@Override
public RestulfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration();
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal;
}
@ -611,7 +613,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rsWithType.setServerConformanceProvider(scWithType);
rsWithType.init(createServletConfig());
CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest());
CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsWithType));
String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType);
ourLog.info(confWithType);
@ -630,7 +632,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -649,7 +651,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -668,7 +670,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
@ -685,7 +687,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -695,7 +697,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
String operationReference = operationComponent.getDefinition().getReference();
assertThat(operationReference, not(nullValue()));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition);
assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME));
@ -729,7 +731,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -737,7 +739,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
String operationReference = operationComponent.getDefinition().getReference();
assertThat(operationReference, not(nullValue()));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition);
assertThat("The operation name should be the code if no description is set", operationDefinition.getName(), is(NamedQueryResourceProvider.QUERY_NAME));
@ -772,7 +774,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -781,7 +783,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertThat(operations.size(), is(1));
assertThat(operations.get(0).getName(), is(TypeLevelOperationProvider.OPERATION_NAME));
OperationDefinition opDef = sc.readOperationDefinition(new IdType(operations.get(0).getDefinition().getReference()));
OperationDefinition opDef = sc.readOperationDefinition(new IdType(operations.get(0).getDefinition().getReference()), createRequestDetails(rs));
validate(opDef);
assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode());
assertThat(opDef.getSystem(), is(false));
@ -1157,4 +1159,10 @@ public class ServerCapabilityStatementProviderDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
}

View File

@ -21,17 +21,16 @@ package org.hl7.fhir.instance.conf;
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.text.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.*;
import org.hl7.fhir.instance.model.Conformance.*;
@ -65,14 +64,9 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
* constructor.
* </p>
*/
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
public class ServerConformanceProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider<Conformance> {
private boolean myCache = true;
private volatile Conformance myConformance;
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
private String myPublisher = "Not provided";
private Callable<RestulfulServerConfiguration> myServerConfiguration;
/**
* No-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
@ -83,29 +77,24 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
/**
* Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/
@Deprecated
public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration;
this();
}
/**
* Constructor
*/
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration;
public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) {
super(theServerConfiguration);
}
@Override
public void setRestfulServer (RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration;
}
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
// ignore
}
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps,
@ -130,9 +119,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings(RequestDetails theRequestDetails) {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
for (ResourceBinding next : getServerConfiguration().getResourceBindings()) {
for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
@ -141,10 +130,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
}
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) {
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
resourceToMethods.put(resourceName, new ArrayList<>());
}
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
@ -166,45 +155,45 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return myPublisher;
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override
@Metadata
public Conformance getServerConformance(HttpServletRequest theRequest) {
if (myConformance != null && myCache) {
return myConformance;
}
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
Bindings bindings = serverConfiguration.provideBindings();
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate());
retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU2_HL7ORG.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
// needs to be modified to actually allow it
retVal.getImplementation().setDescription(getServerConfiguration().getImplementationDescription());
retVal.getImplementation().setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(ConformanceStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion());
retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML);
retVal.addFormat(Constants.CT_FHIR_JSON);
ConformanceRestComponent rest = retVal.addRest();
rest.setMode(RestfulConformanceMode.SERVER);
Set<SystemRestfulInteraction> systemOps = new HashSet<SystemRestfulInteraction>();
Set<String> operationNames = new HashSet<String>();
Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings(theRequestDetails);
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<TypeRestfulInteraction>();
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
ConformanceRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName());
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
String serverBase = getServerConfiguration().getServerAddressStrategy().determineServerBase(servletContext, theRequest);
String serverBase = serverConfiguration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
resource.getProfile().setReference((def.getResourceProfile(serverBase)));
TreeSet<String> includes = new TreeSet<>();
@ -258,11 +247,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof SearchMethodBinding) {
handleSearchMethodBinding(rest, resource, resourceName, def, includes,
(SearchMethodBinding) nextMethodBinding);
handleSearchMethodBinding(resource, def, includes,
(SearchMethodBinding) nextMethodBinding, theRequestDetails);
} else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
// Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName()).getDefinition()
@ -298,7 +287,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
rest.addOperation().setName(methodBinding.getName()).getDefinition()
.setReference("OperationDefinition/" + opName);
@ -308,12 +297,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
myConformance = retVal;
return retVal;
}
private DateTimeType conformanceDate() {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate();
private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) {
try {
return new DateTimeType(buildDate.getValueAsString());
@ -324,13 +312,13 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return DateTimeType.now();
}
private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource,
String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) {
private void handleSearchMethodBinding(ConformanceRestResourceComponent resource,
RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>();
List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter);
@ -388,7 +376,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
}
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget);
RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) {
ResourceType code;
try {
@ -405,38 +393,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
}
@Initialize
public void initializeOperations() {
myOperationBindingToName = new IdentityHashMap<>();
myOperationNameToBindings = new HashMap<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
List<BaseMethodBinding<?>> nextMethodBindings = nextEntry.getValue();
for (BaseMethodBinding<?> nextMethodBinding : nextMethodBindings) {
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
if (myOperationBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createOperationName(methodBinding);
myOperationBindingToName.put(methodBinding, name);
if (myOperationNameToBindings.containsKey(name) == false) {
myOperationNameToBindings.put(name, new ArrayList<>());
}
myOperationNameToBindings.get(name).add(methodBinding);
}
}
}
}
@Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) {
public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId);
}
List<OperationMethodBinding> sharedDescriptions = myOperationNameToBindings.get(theId.getIdPart());
List<OperationMethodBinding> sharedDescriptions = getServerConfiguration(theRequestDetails).provideBindings().getOperationNameToBindings().get(theId.getIdPart());
if (sharedDescriptions == null || sharedDescriptions.isEmpty()) {
throw new ResourceNotFoundException(theId);
}
@ -508,9 +472,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
* See the class documentation for an important note if you are extending this
* class
* </p>
* @deprecated Since 4.0.0 this method doesn't do anything
*/
@Deprecated
public void setCache(boolean theCache) {
myCache = theCache;
// nothing
}
/**
@ -524,15 +490,6 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
myPublisher = thePublisher;
}
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
@Override
public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) {
return theO1.getName().compareTo(theO2.getName());
}
});
}
private void sortSearchParameters(List<SearchParameter> searchParameters) {
Collections.sort(searchParameters, new Comparator<SearchParameter>() {
@Override

View File

@ -14,6 +14,8 @@ import java.util.*;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.instance.conf.ServerConformanceProvider;
import org.hl7.fhir.instance.model.*;
import org.hl7.fhir.instance.model.Conformance.*;
@ -62,7 +64,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -85,14 +87,14 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
assertEquals(1, conformance.getRest().get(0).getOperation().size());
assertEquals("$everything", conformance.getRest().get(0).getOperation().get(0).getName());
assertEquals("OperationDefinition/everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference());
assertEquals("OperationDefinition/Patient-i-everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference());
}
@ -107,7 +109,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/everything"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
ourLog.info(conf);
@ -127,7 +129,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -159,7 +161,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -179,7 +181,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -214,7 +216,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
}
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -231,18 +233,18 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
ServerConformanceProvider sc = new ServerConformanceProvider(rs) {
@Override
public Conformance getServerConformance(HttpServletRequest theRequest) {
return super.getServerConformance(theRequest);
public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest, theRequestDetails);
}
};
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
Conformance sconf = sc.getServerConformance(createHttpServletRequest());
assertEquals("OperationDefinition/plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference());
Conformance sconf = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
assertEquals("OperationDefinition/-is-plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/plain"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
ourLog.info(conf);
@ -273,7 +275,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -303,7 +305,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -323,7 +325,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -355,7 +357,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
}
}
assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -376,7 +378,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -395,7 +397,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -414,7 +416,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest());
Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
assertTrue(ourCtx.newValidator().validateWithResult(conformance).isSuccessful());
}
@ -597,4 +599,10 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
}

View File

@ -5,19 +5,16 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Initialize;
import ca.uhn.fhir.rest.annotation.Metadata;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.RestulfulServerConfiguration;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.*;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -28,13 +25,11 @@ import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
import org.hl7.fhir.r4.model.OperationDefinition.OperationDefinitionParameterComponent;
import org.hl7.fhir.r4.model.OperationDefinition.OperationKind;
import org.hl7.fhir.r4.model.OperationDefinition.OperationParameterUse;
import org.hl7.fhir.r4.model.codesystems.UnknownContentCode;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -67,17 +62,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* <code>false</code>. This means that if you are adding anything to the returned conformance instance on each call you should call <code>setCache(false)</code> in your provider constructor.
* </p>
*/
public class ServerCapabilityStatementProvider implements IServerConformanceProvider<CapabilityStatement> {
public class ServerCapabilityStatementProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider<CapabilityStatement> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerCapabilityStatementProvider.class);
private boolean myCache = true;
private volatile CapabilityStatement myCapabilityStatement;
private IdentityHashMap<SearchMethodBinding, String> myNamedSearchMethodBindingToName;
private HashMap<String, List<SearchMethodBinding>> mySearchNameToBindings;
private IdentityHashMap<OperationMethodBinding, String> myOperationBindingToName;
private HashMap<String, List<OperationMethodBinding>> myOperationNameToBindings;
private String myPublisher = "Not provided";
private Callable<RestulfulServerConfiguration> myServerConfiguration;
/**
* No-arg constructor and setter so that the ServerConformanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
@ -88,16 +76,19 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
/**
* Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/
@Deprecated
public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration;
this();
}
/**
* Constructor
* Constructor - This is intended only for JAX-RS server
*/
public ServerCapabilityStatementProvider(RestulfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration;
public ServerCapabilityStatementProvider(RestfulServerConfiguration theServerConfiguration) {
super(theServerConfiguration);
}
private void checkBindingForSystemOps(CapabilityStatementRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) {
@ -121,29 +112,10 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
}
private Map<String, List<BaseMethodBinding<?>>> collectMethodBindings() {
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<String, List<BaseMethodBinding<?>>>();
for (ResourceBinding next : getServerConfiguration().getResourceBindings()) {
String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
}
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
}
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) {
String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>());
}
resourceToMethods.get(resourceName).add(nextMethodBinding);
}
return resourceToMethods;
}
private DateTimeType conformanceDate() {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate();
private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) {
try {
return new DateTimeType(buildDate.getValueAsString());
@ -154,37 +126,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
return DateTimeType.now();
}
private String createNamedQueryName(SearchMethodBinding searchMethodBinding) {
StringBuilder retVal = new StringBuilder();
if (searchMethodBinding.getResourceName() != null) {
retVal.append(searchMethodBinding.getResourceName());
}
retVal.append("-query-");
retVal.append(searchMethodBinding.getQueryName());
return retVal.toString();
}
private String createOperationName(OperationMethodBinding theMethodBinding) {
StringBuilder retVal = new StringBuilder();
if (theMethodBinding.getResourceName() != null) {
retVal.append(theMethodBinding.getResourceName());
}
retVal.append('-');
if (theMethodBinding.isCanOperateAtInstanceLevel()) {
retVal.append('i');
}
if (theMethodBinding.isCanOperateAtServerLevel()) {
retVal.append('s');
}
retVal.append('-');
// Exclude the leading $
retVal.append(theMethodBinding.getName(), 1, theMethodBinding.getName().length());
return retVal.toString();
}
/**
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null (although this is not enforced). The
@ -202,37 +144,30 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
myPublisher = thePublisher;
}
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override
@Metadata
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
if (myCapabilityStatement != null && myCache) {
return myCapabilityStatement;
}
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
RestfulServerConfiguration configuration = getServerConfiguration(theRequestDetails);
Bindings bindings = configuration.provideBindings();
CapabilityStatement retVal = new CapabilityStatement();
retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate());
retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(Enumerations.FHIRVersion.fromCode(FhirVersionEnum.R4.getFhirVersionString()));
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
String serverBase = getServerConfiguration().getServerAddressStrategy().determineServerBase(servletContext, theRequest);
String serverBase = configuration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
retVal
.getImplementation()
.setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription());
.setDescription(configuration.getImplementationDescription());
retVal.setKind(CapabilityStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion());
retVal.getSoftware().setName(configuration.getServerName());
retVal.getSoftware().setVersion(configuration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML_NEW);
retVal.addFormat(Constants.CT_FHIR_JSON_NEW);
retVal.setStatus(PublicationStatus.ACTIVE);
@ -243,14 +178,14 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = new HashSet<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = configuration.collectMethodBindings();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName);
RuntimeResourceDefinition def = configuration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName());
resource.getProfileElement().setValue((def.getResourceProfile(serverBase)));
@ -310,16 +245,16 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (methodBinding.getQueryName() != null) {
String queryName = myNamedSearchMethodBindingToName.get(methodBinding);
String queryName = bindings.getNamedSearchMethodBindingToName().get(methodBinding);
if (operationNames.add(queryName)) {
rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(("OperationDefinition/" + queryName));
}
} else {
handleNamelessSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding);
handleNamelessSearchMethodBinding(resource, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
}
} else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
// Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName));
@ -354,7 +289,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding);
String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) {
ourLog.debug("Found bound operation: {}", opName);
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName));
@ -364,16 +299,15 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
}
myCapabilityStatement = retVal;
return retVal;
}
private void handleNamelessSearchMethodBinding(CapabilityStatementRestComponent rest, CapabilityStatementRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) {
private void handleNamelessSearchMethodBinding(CapabilityStatementRestResourceComponent resource, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>();
List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter);
@ -438,7 +372,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
}
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget);
RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) {
ResourceType code;
try {
@ -455,60 +389,21 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
}
@Initialize
public void initializeOperations() {
myNamedSearchMethodBindingToName = new IdentityHashMap<>();
mySearchNameToBindings = new HashMap<>();
myOperationBindingToName = new IdentityHashMap<>();
myOperationNameToBindings = new HashMap<>();
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = collectMethodBindings();
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
List<BaseMethodBinding<?>> nextMethodBindings = nextEntry.getValue();
for (BaseMethodBinding<?> nextMethodBinding : nextMethodBindings) {
if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
if (myOperationBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createOperationName(methodBinding);
ourLog.debug("Detected operation: {}", name);
myOperationBindingToName.put(methodBinding, name);
if (myOperationNameToBindings.containsKey(name) == false) {
myOperationNameToBindings.put(name, new ArrayList<>());
}
myOperationNameToBindings.get(name).add(methodBinding);
} else if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (myNamedSearchMethodBindingToName.containsKey(methodBinding)) {
continue;
}
String name = createNamedQueryName(methodBinding);
ourLog.debug("Detected named query: {}", name);
myNamedSearchMethodBindingToName.put(methodBinding, name);
if (!mySearchNameToBindings.containsKey(name)) {
mySearchNameToBindings.put(name, new ArrayList<>());
}
mySearchNameToBindings.get(name).add(methodBinding);
}
}
}
}
@Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) {
public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId);
}
List<OperationMethodBinding> operationBindings = myOperationNameToBindings.get(theId.getIdPart());
RestfulServerConfiguration configuration = getServerConfiguration(theRequestDetails);
Bindings bindings = configuration.provideBindings();
List<OperationMethodBinding> operationBindings = bindings.getOperationNameToBindings().get(theId.getIdPart());
if (operationBindings != null && !operationBindings.isEmpty()) {
return readOperationDefinitionForOperation(operationBindings);
}
List<SearchMethodBinding> searchBindings = mySearchNameToBindings.get(theId.getIdPart());
List<SearchMethodBinding> searchBindings = bindings.getSearchNameToBindings().get(theId.getIdPart());
if (searchBindings != null && !searchBindings.isEmpty()) {
return readOperationDefinitionForNamedSearch(searchBindings);
}
@ -665,15 +560,17 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
* <p>
* See the class documentation for an important note if you are extending this class
* </p>
*
* @deprecated Since 4.0.0 - This method no longer does anything
*/
@Deprecated
public ServerCapabilityStatementProvider setCache(boolean theCache) {
myCache = theCache;
return this;
}
@Override
public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration;
// ignore
}
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {

View File

@ -8,12 +8,13 @@ import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.client.HttpProxyTest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.method.IParameter;
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
@ -90,7 +91,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -102,6 +103,12 @@ public class ServerCapabilityStatementProviderR4Test {
assertTrue(res.getConditionalUpdate());
}
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
@Test
public void testExtendedOperationReturningBundle() throws Exception {
@ -113,7 +120,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -121,7 +128,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertEquals(1, conformance.getRest().get(0).getOperation().size());
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs));
validate(opDef);
assertEquals("everything", opDef.getCode());
assertThat(opDef.getSystem(), is(false));
@ -141,7 +148,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs));
validate(opDef);
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
@ -162,7 +169,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -194,7 +201,7 @@ public class ServerCapabilityStatementProviderR4Test {
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -214,7 +221,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -237,7 +244,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -250,7 +257,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp", "Encounter-i-someOp", "Patient-i-validate", "Encounter-i-validate"));
{
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp"), createRequestDetails(rs));
validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource());
@ -265,7 +272,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertEquals("Patient", opDef.getParameter().get(1).getType());
}
{
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp"), createRequestDetails(rs));
validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource());
@ -280,7 +287,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertEquals("Encounter", opDef.getParameter().get(1).getType());
}
{
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate"), createRequestDetails(rs));
validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource());
@ -305,7 +312,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
@ -321,15 +328,15 @@ public class ServerCapabilityStatementProviderR4Test {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
@Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) {
return super.getServerConformance(theRequest);
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest, createRequestDetails(rs));
}
};
rs.setServerConformanceProvider(sc);
rs.init(createServletConfig());
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"));
OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"), createRequestDetails(rs));
validate(opDef);
assertEquals("plain", opDef.getCode());
@ -364,7 +371,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -394,7 +401,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -414,7 +421,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -450,7 +457,7 @@ public class ServerCapabilityStatementProviderR4Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -486,7 +493,7 @@ public class ServerCapabilityStatementProviderR4Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -519,7 +526,7 @@ public class ServerCapabilityStatementProviderR4Test {
}
}
assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -537,8 +544,8 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rsNoType = new RestfulServer(ourCtx){
@Override
public RestulfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration();
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal;
}
@ -548,14 +555,14 @@ public class ServerCapabilityStatementProviderR4Test {
rsNoType.setServerConformanceProvider(scNoType);
rsNoType.init(createServletConfig());
CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsNoType));
String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(confNoType);
RestfulServer rsWithType = new RestfulServer(ourCtx){
@Override
public RestulfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration();
public RestfulServerConfiguration createConfiguration() {
RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal;
}
@ -565,7 +572,7 @@ public class ServerCapabilityStatementProviderR4Test {
rsWithType.setServerConformanceProvider(scWithType);
rsWithType.init(createServletConfig());
CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest());
CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsWithType));
String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType);
ourLog.info(confWithType);
@ -584,7 +591,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -603,7 +610,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -622,7 +629,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
@ -639,7 +646,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -649,7 +656,7 @@ public class ServerCapabilityStatementProviderR4Test {
String operationReference = operationComponent.getDefinition();
assertThat(operationReference, not(nullValue()));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition);
assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME));
@ -683,7 +690,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -691,7 +698,7 @@ public class ServerCapabilityStatementProviderR4Test {
String operationReference = operationComponent.getDefinition();
assertThat(operationReference, not(nullValue()));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference));
OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition);
assertThat("The operation name should be the code if no description is set", operationDefinition.getName(), is(NamedQueryResourceProvider.QUERY_NAME));
@ -726,7 +733,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf);
@ -735,7 +742,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertThat(operations.size(), is(1));
assertThat(operations.get(0).getName(), is(TypeLevelOperationProvider.OPERATION_NAME));
OperationDefinition opDef = sc.readOperationDefinition(new IdType(operations.get(0).getDefinition()));
OperationDefinition opDef = sc.readOperationDefinition(new IdType(operations.get(0).getDefinition()), createRequestDetails(rs));
validate(opDef);
assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode());
assertThat(opDef.getSystem(), is(false));

View File

@ -251,6 +251,12 @@
results exist. A default implementation has been provided, so this is not
a breaking change.
</action>
<action type="change">
Server CapabilityStatement/Conformance repsonses from the /metadata endpoint will
now be cached for 60 seconds always. This was previously a configurable setting on
the ServerConformanceProvider, but it is now handled directly by the method
binding so the provider now has no responsibility for caching.
</action>
</release>
<release version="3.8.0" date="2019-05-30" description="Hippo">
<action type="fix">