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.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -62,7 +61,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
/** the resource bindings */ /** the resource bindings */
private ConcurrentHashMap<String, ResourceBinding> myResourceNameToBinding = new ConcurrentHashMap<String, ResourceBinding>(); private ConcurrentHashMap<String, ResourceBinding> myResourceNameToBinding = new ConcurrentHashMap<String, ResourceBinding>();
/** the server configuration */ /** the server configuration */
private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration(); private RestfulServerConfiguration serverConfiguration = new RestfulServerConfiguration();
/** the conformance. It is created once during startup */ /** the conformance. It is created once during startup */
private org.hl7.fhir.r4.model.CapabilityStatement myR4CapabilityStatement; private org.hl7.fhir.r4.model.CapabilityStatement myR4CapabilityStatement;
@ -135,28 +134,23 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv
switch (fhirContextVersion) { switch (fhirContextVersion) {
case R4: case R4:
org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider r4ServerCapabilityStatementProvider = new org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration); 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, null);
myR4CapabilityStatement = r4ServerCapabilityStatementProvider.getServerConformance(null);
break; break;
case DSTU3: case DSTU3:
org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider dstu3ServerCapabilityStatementProvider = new org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration); 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, null);
myDstu3CapabilityStatement = dstu3ServerCapabilityStatementProvider.getServerConformance(null);
break; break;
case DSTU2_1: case DSTU2_1:
org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider dstu2_1ServerConformanceProvider = new org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider(serverConfiguration); 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, null);
myDstu2_1Conformance = dstu2_1ServerConformanceProvider.getServerConformance(null);
break; break;
case DSTU2_HL7ORG: case DSTU2_HL7ORG:
org.hl7.fhir.instance.conf.ServerConformanceProvider dstu2Hl7OrgServerConformanceProvider = new org.hl7.fhir.instance.conf.ServerConformanceProvider(serverConfiguration); org.hl7.fhir.instance.conf.ServerConformanceProvider dstu2Hl7OrgServerConformanceProvider = new org.hl7.fhir.instance.conf.ServerConformanceProvider(serverConfiguration);
dstu2Hl7OrgServerConformanceProvider.initializeOperations(); myDstu2Hl7OrgConformance = dstu2Hl7OrgServerConformanceProvider.getServerConformance(null, null);
myDstu2Hl7OrgConformance = dstu2Hl7OrgServerConformanceProvider.getServerConformance(null);
break; break;
case DSTU2: case DSTU2:
ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider dstu2ServerConformanceProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration); 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, null);
myDstu2Conformance = dstu2ServerConformanceProvider.getServerConformance(null);
break; break;
default: default:
throw new ConfigurationException("Unsupported Fhir version: " + fhirContextVersion); 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 * @param theProvider
* an instance of the provider interface * an instance of the provider interface
* @param theProviderInterface * @param theProviderInterface
* the class describing the providers interface * the class describing the providers interface
* @return the numbers of basemethodbindings added * @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 { public int addProvider(IResourceProvider theProvider, Class<? extends IResourceProvider> theProviderInterface) throws ConfigurationException {
int count = 0; 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.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.util.ResourceCountCache; 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.api.ExtensionDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt; import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle; 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.DecimalDt;
import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.Constants; 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.RestfulServer;
import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider; import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider;
import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.CoverageIgnore;
import ca.uhn.fhir.util.ExtensionConstants; import ca.uhn.fhir.util.ExtensionConstants;
import org.hl7.fhir.instance.model.Subscription; 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.ObjectUtils.defaultIfNull;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -87,7 +86,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
} }
@Override @Override
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
Conformance retVal = myCachedValue; Conformance retVal = myCachedValue;
Map<String, Long> counts = null; Map<String, Long> counts = null;
@ -98,7 +97,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
FhirContext ctx = myRestfulServer.getFhirContext(); FhirContext ctx = myRestfulServer.getFhirContext();
retVal = super.getServerConformance(theRequest); retVal = super.getServerConformance(theRequest, theRequestDetails);
for (Rest nextRest : retVal.getRest()) { for (Rest nextRest : retVal.getRest()) {
for (RestResource nextResource : nextRest.getResource()) { 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.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; 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.Constants;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.CoverageIgnore;
import ca.uhn.fhir.util.ExtensionConstants; import ca.uhn.fhir.util.ExtensionConstants;
@ -80,7 +79,7 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
} }
@Override @Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
CapabilityStatement retVal = myCachedValue; CapabilityStatement retVal = myCachedValue;
Map<String, Long> counts = null; 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()); counts = defaultIfNull(counts, Collections.emptyMap());
retVal = super.getServerConformance(theRequest); retVal = super.getServerConformance(theRequest, theRequestDetails);
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) { for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) { 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.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.rest.api.Constants; 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.*;
import org.hl7.fhir.r4.model.CapabilityStatement.*; import org.hl7.fhir.r4.model.CapabilityStatement.*;
import org.hl7.fhir.r4.model.Enumerations.SearchParamType; 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 @Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
CapabilityStatement retVal = myCachedValue; CapabilityStatement retVal = myCachedValue;
Map<String, Long> counts = null; 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()); counts = defaultIfNull(counts, Collections.emptyMap());
retVal = super.getServerConformance(theRequest); retVal = super.getServerConformance(theRequest, theRequestDetails);
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) { for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) { 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 javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
public interface IServerConformanceProvider<T extends 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 * 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 * 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() { public RestfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration result = new RestulfulServerConfiguration(); RestfulServerConfiguration result = new RestfulServerConfiguration();
result.setResourceBindings(getResourceBindings()); result.setResourceBindings(getResourceBindings());
result.setServerBindings(getServerBindings()); result.setServerBindings(getServerBindings());
result.setImplementationDescription(getImplementationDescription()); 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.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.IBaseConformance;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
@ -40,13 +42,20 @@ import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding { 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); super(theMethod.getReturnType(), theMethod, theContext, theProvider);
// if (Modifier.isAbstract(theMethod.getReturnType().getModifiers())) {
// throw new ConfigurationException("Conformance resource provider method '" + theMethod.getName() + "' must not be abstract");
// }
MethodReturnTypeEnum methodReturnType = getMethodReturnType(); MethodReturnTypeEnum methodReturnType = getMethodReturnType();
Class<?> genericReturnType = (Class<?>) theMethod.getGenericReturnType(); Class<?> genericReturnType = (Class<?>) theMethod.getGenericReturnType();
if (methodReturnType != MethodReturnTypeEnum.RESOURCE || !IBaseConformance.class.isAssignableFrom(genericReturnType)) { if (methodReturnType != MethodReturnTypeEnum.RESOURCE || !IBaseConformance.class.isAssignableFrom(genericReturnType)) {
@ -62,7 +71,22 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding
@Override @Override
public IBundleProvider invokeServer(IRestfulServer<?> theServer, RequestDetails theRequest, Object[] theMethodParams) throws BaseServerResponseException { 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); 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; 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.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/* /*
* #%L * #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
@ -10,9 +45,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,54 +55,14 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
* limitations under the License. * limitations under the License.
* #L% * #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 * 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 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 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 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 * Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/ */
@Deprecated
public ServerConformanceProvider(RestfulServer theRestfulServer) { public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration; this();
} }
/** /**
* Constructor * Constructor
*/ */
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) { public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration; super(theServerConfiguration);
} }
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) { 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<>(); Map<String, List<BaseMethodBinding<?>>> resourceToMethods = new TreeMap<>();
for (ResourceBinding next : getServerConfiguration().getResourceBindings()) { for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) {
String resourceName = next.getResourceName(); String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) { for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
@ -122,7 +120,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
resourceToMethods.get(resourceName).add(nextMethodBinding); resourceToMethods.get(resourceName).add(nextMethodBinding);
} }
} }
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) { for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = ""; String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>()); resourceToMethods.put(resourceName, new ArrayList<>());
@ -132,8 +130,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return resourceToMethods; return resourceToMethods;
} }
private DateTimeType conformanceDate() { private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate(); IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) { if (buildDate != null && buildDate.getValue() != null) {
try { try {
return new DateTimeType(buildDate.getValueAsString()); return new DateTimeType(buildDate.getValueAsString());
@ -173,32 +171,32 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return myPublisher; return myPublisher;
} }
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override @Override
@Metadata @Metadata
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
if (myConformance != null && myCache) { RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
return myConformance; Bindings bindings = serverConfiguration.provideBindings();
}
Conformance retVal = new Conformance(); Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher); retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate()); retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU2_1.getFhirVersionString()); retVal.setFhirVersion(FhirVersionEnum.DSTU2_1.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big
// effort since the parser // effort since the parser
// needs to be modified to actually allow it // needs to be modified to actually allow it
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE)); 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 retVal
.getImplementation() .getImplementation()
.setUrl(serverBase) .setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription()); .setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(ConformanceStatementKind.INSTANCE); retVal.setKind(ConformanceStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName()); retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion()); retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML); retVal.addFormat(Constants.CT_FHIR_XML);
retVal.addFormat(Constants.CT_FHIR_JSON); retVal.addFormat(Constants.CT_FHIR_JSON);
retVal.setStatus(ConformanceResourceStatus.ACTIVE); retVal.setStatus(ConformanceResourceStatus.ACTIVE);
@ -209,14 +207,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Set<SystemRestfulInteraction> systemOps = new HashSet<>(); Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = 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()) { for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) { if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>(); Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
ConformanceRestResourceComponent resource = rest.addResource(); ConformanceRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey(); String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName()); resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference((def.getResourceProfile(serverBase))); resource.getProfile().setReference((def.getResourceProfile(serverBase)));
@ -274,10 +272,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof SearchMethodBinding) { 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) { } else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
// Only add each operation (by name) once // Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName)); 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); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) { if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
ourLog.debug("Found bound operation: {}", opName); ourLog.debug("Found bound operation: {}", opName);
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + 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; return retVal;
} }
private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) { SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes()); includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters(); List<IParameter> params = searchMethodBinding.getParameters();
@ -395,7 +392,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode()); param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
} }
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) { for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) { if (targetDef != null) {
ResourceType code; ResourceType code;
try { 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) @Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) { public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) { if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId); 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()) { if (sharedDescriptions == null || sharedDescriptions.isEmpty()) {
throw new ResourceNotFoundException(theId); throw new ResourceNotFoundException(theId);
} }
@ -457,8 +431,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
op.setInstance(false); op.setInstance(false);
op.setSystem(false); op.setSystem(false);
Set<String> inParams = new HashSet<String>(); Set<String> inParams = new HashSet<>();
Set<String> outParams = new HashSet<String>(); Set<String> outParams = new HashSet<>();
for (OperationMethodBinding sharedDescription : sharedDescriptions) { for (OperationMethodBinding sharedDescription : sharedDescriptions) {
if (isNotBlank(sharedDescription.getDescription())) { if (isNotBlank(sharedDescription.getDescription())) {
@ -542,9 +516,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
* <p> * <p>
* See the class documentation for an important note if you are extending this class * See the class documentation for an important note if you are extending this class
* </p> * </p>
* @deprecated Since 4.0.0 this does not do anything
*/ */
public void setCache(boolean theCache) { public void setCache(boolean theCache) {
myCache = theCache; // nothing
} }
/** /**
@ -557,24 +532,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
@Override @Override
public void setRestfulServer(RestfulServer theRestfulServer) { public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration; // ignore
}
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());
}
});
} }
private void sortSearchParameters(List<SearchParameter> searchParameters) { private void sortSearchParameters(List<SearchParameter> searchParameters) {

View File

@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest; 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 ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -152,7 +154,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -178,7 +180,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
/* /*
* Check the operation definitions themselves * 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); String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@formatter:off
@ -194,7 +196,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
)); ));
//@formatter:on //@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); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@formatter:off
@ -210,7 +212,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
)); ));
//@formatter:on //@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); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@formatter:off
@ -226,7 +228,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test {
)); ));
//@formatter:on //@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); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@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.model.primitive.IdDt;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam; 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.Metadata;
import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.*;
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.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*; import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; 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.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
@ -36,7 +33,6 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
import java.util.Map.Entry; 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.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; 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 * 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 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() { public ServerConformanceProvider() {
super(); super();
@ -87,16 +73,19 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
/** /**
* Constructor * Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/ */
@Deprecated
public ServerConformanceProvider(RestfulServer theRestfulServer) { public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration; this();
} }
/** /**
* Constructor * Constructor
*/ */
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) { public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration; super(theServerConfiguration);
} }
private void checkBindingForSystemOps(Rest rest, Set<SystemRestfulInteractionEnum> systemOps, BaseMethodBinding<?> nextMethodBinding) { 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<?>>>(); 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(); String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) { for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
@ -126,7 +115,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
resourceToMethods.get(resourceName).add(nextMethodBinding); resourceToMethods.get(resourceName).add(nextMethodBinding);
} }
} }
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) { for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = ""; String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>()); resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>());
@ -136,8 +125,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return resourceToMethods; return resourceToMethods;
} }
private DateTimeDt conformanceDate() { private DateTimeDt conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate(); IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) { if (buildDate != null && buildDate.getValue() != null) {
try { try {
return new DateTimeDt(buildDate.getValueAsString()); return new DateTimeDt(buildDate.getValueAsString());
@ -185,39 +174,31 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
myPublisher = thePublisher; myPublisher = thePublisher;
} }
RestulfulServerConfiguration getServerConfiguration() { @SuppressWarnings("EnumSwitchStatementWhichMissesCases")
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@Override @Override
@Metadata @Metadata
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
if (myConformance != null && myCache) { RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
return myConformance; Bindings bindings = serverConfiguration.provideBindings();
}
Conformance retVal = new Conformance(); Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher); retVal.setPublisher(myPublisher);
retVal.setDate(conformanceDate()); retVal.setDate(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU2.getFhirVersionString()); retVal.setFhirVersion(FhirVersionEnum.DSTU2.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCodeEnum.UNKNOWN_EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser 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 // needs to be modified to actually allow it
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE)); 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 retVal
.getImplementation() .getImplementation()
.setUrl(serverBase) .setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription()); .setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(ConformanceStatementKindEnum.INSTANCE); retVal.setKind(ConformanceStatementKindEnum.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName()); retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion()); retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML); retVal.addFormat(Constants.CT_FHIR_XML);
retVal.addFormat(Constants.CT_FHIR_JSON); retVal.addFormat(Constants.CT_FHIR_JSON);
@ -227,14 +208,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Set<SystemRestfulInteractionEnum> systemOps = new HashSet<>(); Set<SystemRestfulInteractionEnum> systemOps = new HashSet<>();
Set<String> operationNames = 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()) { for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) { if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteractionEnum> resourceOps = new HashSet<>(); Set<TypeRestfulInteractionEnum> resourceOps = new HashSet<>();
RestResource resource = rest.addResource(); RestResource resource = rest.addResource();
String resourceName = nextEntry.getKey(); String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName()); resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference(new IdDt(def.getResourceProfile(serverBase))); resource.getProfile().setReference(new IdDt(def.getResourceProfile(serverBase)));
@ -287,10 +268,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof SearchMethodBinding) { if (nextMethodBinding instanceof SearchMethodBinding) {
handleSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding); handleSearchMethodBinding(resource, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
} else if (nextMethodBinding instanceof OperationMethodBinding) { } else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
// Only add each operation (by name) once // Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).getDefinition().setReference("OperationDefinition/" + opName); 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); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) { if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
rest.addOperation().setName(methodBinding.getName().substring(1)).getDefinition().setReference("OperationDefinition/" + 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; 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()); includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters(); List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>(); List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) { for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) { if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter); searchParameters.add((SearchParameter) nextParameter);
@ -401,7 +381,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.addChain(chain); param.addChain(chain);
} else { } else {
if (nextParameter.getParamType() == RestSearchParameterTypeEnum.REFERENCE) { if (nextParameter.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
for (String nextWhitelist : new TreeSet<String>(nextParameter.getQualifierWhitelist())) { for (String nextWhitelist : new TreeSet<>(nextParameter.getQualifierWhitelist())) {
if (nextWhitelist.startsWith(".")) { if (nextWhitelist.startsWith(".")) {
param.addChain(nextWhitelist.substring(1)); param.addChain(nextWhitelist.substring(1));
} }
@ -414,7 +394,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode()); param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
} }
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) { for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) { if (targetDef != null) {
ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName()); ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName());
if (code != null) { 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) @Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdDt theId) { public OperationDefinition readOperationDefinition(@IdParam IdDt theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) { if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId); 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()) { if (sharedDescriptions == null || sharedDescriptions.isEmpty()) {
throw new ResourceNotFoundException(theId); throw new ResourceNotFoundException(theId);
} }
@ -467,8 +425,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
op.setKind(OperationKindEnum.OPERATION); op.setKind(OperationKindEnum.OPERATION);
op.setIdempotent(true); op.setIdempotent(true);
Set<String> inParams = new HashSet<String>(); Set<String> inParams = new HashSet<>();
Set<String> outParams = new HashSet<String>(); Set<String> outParams = new HashSet<>();
for (OperationMethodBinding sharedDescription : sharedDescriptions) { for (OperationMethodBinding sharedDescription : sharedDescriptions) {
if (isNotBlank(sharedDescription.getDescription())) { if (isNotBlank(sharedDescription.getDescription())) {
@ -543,23 +501,16 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
* <p> * <p>
* See the class documentation for an important note if you are extending this class * See the class documentation for an important note if you are extending this class
* </p> * </p>
* @deprecated Since 4.0.0 this does nothing
*/ */
@Deprecated
public void setCache(boolean theCache) { public void setCache(boolean theCache) {
myCache = theCache; // nothing
} }
@Override @Override
public void setRestfulServer(RestfulServer theRestfulServer) { public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration; // nothing
}
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) { private void sortSearchParameters(List<SearchParameter> searchParameters) {

View File

@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest; 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 ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -145,7 +147,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -170,7 +172,7 @@ public class OperationServerWithSearchParamTypesDstu2Test {
/* /*
* Check the operation definitions themselves * 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); String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@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.ServletException;
import javax.servlet.http.HttpServletRequest; 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.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Test; import org.junit.Test;
@ -104,7 +106,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -127,7 +129,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -149,7 +151,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); 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); validate(opDef);
assertEquals("everything", opDef.getCode()); assertEquals("everything", opDef.getCode());
@ -167,7 +169,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -200,7 +202,7 @@ public class ServerConformanceProviderDstu2Test {
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -220,7 +222,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -243,7 +245,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); 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")); 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); validate(opDef);
Set<String> types = toStrings(opDef.getType()); Set<String> types = toStrings(opDef.getType());
@ -271,7 +273,7 @@ public class ServerConformanceProviderDstu2Test {
assertEquals("Patient", opDef.getParameter().get(1).getType()); 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); validate(opDef);
Set<String> types = toStrings(opDef.getType()); Set<String> types = toStrings(opDef.getType());
@ -286,7 +288,7 @@ public class ServerConformanceProviderDstu2Test {
assertEquals("Encounter", opDef.getParameter().get(1).getType()); 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); validate(opDef);
Set<String> types = toStrings(opDef.getType()); Set<String> types = toStrings(opDef.getType());
@ -311,7 +313,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info("AAAAAA" + conf); ourLog.info("AAAAAA" + conf);
@ -328,18 +330,18 @@ public class ServerConformanceProviderDstu2Test {
ServerConformanceProvider sc = new ServerConformanceProvider(rs) { ServerConformanceProvider sc = new ServerConformanceProvider(rs) {
@Override @Override
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest); return super.getServerConformance(theRequest, theRequestDetails);
} }
}; };
rs.setServerConformanceProvider(sc); rs.setServerConformanceProvider(sc);
rs.init(createServletConfig()); 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()); 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); validate(opDef);
assertEquals("plain", opDef.getCode()); assertEquals("plain", opDef.getCode());
@ -366,8 +368,8 @@ public class ServerConformanceProviderDstu2Test {
ServerConformanceProvider sc = new ServerConformanceProvider(rs) { ServerConformanceProvider sc = new ServerConformanceProvider(rs) {
@Override @Override
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
Conformance conformance = super.getServerConformance(theRequest); Conformance conformance = super.getServerConformance(theRequest, theRequestDetails);
ExtensionDt extensionDt = new ExtensionDt(); ExtensionDt extensionDt = new ExtensionDt();
ExtensionDt extensionDtToken = new ExtensionDt(); ExtensionDt extensionDtToken = new ExtensionDt();
ExtensionDt extensionDtAuthorize = new ExtensionDt(); ExtensionDt extensionDtAuthorize = new ExtensionDt();
@ -392,7 +394,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -410,7 +412,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -440,7 +442,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -460,7 +462,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -496,7 +498,7 @@ public class ServerConformanceProviderDstu2Test {
} }
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -532,7 +534,7 @@ public class ServerConformanceProviderDstu2Test {
} }
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -566,7 +568,7 @@ public class ServerConformanceProviderDstu2Test {
} }
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -602,7 +604,7 @@ public class ServerConformanceProviderDstu2Test {
} }
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -629,7 +631,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -648,7 +650,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -667,7 +669,7 @@ public class ServerConformanceProviderDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
ValidationResult result = ourCtx.newValidator().validateWithResult(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.context.RuntimeSearchParam;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam; 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.Metadata;
import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.*;
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.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*; import ca.uhn.fhir.rest.server.method.*;
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
import ca.uhn.fhir.rest.server.method.SearchParameter; import ca.uhn.fhir.rest.server.method.SearchParameter;
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.CapabilityStatement.*; import org.hl7.fhir.dstu3.model.CapabilityStatement.*;
@ -33,7 +30,6 @@ import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
import java.util.Map.Entry; 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.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; 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. * <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> * </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 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 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. * 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 * Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/ */
@Deprecated
public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) { public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration; this();
} }
/** /**
* Constructor * Constructor - This is intended only for JAX-RS server
*/ */
public ServerCapabilityStatementProvider(RestulfulServerConfiguration theServerConfiguration) { public ServerCapabilityStatementProvider(RestfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration; super(theServerConfiguration);
} }
private void checkBindingForSystemOps(CapabilityStatementRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) { 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<?>>>(); 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(); String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) { for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
@ -131,7 +123,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
resourceToMethods.get(resourceName).add(nextMethodBinding); resourceToMethods.get(resourceName).add(nextMethodBinding);
} }
} }
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) { for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = ""; String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<>()); resourceToMethods.put(resourceName, new ArrayList<>());
@ -141,8 +133,8 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
return resourceToMethods; return resourceToMethods;
} }
private DateTimeType conformanceDate() { private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate(); IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) { if (buildDate != null && buildDate.getValue() != null) {
try { try {
return new DateTimeType(buildDate.getValueAsString()); return new DateTimeType(buildDate.getValueAsString());
@ -201,40 +193,33 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
myPublisher = thePublisher; myPublisher = thePublisher;
} }
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override @Override
@Metadata @Metadata
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
if (myCapabilityStatement != null && myCache) { RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
return myCapabilityStatement; Bindings bindings = serverConfiguration.provideBindings();
}
CapabilityStatement retVal = new CapabilityStatement(); CapabilityStatement retVal = new CapabilityStatement();
retVal.setPublisher(myPublisher); retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate()); retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU3.getFhirVersionString()); retVal.setFhirVersion(FhirVersionEnum.DSTU3.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big
// effort since the parser // effort since the parser
// needs to be modified to actually allow it // needs to be modified to actually allow it
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE)); 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 retVal
.getImplementation() .getImplementation()
.setUrl(serverBase) .setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription()); .setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(CapabilityStatementKind.INSTANCE); retVal.setKind(CapabilityStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName()); retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion()); retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML_NEW); retVal.addFormat(Constants.CT_FHIR_XML_NEW);
retVal.addFormat(Constants.CT_FHIR_JSON_NEW); retVal.addFormat(Constants.CT_FHIR_JSON_NEW);
retVal.setStatus(PublicationStatus.ACTIVE); retVal.setStatus(PublicationStatus.ACTIVE);
@ -245,14 +230,14 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
Set<SystemRestfulInteraction> systemOps = new HashSet<>(); Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = 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()) { for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) { if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>(); Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource(); CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey(); String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName()); resource.getTypeElement().setValue(def.getName());
resource.getProfile().setReference((def.getResourceProfile(serverBase))); resource.getProfile().setReference((def.getResourceProfile(serverBase)));
@ -312,16 +297,16 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
if (nextMethodBinding instanceof SearchMethodBinding) { if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding; SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (methodBinding.getQueryName() != null) { if (methodBinding.getQueryName() != null) {
String queryName = myNamedSearchMethodBindingToName.get(methodBinding); String queryName = bindings.getNamedSearchMethodBindingToName().get(methodBinding);
if (operationNames.add(queryName)) { if (operationNames.add(queryName)) {
rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(new Reference("OperationDefinition/" + queryName)); rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(new Reference("OperationDefinition/" + queryName));
} }
} else { } else {
handleNamelessSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding); handleNamelessSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
} }
} else if (nextMethodBinding instanceof OperationMethodBinding) { } else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
// Only add each operation (by name) once // Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + opName)); 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); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) { if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
ourLog.debug("Found bound operation: {}", opName); ourLog.debug("Found bound operation: {}", opName);
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(new Reference("OperationDefinition/" + 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; return retVal;
} }
private void handleNamelessSearchMethodBinding(CapabilityStatementRestComponent rest, CapabilityStatementRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, private void handleNamelessSearchMethodBinding(CapabilityStatementRestComponent rest, CapabilityStatementRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) { SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes()); includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters(); List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>(); List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) { for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) { if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter); searchParameters.add((SearchParameter) nextParameter);
@ -440,7 +426,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode()); param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
} }
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) { for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) { if (targetDef != null) {
ResourceType code; ResourceType code;
try { 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) @Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) { public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) { if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId); 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()) { if (operationBindings != null && !operationBindings.isEmpty()) {
return readOperationDefinitionForOperation(operationBindings); return readOperationDefinitionForOperation(operationBindings);
} }
List<SearchMethodBinding> searchBindings = mySearchNameToBindings.get(theId.getIdPart()); List<SearchMethodBinding> searchBindings = bindings.getSearchNameToBindings().get(theId.getIdPart());
if (searchBindings != null && !searchBindings.isEmpty()) { if (searchBindings != null && !searchBindings.isEmpty()) {
return readOperationDefinitionForNamedSearch(searchBindings); return readOperationDefinitionForNamedSearch(searchBindings);
} }
@ -667,24 +615,16 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
* <p> * <p>
* See the class documentation for an important note if you are extending this class * See the class documentation for an important note if you are extending this class
* </p> * </p>
*
* @deprecated Since 4.0.0 this doesn't do anything
*/ */
public ServerCapabilityStatementProvider setCache(boolean theCache) { public ServerCapabilityStatementProvider setCache(boolean theCache) {
myCache = theCache;
return this; return this;
} }
@Override @Override
public void setRestfulServer(RestfulServer theRestfulServer) { public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration; // ignore
}
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) { private void sortSearchParameters(List<SearchParameter> searchParameters) {

View File

@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest; 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 ca.uhn.fhir.test.utilities.JettyUtil;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
@ -152,7 +154,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -178,7 +180,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
/* /*
* Check the operation definitions themselves * 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); String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@formatter:off
@ -194,7 +196,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
)); ));
//@formatter:on //@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); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@formatter:off
@ -210,7 +212,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
)); ));
//@formatter:on //@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); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@formatter:off
@ -226,7 +228,7 @@ public class OperationServerWithSearchParamTypesDstu3Test {
)); ));
//@formatter:on //@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); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef);
ourLog.info(def); ourLog.info(def);
//@formatter:off //@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.MethodOutcome;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider; 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.param.*;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer; 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.BaseMethodBinding;
import ca.uhn.fhir.rest.server.method.IParameter; import ca.uhn.fhir.rest.server.method.IParameter;
import ca.uhn.fhir.rest.server.method.SearchMethodBinding; import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchParameter; 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.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
@ -106,7 +108,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -134,7 +136,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -157,7 +159,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -165,7 +167,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertEquals(1, conformance.getRest().get(0).getOperation().size()); assertEquals(1, conformance.getRest().get(0).getOperation().size());
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName()); 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); validate(opDef);
assertEquals("everything", opDef.getCode()); assertEquals("everything", opDef.getCode());
assertThat(opDef.getSystem(), is(false)); assertThat(opDef.getSystem(), is(false));
@ -185,7 +187,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); 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); validate(opDef);
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
@ -206,7 +208,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -238,7 +240,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -258,7 +260,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -283,7 +285,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); 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")); 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); validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource()); Set<String> types = toStrings(opDef.getResource());
@ -311,7 +313,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertEquals("Patient", opDef.getParameter().get(1).getType()); 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); validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource()); Set<String> types = toStrings(opDef.getResource());
@ -326,7 +328,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertEquals("Encounter", opDef.getParameter().get(1).getType()); 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); validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource()); Set<String> types = toStrings(opDef.getResource());
@ -351,7 +353,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
@ -367,15 +369,15 @@ public class ServerCapabilityStatementProviderDstu3Test {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) { ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
@Override @Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest); return super.getServerConformance(theRequest, createRequestDetails(rs));
} }
}; };
rs.setServerConformanceProvider(sc); rs.setServerConformanceProvider(sc);
rs.init(createServletConfig()); 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); validate(opDef);
assertEquals("plain", opDef.getCode()); assertEquals("plain", opDef.getCode());
@ -410,7 +412,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -440,7 +442,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -460,7 +462,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -496,7 +498,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -532,7 +534,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -565,7 +567,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -583,8 +585,8 @@ public class ServerCapabilityStatementProviderDstu3Test {
RestfulServer rsNoType = new RestfulServer(ourCtx) { RestfulServer rsNoType = new RestfulServer(ourCtx) {
@Override @Override
public RestulfulServerConfiguration createConfiguration() { public RestfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration(); RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z")); retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal; return retVal;
} }
@ -594,14 +596,14 @@ public class ServerCapabilityStatementProviderDstu3Test {
rsNoType.setServerConformanceProvider(scNoType); rsNoType.setServerConformanceProvider(scNoType);
rsNoType.init(createServletConfig()); rsNoType.init(createServletConfig());
CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsNoType));
String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(confNoType); ourLog.info(confNoType);
RestfulServer rsWithType = new RestfulServer(ourCtx) { RestfulServer rsWithType = new RestfulServer(ourCtx) {
@Override @Override
public RestulfulServerConfiguration createConfiguration() { public RestfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration(); RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z")); retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal; return retVal;
} }
@ -611,7 +613,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rsWithType.setServerConformanceProvider(scWithType); rsWithType.setServerConformanceProvider(scWithType);
rsWithType.init(createServletConfig()); rsWithType.init(createServletConfig());
CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest()); CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsWithType));
String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType); String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType);
ourLog.info(confWithType); ourLog.info(confWithType);
@ -630,7 +632,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -649,7 +651,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -668,7 +670,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance); ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
@ -685,7 +687,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0); CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -695,7 +697,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
String operationReference = operationComponent.getDefinition().getReference(); String operationReference = operationComponent.getDefinition().getReference();
assertThat(operationReference, not(nullValue())); 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)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition); validate(operationDefinition);
assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME)); assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME));
@ -729,7 +731,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0); CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -737,7 +739,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
String operationReference = operationComponent.getDefinition().getReference(); String operationReference = operationComponent.getDefinition().getReference();
assertThat(operationReference, not(nullValue())); 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)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition); validate(operationDefinition);
assertThat("The operation name should be the code if no description is set", operationDefinition.getName(), is(NamedQueryResourceProvider.QUERY_NAME)); 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()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -781,7 +783,7 @@ public class ServerCapabilityStatementProviderDstu3Test {
assertThat(operations.size(), is(1)); assertThat(operations.size(), is(1));
assertThat(operations.get(0).getName(), is(TypeLevelOperationProvider.OPERATION_NAME)); 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); validate(opDef);
assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode()); assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode());
assertThat(opDef.getSystem(), is(false)); assertThat(opDef.getSystem(), is(false));
@ -1157,4 +1159,10 @@ public class ServerCapabilityStatementProviderDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest(); 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 static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.text.*;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.Callable;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.parser.DataFormatException; 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.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.*; import org.hl7.fhir.instance.model.*;
import org.hl7.fhir.instance.model.Conformance.*; import org.hl7.fhir.instance.model.Conformance.*;
@ -65,14 +64,9 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
* constructor. * constructor.
* </p> * </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 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 seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
@ -83,31 +77,26 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
/** /**
* Constructor * Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/ */
@Deprecated
public ServerConformanceProvider(RestfulServer theRestfulServer) { public ServerConformanceProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration; this();
} }
/** /**
* Constructor * Constructor
*/ */
public ServerConformanceProvider(RestulfulServerConfiguration theServerConfiguration) { public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration; super(theServerConfiguration);
} }
@Override @Override
public void setRestfulServer (RestfulServer theRestfulServer) { public void setRestfulServer (RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration; // ignore
} }
RestulfulServerConfiguration getServerConfiguration() {
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps, private void checkBindingForSystemOps(ConformanceRestComponent rest, Set<SystemRestfulInteraction> systemOps,
BaseMethodBinding<?> nextMethodBinding) { BaseMethodBinding<?> nextMethodBinding) {
if (nextMethodBinding.getRestOperationType() != null) { if (nextMethodBinding.getRestOperationType() != null) {
@ -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<?>>>(); 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(); String resourceName = next.getResourceName();
for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) { for (BaseMethodBinding<?> nextMethodBinding : next.getMethodBindings()) {
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
@ -141,10 +130,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
resourceToMethods.get(resourceName).add(nextMethodBinding); resourceToMethods.get(resourceName).add(nextMethodBinding);
} }
} }
for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration().getServerBindings()) { for (BaseMethodBinding<?> nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) {
String resourceName = ""; String resourceName = "";
if (resourceToMethods.containsKey(resourceName) == false) { if (resourceToMethods.containsKey(resourceName) == false) {
resourceToMethods.put(resourceName, new ArrayList<BaseMethodBinding<?>>()); resourceToMethods.put(resourceName, new ArrayList<>());
} }
resourceToMethods.get(resourceName).add(nextMethodBinding); resourceToMethods.get(resourceName).add(nextMethodBinding);
} }
@ -166,45 +155,45 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return myPublisher; return myPublisher;
} }
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
@Override @Override
@Metadata @Metadata
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
if (myConformance != null && myCache) { RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails);
return myConformance; Bindings bindings = serverConfiguration.provideBindings();
}
Conformance retVal = new Conformance(); Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher); retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate()); retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(FhirVersionEnum.DSTU2_HL7ORG.getFhirVersionString()); retVal.setFhirVersion(FhirVersionEnum.DSTU2_HL7ORG.getFhirVersionString());
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser 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 // needs to be modified to actually allow it
retVal.getImplementation().setDescription(getServerConfiguration().getImplementationDescription()); retVal.getImplementation().setDescription(serverConfiguration.getImplementationDescription());
retVal.setKind(ConformanceStatementKind.INSTANCE); retVal.setKind(ConformanceStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName()); retVal.getSoftware().setName(serverConfiguration.getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion()); retVal.getSoftware().setVersion(serverConfiguration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML); retVal.addFormat(Constants.CT_FHIR_XML);
retVal.addFormat(Constants.CT_FHIR_JSON); retVal.addFormat(Constants.CT_FHIR_JSON);
ConformanceRestComponent rest = retVal.addRest(); ConformanceRestComponent rest = retVal.addRest();
rest.setMode(RestfulConformanceMode.SERVER); rest.setMode(RestfulConformanceMode.SERVER);
Set<SystemRestfulInteraction> systemOps = new HashSet<SystemRestfulInteraction>(); Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = new HashSet<String>(); 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()) { for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) { if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<TypeRestfulInteraction>(); Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
ConformanceRestResourceComponent resource = rest.addResource(); ConformanceRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey(); String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName()); resource.getTypeElement().setValue(def.getName());
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE)); 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))); resource.getProfile().setReference((def.getResourceProfile(serverBase)));
TreeSet<String> includes = new TreeSet<>(); TreeSet<String> includes = new TreeSet<>();
@ -258,11 +247,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof SearchMethodBinding) { if (nextMethodBinding instanceof SearchMethodBinding) {
handleSearchMethodBinding(rest, resource, resourceName, def, includes, handleSearchMethodBinding(resource, def, includes,
(SearchMethodBinding) nextMethodBinding); (SearchMethodBinding) nextMethodBinding, theRequestDetails);
} else if (nextMethodBinding instanceof OperationMethodBinding) { } else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
// Only add each operation (by name) once // Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName()).getDefinition() rest.addOperation().setName(methodBinding.getName()).getDefinition()
@ -298,7 +287,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
checkBindingForSystemOps(rest, systemOps, nextMethodBinding); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) { if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
rest.addOperation().setName(methodBinding.getName()).getDefinition() rest.addOperation().setName(methodBinding.getName()).getDefinition()
.setReference("OperationDefinition/" + opName); .setReference("OperationDefinition/" + opName);
@ -308,12 +297,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
} }
} }
myConformance = retVal;
return retVal; return retVal;
} }
private DateTimeType conformanceDate() { private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
IPrimitiveType<Date> buildDate = getServerConfiguration().getConformanceDate(); IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
if (buildDate != null && buildDate.getValue() != null) { if (buildDate != null && buildDate.getValue() != null) {
try { try {
return new DateTimeType(buildDate.getValueAsString()); return new DateTimeType(buildDate.getValueAsString());
@ -324,13 +312,13 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return DateTimeType.now(); return DateTimeType.now();
} }
private void handleSearchMethodBinding(ConformanceRestComponent rest, ConformanceRestResourceComponent resource, private void handleSearchMethodBinding(ConformanceRestResourceComponent resource,
String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) { SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes()); includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters(); List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>(); List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) { for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) { if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter); searchParameters.add((SearchParameter) nextParameter);
@ -388,7 +376,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode()); param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
} }
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) { for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) { if (targetDef != null) {
ResourceType code; ResourceType code;
try { 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) @Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) { public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) { if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId); 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()) { if (sharedDescriptions == null || sharedDescriptions.isEmpty()) {
throw new ResourceNotFoundException(theId); 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 * See the class documentation for an important note if you are extending this
* class * class
* </p> * </p>
* @deprecated Since 4.0.0 this method doesn't do anything
*/ */
@Deprecated
public void setCache(boolean theCache) { public void setCache(boolean theCache) {
myCache = theCache; // nothing
} }
/** /**
@ -524,15 +490,6 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
myPublisher = thePublisher; 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) { private void sortSearchParameters(List<SearchParameter> searchParameters) {
Collections.sort(searchParameters, new Comparator<SearchParameter>() { Collections.sort(searchParameters, new Comparator<SearchParameter>() {
@Override @Override

View File

@ -14,6 +14,8 @@ import java.util.*;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest; 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.conf.ServerConformanceProvider;
import org.hl7.fhir.instance.model.*; import org.hl7.fhir.instance.model.*;
import org.hl7.fhir.instance.model.Conformance.*; import org.hl7.fhir.instance.model.Conformance.*;
@ -62,7 +64,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -85,14 +87,14 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
assertEquals(1, conformance.getRest().get(0).getOperation().size()); assertEquals(1, conformance.getRest().get(0).getOperation().size());
assertEquals("$everything", conformance.getRest().get(0).getOperation().get(0).getName()); 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()); 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); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
ourLog.info(conf); ourLog.info(conf);
@ -127,7 +129,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -159,7 +161,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -179,7 +181,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -214,7 +216,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
} }
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -231,18 +233,18 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
ServerConformanceProvider sc = new ServerConformanceProvider(rs) { ServerConformanceProvider sc = new ServerConformanceProvider(rs) {
@Override @Override
public Conformance getServerConformance(HttpServletRequest theRequest) { public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest); return super.getServerConformance(theRequest, theRequestDetails);
} }
}; };
rs.setServerConformanceProvider(sc); rs.setServerConformanceProvider(sc);
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance sconf = sc.getServerConformance(createHttpServletRequest()); Conformance sconf = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
assertEquals("OperationDefinition/plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference()); 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); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
ourLog.info(conf); ourLog.info(conf);
@ -273,7 +275,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -303,7 +305,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -323,7 +325,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -355,7 +357,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
} }
} }
assertTrue(found); assertTrue(found);
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -376,7 +378,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -395,7 +397,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -414,7 +416,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
Conformance conformance = sc.getServerConformance(createHttpServletRequest()); Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
assertTrue(ourCtx.newValidator().validateWithResult(conformance).isSuccessful()); 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.context.RuntimeSearchParam;
import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.annotation.IdParam; 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.Metadata;
import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.IServerConformanceProvider; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.*;
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.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.method.*; 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.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.apache.commons.lang3.StringUtils;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource; 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.OperationDefinitionParameterComponent;
import org.hl7.fhir.r4.model.OperationDefinition.OperationKind; import org.hl7.fhir.r4.model.OperationDefinition.OperationKind;
import org.hl7.fhir.r4.model.OperationDefinition.OperationParameterUse; import org.hl7.fhir.r4.model.OperationDefinition.OperationParameterUse;
import org.hl7.fhir.r4.model.codesystems.UnknownContentCode;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
import java.util.Map.Entry; 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.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank; 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. * <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> * </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 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 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. * 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 * Constructor
*
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
*/ */
@Deprecated
public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) { public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) {
this.myServerConfiguration = theRestfulServer::createConfiguration; this();
} }
/** /**
* Constructor * Constructor - This is intended only for JAX-RS server
*/ */
public ServerCapabilityStatementProvider(RestulfulServerConfiguration theServerConfiguration) { public ServerCapabilityStatementProvider(RestfulServerConfiguration theServerConfiguration) {
this.myServerConfiguration = () -> theServerConfiguration; super(theServerConfiguration);
} }
private void checkBindingForSystemOps(CapabilityStatementRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) { 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) { if (buildDate != null && buildDate.getValue() != null) {
try { try {
return new DateTimeType(buildDate.getValueAsString()); return new DateTimeType(buildDate.getValueAsString());
@ -154,37 +126,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
return DateTimeType.now(); 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 * 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; myPublisher = thePublisher;
} }
RestulfulServerConfiguration getServerConfiguration() { @SuppressWarnings("EnumSwitchStatementWhichMissesCases")
try {
return myServerConfiguration.call();
} catch (Exception e) {
throw new InternalErrorException(e);
}
}
@Override @Override
@Metadata @Metadata
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
if (myCapabilityStatement != null && myCache) {
return myCapabilityStatement; RestfulServerConfiguration configuration = getServerConfiguration(theRequestDetails);
} Bindings bindings = configuration.provideBindings();
CapabilityStatement retVal = new CapabilityStatement(); CapabilityStatement retVal = new CapabilityStatement();
retVal.setPublisher(myPublisher); retVal.setPublisher(myPublisher);
retVal.setDateElement(conformanceDate()); retVal.setDateElement(conformanceDate(theRequestDetails));
retVal.setFhirVersion(Enumerations.FHIRVersion.fromCode(FhirVersionEnum.R4.getFhirVersionString())); retVal.setFhirVersion(Enumerations.FHIRVersion.fromCode(FhirVersionEnum.R4.getFhirVersionString()));
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE)); 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 retVal
.getImplementation() .getImplementation()
.setUrl(serverBase) .setUrl(serverBase)
.setDescription(getServerConfiguration().getImplementationDescription()); .setDescription(configuration.getImplementationDescription());
retVal.setKind(CapabilityStatementKind.INSTANCE); retVal.setKind(CapabilityStatementKind.INSTANCE);
retVal.getSoftware().setName(getServerConfiguration().getServerName()); retVal.getSoftware().setName(configuration.getServerName());
retVal.getSoftware().setVersion(getServerConfiguration().getServerVersion()); retVal.getSoftware().setVersion(configuration.getServerVersion());
retVal.addFormat(Constants.CT_FHIR_XML_NEW); retVal.addFormat(Constants.CT_FHIR_XML_NEW);
retVal.addFormat(Constants.CT_FHIR_JSON_NEW); retVal.addFormat(Constants.CT_FHIR_JSON_NEW);
retVal.setStatus(PublicationStatus.ACTIVE); retVal.setStatus(PublicationStatus.ACTIVE);
@ -243,14 +178,14 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
Set<SystemRestfulInteraction> systemOps = new HashSet<>(); Set<SystemRestfulInteraction> systemOps = new HashSet<>();
Set<String> operationNames = 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()) { for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
if (nextEntry.getKey().isEmpty() == false) { if (nextEntry.getKey().isEmpty() == false) {
Set<TypeRestfulInteraction> resourceOps = new HashSet<>(); Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
CapabilityStatementRestResourceComponent resource = rest.addResource(); CapabilityStatementRestResourceComponent resource = rest.addResource();
String resourceName = nextEntry.getKey(); String resourceName = nextEntry.getKey();
RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); RuntimeResourceDefinition def = configuration.getFhirContext().getResourceDefinition(resourceName);
resource.getTypeElement().setValue(def.getName()); resource.getTypeElement().setValue(def.getName());
resource.getProfileElement().setValue((def.getResourceProfile(serverBase))); resource.getProfileElement().setValue((def.getResourceProfile(serverBase)));
@ -310,16 +245,16 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
if (nextMethodBinding instanceof SearchMethodBinding) { if (nextMethodBinding instanceof SearchMethodBinding) {
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding; SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
if (methodBinding.getQueryName() != null) { if (methodBinding.getQueryName() != null) {
String queryName = myNamedSearchMethodBindingToName.get(methodBinding); String queryName = bindings.getNamedSearchMethodBindingToName().get(methodBinding);
if (operationNames.add(queryName)) { if (operationNames.add(queryName)) {
rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(("OperationDefinition/" + queryName)); rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(("OperationDefinition/" + queryName));
} }
} else { } else {
handleNamelessSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding); handleNamelessSearchMethodBinding(resource, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
} }
} else if (nextMethodBinding instanceof OperationMethodBinding) { } else if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
// Only add each operation (by name) once // Only add each operation (by name) once
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName)); rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName));
@ -354,7 +289,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
checkBindingForSystemOps(rest, systemOps, nextMethodBinding); checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
if (nextMethodBinding instanceof OperationMethodBinding) { if (nextMethodBinding instanceof OperationMethodBinding) {
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
String opName = myOperationBindingToName.get(methodBinding); String opName = bindings.getOperationBindingToName().get(methodBinding);
if (operationNames.add(opName)) { if (operationNames.add(opName)) {
ourLog.debug("Found bound operation: {}", opName); ourLog.debug("Found bound operation: {}", opName);
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName)); rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName));
@ -364,16 +299,15 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
} }
} }
myCapabilityStatement = retVal;
return retVal; return retVal;
} }
private void handleNamelessSearchMethodBinding(CapabilityStatementRestComponent rest, CapabilityStatementRestResourceComponent resource, String resourceName, RuntimeResourceDefinition def, TreeSet<String> includes, private void handleNamelessSearchMethodBinding(CapabilityStatementRestResourceComponent resource, RuntimeResourceDefinition def, TreeSet<String> includes,
SearchMethodBinding searchMethodBinding) { SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
includes.addAll(searchMethodBinding.getIncludes()); includes.addAll(searchMethodBinding.getIncludes());
List<IParameter> params = searchMethodBinding.getParameters(); List<IParameter> params = searchMethodBinding.getParameters();
List<SearchParameter> searchParameters = new ArrayList<SearchParameter>(); List<SearchParameter> searchParameters = new ArrayList<>();
for (IParameter nextParameter : params) { for (IParameter nextParameter : params) {
if ((nextParameter instanceof SearchParameter)) { if ((nextParameter instanceof SearchParameter)) {
searchParameters.add((SearchParameter) nextParameter); searchParameters.add((SearchParameter) nextParameter);
@ -438,7 +372,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode()); param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
} }
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) { for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
if (targetDef != null) { if (targetDef != null) {
ResourceType code; ResourceType code;
try { 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) @Read(type = OperationDefinition.class)
public OperationDefinition readOperationDefinition(@IdParam IdType theId) { public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
if (theId == null || theId.hasIdPart() == false) { if (theId == null || theId.hasIdPart() == false) {
throw new ResourceNotFoundException(theId); 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()) { if (operationBindings != null && !operationBindings.isEmpty()) {
return readOperationDefinitionForOperation(operationBindings); return readOperationDefinitionForOperation(operationBindings);
} }
List<SearchMethodBinding> searchBindings = mySearchNameToBindings.get(theId.getIdPart()); List<SearchMethodBinding> searchBindings = bindings.getSearchNameToBindings().get(theId.getIdPart());
if (searchBindings != null && !searchBindings.isEmpty()) { if (searchBindings != null && !searchBindings.isEmpty()) {
return readOperationDefinitionForNamedSearch(searchBindings); return readOperationDefinitionForNamedSearch(searchBindings);
} }
@ -665,15 +560,17 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
* <p> * <p>
* See the class documentation for an important note if you are extending this class * See the class documentation for an important note if you are extending this class
* </p> * </p>
*
* @deprecated Since 4.0.0 - This method no longer does anything
*/ */
@Deprecated
public ServerCapabilityStatementProvider setCache(boolean theCache) { public ServerCapabilityStatementProvider setCache(boolean theCache) {
myCache = theCache;
return this; return this;
} }
@Override @Override
public void setRestfulServer(RestfulServer theRestfulServer) { public void setRestfulServer(RestfulServer theRestfulServer) {
myServerConfiguration = theRestfulServer::createConfiguration; // ignore
} }
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) { 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.MethodOutcome;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider; 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.param.*;
import ca.uhn.fhir.rest.server.method.BaseMethodBinding; import ca.uhn.fhir.rest.server.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.method.IParameter; import ca.uhn.fhir.rest.server.method.IParameter;
import ca.uhn.fhir.rest.server.method.SearchMethodBinding; import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
import ca.uhn.fhir.rest.server.method.SearchParameter; 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.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult; import ca.uhn.fhir.validation.ValidationResult;
@ -90,7 +91,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -102,6 +103,12 @@ public class ServerCapabilityStatementProviderR4Test {
assertTrue(res.getConditionalUpdate()); assertTrue(res.getConditionalUpdate());
} }
private RequestDetails createRequestDetails(RestfulServer theServer) {
ServletRequestDetails retVal = new ServletRequestDetails(null);
retVal.setServer(theServer);
return retVal;
}
@Test @Test
public void testExtendedOperationReturningBundle() throws Exception { public void testExtendedOperationReturningBundle() throws Exception {
@ -113,7 +120,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -121,7 +128,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertEquals(1, conformance.getRest().get(0).getOperation().size()); assertEquals(1, conformance.getRest().get(0).getOperation().size());
assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName()); 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); validate(opDef);
assertEquals("everything", opDef.getCode()); assertEquals("everything", opDef.getCode());
assertThat(opDef.getSystem(), is(false)); assertThat(opDef.getSystem(), is(false));
@ -141,7 +148,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); 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); validate(opDef);
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef);
@ -162,7 +169,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -194,7 +201,7 @@ public class ServerCapabilityStatementProviderR4Test {
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -214,7 +221,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -237,7 +244,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); 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")); 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); validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource()); Set<String> types = toStrings(opDef.getResource());
@ -265,7 +272,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertEquals("Patient", opDef.getParameter().get(1).getType()); 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); validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource()); Set<String> types = toStrings(opDef.getResource());
@ -280,7 +287,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertEquals("Encounter", opDef.getParameter().get(1).getType()); 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); validate(opDef);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef));
Set<String> types = toStrings(opDef.getResource()); Set<String> types = toStrings(opDef.getResource());
@ -305,7 +312,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
@ -321,15 +328,15 @@ public class ServerCapabilityStatementProviderR4Test {
ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) { ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) {
@Override @Override
public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
return super.getServerConformance(theRequest); return super.getServerConformance(theRequest, createRequestDetails(rs));
} }
}; };
rs.setServerConformanceProvider(sc); rs.setServerConformanceProvider(sc);
rs.init(createServletConfig()); 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); validate(opDef);
assertEquals("plain", opDef.getCode()); assertEquals("plain", opDef.getCode());
@ -364,7 +371,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -394,7 +401,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -414,7 +421,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -450,7 +457,7 @@ public class ServerCapabilityStatementProviderR4Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -486,7 +493,7 @@ public class ServerCapabilityStatementProviderR4Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -519,7 +526,7 @@ public class ServerCapabilityStatementProviderR4Test {
} }
} }
assertTrue(found); assertTrue(found);
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -537,8 +544,8 @@ public class ServerCapabilityStatementProviderR4Test {
RestfulServer rsNoType = new RestfulServer(ourCtx){ RestfulServer rsNoType = new RestfulServer(ourCtx){
@Override @Override
public RestulfulServerConfiguration createConfiguration() { public RestfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration(); RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z")); retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal; return retVal;
} }
@ -548,14 +555,14 @@ public class ServerCapabilityStatementProviderR4Test {
rsNoType.setServerConformanceProvider(scNoType); rsNoType.setServerConformanceProvider(scNoType);
rsNoType.init(createServletConfig()); rsNoType.init(createServletConfig());
CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsNoType));
String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(confNoType); ourLog.info(confNoType);
RestfulServer rsWithType = new RestfulServer(ourCtx){ RestfulServer rsWithType = new RestfulServer(ourCtx){
@Override @Override
public RestulfulServerConfiguration createConfiguration() { public RestfulServerConfiguration createConfiguration() {
RestulfulServerConfiguration retVal = super.createConfiguration(); RestfulServerConfiguration retVal = super.createConfiguration();
retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z")); retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z"));
return retVal; return retVal;
} }
@ -565,7 +572,7 @@ public class ServerCapabilityStatementProviderR4Test {
rsWithType.setServerConformanceProvider(scWithType); rsWithType.setServerConformanceProvider(scWithType);
rsWithType.init(createServletConfig()); rsWithType.init(createServletConfig());
CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest()); CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsWithType));
String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType); String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType);
ourLog.info(confWithType); ourLog.info(confWithType);
@ -584,7 +591,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -603,7 +610,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -622,7 +629,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
ValidationResult result = ourCtx.newValidator().validateWithResult(conformance); ValidationResult result = ourCtx.newValidator().validateWithResult(conformance);
@ -639,7 +646,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0); CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -649,7 +656,7 @@ public class ServerCapabilityStatementProviderR4Test {
String operationReference = operationComponent.getDefinition(); String operationReference = operationComponent.getDefinition();
assertThat(operationReference, not(nullValue())); 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)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition); validate(operationDefinition);
assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME)); assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME));
@ -683,7 +690,7 @@ public class ServerCapabilityStatementProviderR4Test {
rs.init(createServletConfig()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance));
CapabilityStatementRestComponent restComponent = conformance.getRest().get(0); CapabilityStatementRestComponent restComponent = conformance.getRest().get(0);
@ -691,7 +698,7 @@ public class ServerCapabilityStatementProviderR4Test {
String operationReference = operationComponent.getDefinition(); String operationReference = operationComponent.getDefinition();
assertThat(operationReference, not(nullValue())); 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)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition));
validate(operationDefinition); validate(operationDefinition);
assertThat("The operation name should be the code if no description is set", operationDefinition.getName(), is(NamedQueryResourceProvider.QUERY_NAME)); 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()); rs.init(createServletConfig());
CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs));
String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance);
ourLog.info(conf); ourLog.info(conf);
@ -735,7 +742,7 @@ public class ServerCapabilityStatementProviderR4Test {
assertThat(operations.size(), is(1)); assertThat(operations.size(), is(1));
assertThat(operations.get(0).getName(), is(TypeLevelOperationProvider.OPERATION_NAME)); 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); validate(opDef);
assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode()); assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode());
assertThat(opDef.getSystem(), is(false)); assertThat(opDef.getSystem(), is(false));

View File

@ -251,6 +251,12 @@
results exist. A default implementation has been provided, so this is not results exist. A default implementation has been provided, so this is not
a breaking change. a breaking change.
</action> </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>
<release version="3.8.0" date="2019-05-30" description="Hippo"> <release version="3.8.0" date="2019-05-30" description="Hippo">
<action type="fix"> <action type="fix">