From 34f7d4ddbde8c145c51a32ae5f675d9e41c358f2 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Sun, 7 Jul 2019 12:57:31 -0400 Subject: [PATCH] Refactor ServerConformanceProvider so that it no longer keeps any state --- .../AbstractJaxRsConformanceProvider.java | 22 +- .../provider/JpaConformanceProviderDstu2.java | 7 +- .../dstu3/JpaConformanceProviderDstu3.java | 7 +- .../provider/r4/JpaConformanceProviderR4.java | 5 +- .../ca/uhn/fhir/rest/server/Bindings.java | 38 +++ .../server/IServerConformanceProvider.java | 3 +- .../uhn/fhir/rest/server/RestfulServer.java | 4 +- .../server/RestfulServerConfiguration.java | 304 ++++++++++++++++++ .../fhir/rest/server/RestfulServerUtils.java | 2 + .../server/RestulfulServerConfiguration.java | 191 ----------- .../method/ConformanceMethodBinding.java | 34 +- ...BaseServerCapabilityStatementProvider.java | 34 ++ .../server/ServerConformanceProvider.java | 194 +++++------ ...ServerWithSearchParamTypesDstu2_1Test.java | 20 +- .../dstu2/ServerConformanceProvider.java | 139 +++----- ...onServerWithSearchParamTypesDstu2Test.java | 13 +- .../ServerConformanceProviderDstu2Test.java | 65 ++-- .../ServerCapabilityStatementProvider.java | 152 +++------ ...onServerWithSearchParamTypesDstu3Test.java | 19 +- ...rCapabilityStatementProviderDstu3Test.java | 84 ++--- .../conf/ServerConformanceProvider.java | 131 +++----- ...verConformanceProviderHl7OrgDstu2Test.java | 48 +-- .../ServerCapabilityStatementProvider.java | 193 +++-------- ...rverCapabilityStatementProviderR4Test.java | 81 ++--- src/changes/changes.xml | 6 + 25 files changed, 885 insertions(+), 911 deletions(-) create mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/Bindings.java create mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerConfiguration.java delete mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java create mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/BaseServerCapabilityStatementProvider.java diff --git a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java index 9faee01c76b..33e2eeab44d 100644 --- a/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java +++ b/hapi-fhir-jaxrsserver-base/src/main/java/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.java @@ -33,7 +33,6 @@ import javax.ws.rs.*; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import ca.uhn.fhir.interceptor.api.IInterceptorService; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.LoggerFactory; @@ -62,7 +61,7 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv /** the resource bindings */ private ConcurrentHashMap myResourceNameToBinding = new ConcurrentHashMap(); /** the server configuration */ - private RestulfulServerConfiguration serverConfiguration = new RestulfulServerConfiguration(); + private RestfulServerConfiguration serverConfiguration = new RestfulServerConfiguration(); /** the conformance. It is created once during startup */ private org.hl7.fhir.r4.model.CapabilityStatement myR4CapabilityStatement; @@ -135,28 +134,23 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv switch (fhirContextVersion) { case R4: org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider r4ServerCapabilityStatementProvider = new org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration); - r4ServerCapabilityStatementProvider.initializeOperations(); - myR4CapabilityStatement = r4ServerCapabilityStatementProvider.getServerConformance(null); + myR4CapabilityStatement = r4ServerCapabilityStatementProvider.getServerConformance(null, null); break; case DSTU3: org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider dstu3ServerCapabilityStatementProvider = new org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider(serverConfiguration); - dstu3ServerCapabilityStatementProvider.initializeOperations(); - myDstu3CapabilityStatement = dstu3ServerCapabilityStatementProvider.getServerConformance(null); + myDstu3CapabilityStatement = dstu3ServerCapabilityStatementProvider.getServerConformance(null, null); break; case DSTU2_1: org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider dstu2_1ServerConformanceProvider = new org.hl7.fhir.dstu2016may.hapi.rest.server.ServerConformanceProvider(serverConfiguration); - dstu2_1ServerConformanceProvider.initializeOperations(); - myDstu2_1Conformance = dstu2_1ServerConformanceProvider.getServerConformance(null); + myDstu2_1Conformance = dstu2_1ServerConformanceProvider.getServerConformance(null, null); break; case DSTU2_HL7ORG: org.hl7.fhir.instance.conf.ServerConformanceProvider dstu2Hl7OrgServerConformanceProvider = new org.hl7.fhir.instance.conf.ServerConformanceProvider(serverConfiguration); - dstu2Hl7OrgServerConformanceProvider.initializeOperations(); - myDstu2Hl7OrgConformance = dstu2Hl7OrgServerConformanceProvider.getServerConformance(null); + myDstu2Hl7OrgConformance = dstu2Hl7OrgServerConformanceProvider.getServerConformance(null, null); break; case DSTU2: ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider dstu2ServerConformanceProvider = new ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider(serverConfiguration); - dstu2ServerConformanceProvider.initializeOperations(); - myDstu2Conformance = dstu2ServerConformanceProvider.getServerConformance(null); + myDstu2Conformance = dstu2ServerConformanceProvider.getServerConformance(null, null); break; default: throw new ConfigurationException("Unsupported Fhir version: " + fhirContextVersion); @@ -228,14 +222,14 @@ public abstract class AbstractJaxRsConformanceProvider extends AbstractJaxRsProv } /** - * This method will add a provider to the conformance. This method is almost an exact copy of {@link ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods } + * This method will add a provider to the conformance. This method is almost an exact copy of {@link ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods(Object, Class)} } * * @param theProvider * an instance of the provider interface * @param theProviderInterface * the class describing the providers interface * @return the numbers of basemethodbindings added - * @see ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods + * @see ca.uhn.fhir.rest.server.RestfulServer#findResourceMethods(Object) */ public int addProvider(IResourceProvider theProvider, Class theProviderInterface) throws ConfigurationException { int count = 0; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu2.java index afccc5caef8..34c8e5baf66 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu2.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaConformanceProviderDstu2.java @@ -29,7 +29,6 @@ import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.util.ResourceCountCache; -import ca.uhn.fhir.jpa.util.SingleItemLoadingCache; import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.dstu2.composite.MetaDt; import ca.uhn.fhir.model.dstu2.resource.Bundle; @@ -44,12 +43,12 @@ import ca.uhn.fhir.model.primitive.BoundCodeDt; import ca.uhn.fhir.model.primitive.DecimalDt; import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider; import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.ExtensionConstants; import org.hl7.fhir.instance.model.Subscription; -import org.hl7.fhir.r4.model.Extension; import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -87,7 +86,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider { } @Override - public Conformance getServerConformance(HttpServletRequest theRequest) { + public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { Conformance retVal = myCachedValue; Map counts = null; @@ -98,7 +97,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider { FhirContext ctx = myRestfulServer.getFhirContext(); - retVal = super.getServerConformance(theRequest); + retVal = super.getServerConformance(theRequest, theRequestDetails); for (Rest nextRest : retVal.getRest()) { for (RestResource nextResource : nextRest.getResource()) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java index 5e242842e7e..176791f79a2 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/dstu3/JpaConformanceProviderDstu3.java @@ -25,9 +25,8 @@ import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; -import ca.uhn.fhir.model.api.ExtensionDt; -import ca.uhn.fhir.model.primitive.UriDt; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.util.CoverageIgnore; import ca.uhn.fhir.util.ExtensionConstants; @@ -80,7 +79,7 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se } @Override - public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { + public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { CapabilityStatement retVal = myCachedValue; Map counts = null; @@ -89,7 +88,7 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se } counts = defaultIfNull(counts, Collections.emptyMap()); - retVal = super.getServerConformance(theRequest); + retVal = super.getServerConformance(theRequest, theRequestDetails); for (CapabilityStatementRestComponent nextRest : retVal.getRest()) { for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/JpaConformanceProviderR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/JpaConformanceProviderR4.java index 5de6a6fe2a7..ab82c1a9d97 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/JpaConformanceProviderR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/JpaConformanceProviderR4.java @@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletRequest; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.RequestDetails; import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.model.CapabilityStatement.*; import org.hl7.fhir.r4.model.Enumerations.SearchParamType; @@ -78,7 +79,7 @@ public class JpaConformanceProviderR4 extends org.hl7.fhir.r4.hapi.rest.server.S } @Override - public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { + public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { CapabilityStatement retVal = myCachedValue; Map counts = null; @@ -87,7 +88,7 @@ public class JpaConformanceProviderR4 extends org.hl7.fhir.r4.hapi.rest.server.S } counts = defaultIfNull(counts, Collections.emptyMap()); - retVal = super.getServerConformance(theRequest); + retVal = super.getServerConformance(theRequest, theRequestDetails); for (CapabilityStatementRestComponent nextRest : retVal.getRest()) { for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) { diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/Bindings.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/Bindings.java new file mode 100644 index 00000000000..69551b371f8 --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/Bindings.java @@ -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 myNamedSearchMethodBindingToName; + private final HashMap> mySearchNameToBindings; + private final HashMap> myOperationNameToBindings; + private final IdentityHashMap myOperationBindingToName; + + public Bindings(IdentityHashMap theNamedSearchMethodBindingToName, HashMap> theSearchNameToBindings, HashMap> theOperationNameToBindings, IdentityHashMap theOperationBindingToName) { + myNamedSearchMethodBindingToName = theNamedSearchMethodBindingToName; + mySearchNameToBindings = theSearchNameToBindings; + myOperationNameToBindings = theOperationNameToBindings; + myOperationBindingToName = theOperationBindingToName; + } + + public IdentityHashMap getNamedSearchMethodBindingToName() { + return myNamedSearchMethodBindingToName; + } + + public HashMap> getSearchNameToBindings() { + return mySearchNameToBindings; + } + + public HashMap> getOperationNameToBindings() { + return myOperationNameToBindings; + } + + public IdentityHashMap getOperationBindingToName() { + return myOperationBindingToName; + } +} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java index 70b6671e269..f6e4a273abe 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/IServerConformanceProvider.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.server; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.rest.api.server.RequestDetails; import org.hl7.fhir.instance.model.api.IBaseResource; public interface IServerConformanceProvider { @@ -31,7 +32,7 @@ public interface IServerConformanceProvider { * * 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 diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java index 4c4999e06ea..f351bc37d36 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java @@ -190,8 +190,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer resourceBindings; + private List> serverBindings; + private String implementationDescription; + private String serverVersion = VersionUtil.getVersion(); + private String serverName = "HAPI FHIR"; + private FhirContext fhirContext; + private IServerAddressStrategy serverAddressStrategy; + private IPrimitiveType myConformanceDate; + + /** + * Constructor + */ + public RestfulServerConfiguration() { + super(); + } + + /** + * Get the resourceBindings + * + * @return the resourceBindings + */ + public Collection getResourceBindings() { + return resourceBindings; + } + + /** + * Set the resourceBindings + * + * @param resourceBindings the resourceBindings to set + */ + public RestfulServerConfiguration setResourceBindings(Collection resourceBindings) { + this.resourceBindings = resourceBindings; + return this; + } + + /** + * Get the serverBindings + * + * @return the serverBindings + */ + public List> getServerBindings() { + return serverBindings; + } + + /** + * Set the theServerBindings + */ + public RestfulServerConfiguration setServerBindings(List> 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 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 theConformanceDate) { + myConformanceDate = theConformanceDate; + } + + public Bindings provideBindings() { + IdentityHashMap myNamedSearchMethodBindingToName = new IdentityHashMap<>(); + HashMap> mySearchNameToBindings = new HashMap<>(); + IdentityHashMap myOperationBindingToName = new IdentityHashMap<>(); + HashMap> myOperationNameToBindings = new HashMap<>(); + + Map>> resourceToMethods = collectMethodBindings(); + for (Map.Entry>> nextEntry : resourceToMethods.entrySet()) { + List> 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>> collectMethodBindings() { + Map>> resourceToMethods = new TreeMap>>(); + 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(); + } + +} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java index 349d2492f6f..0ef3a51a9f9 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestfulServerUtils.java @@ -911,4 +911,6 @@ public class RestfulServerUtils { } } + + } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java deleted file mode 100644 index 97b5a21b940..00000000000 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/RestulfulServerConfiguration.java +++ /dev/null @@ -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 resourceBindings; - private List> serverBindings; - private String implementationDescription; - private String serverVersion = VersionUtil.getVersion(); - private String serverName = "HAPI FHIR"; - private FhirContext fhirContext; - private IServerAddressStrategy serverAddressStrategy; - private IPrimitiveType myConformanceDate; - - /** - * Constructor - */ - public RestulfulServerConfiguration() { - super(); - } - - /** - * Get the resourceBindings - * @return the resourceBindings - */ - public Collection getResourceBindings() { - return resourceBindings; - } - - /** - * Set the resourceBindings - * @param resourceBindings the resourceBindings to set - */ - public RestulfulServerConfiguration setResourceBindings(Collection resourceBindings) { - this.resourceBindings = resourceBindings; - return this; - } - - /** - * Get the serverBindings - * @return the serverBindings - */ - public List> getServerBindings() { - return serverBindings; - } - - /** - * Set the theServerBindings - */ - public RestulfulServerConfiguration setServerBindings(List> 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 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 theConformanceDate) { - myConformanceDate = theConformanceDate; - } - -} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ConformanceMethodBinding.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ConformanceMethodBinding.java index a08ed918375..31d73ebe021 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ConformanceMethodBinding.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/ConformanceMethodBinding.java @@ -21,6 +21,8 @@ package ca.uhn.fhir.rest.server.method; */ import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import org.hl7.fhir.instance.model.api.IBaseConformance; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -40,13 +42,20 @@ import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException; import javax.annotation.Nonnull; public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding { + private static final long CACHE_MILLIS = 60 * 1000; - public ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) { + /* + * Note: This caching mechanism should probably be configurable and maybe + * even applicable to other bindings. It's particularly important for this + * operation though, so a one-off is fine for now + */ + private final AtomicReference myCachedResponse = new AtomicReference<>(); + private final AtomicLong myCachedResponseExpires = new AtomicLong(0L); + + + ConformanceMethodBinding(Method theMethod, FhirContext theContext, Object theProvider) { super(theMethod.getReturnType(), theMethod, theContext, theProvider); - // if (Modifier.isAbstract(theMethod.getReturnType().getModifiers())) { - // throw new ConfigurationException("Conformance resource provider method '" + theMethod.getName() + "' must not be abstract"); - // } MethodReturnTypeEnum methodReturnType = getMethodReturnType(); Class genericReturnType = (Class) theMethod.getGenericReturnType(); if (methodReturnType != MethodReturnTypeEnum.RESOURCE || !IBaseConformance.class.isAssignableFrom(genericReturnType)) { @@ -62,7 +71,22 @@ public class ConformanceMethodBinding extends BaseResourceReturningMethodBinding @Override public IBundleProvider invokeServer(IRestfulServer theServer, RequestDetails theRequest, Object[] theMethodParams) throws BaseServerResponseException { - IBaseResource conf = (IBaseResource) invokeServerMethod(theServer, theRequest, theMethodParams); + IBaseResource conf; + + conf = myCachedResponse.get(); + if (conf != null) { + long expires = myCachedResponseExpires.get(); + if (expires < System.currentTimeMillis()) { + conf = null; + } + } + + if (conf == null) { + conf = (IBaseResource) invokeServerMethod(theServer, theRequest, theMethodParams); + myCachedResponse.set(conf); + myCachedResponseExpires.set(System.currentTimeMillis() + CACHE_MILLIS); + } + return new SimpleBundleProvider(conf); } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/BaseServerCapabilityStatementProvider.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/BaseServerCapabilityStatementProvider.java new file mode 100644 index 00000000000..25a11cb766d --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/BaseServerCapabilityStatementProvider.java @@ -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; + } + +} diff --git a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/rest/server/ServerConformanceProvider.java b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/rest/server/ServerConformanceProvider.java index 14aca165f96..31045cdab6d 100644 --- a/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/rest/server/ServerConformanceProvider.java +++ b/hapi-fhir-structures-dstu2.1/src/main/java/org/hl7/fhir/dstu2016may/hapi/rest/server/ServerConformanceProvider.java @@ -1,6 +1,41 @@ package org.hl7.fhir.dstu2016may.hapi.rest.server; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Metadata; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.*; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.method.*; +import ca.uhn.fhir.rest.server.method.SearchParameter; +import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; +import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider; +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.dstu2016may.model.*; +import org.hl7.fhir.dstu2016may.model.Conformance.*; +import org.hl7.fhir.dstu2016may.model.Enumerations.ConformanceResourceStatus; +import org.hl7.fhir.dstu2016may.model.Enumerations.ResourceType; +import org.hl7.fhir.dstu2016may.model.OperationDefinition.OperationDefinitionParameterComponent; +import org.hl7.fhir.dstu2016may.model.OperationDefinition.OperationKind; +import org.hl7.fhir.dstu2016may.model.OperationDefinition.OperationParameterUse; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import java.util.*; +import java.util.Map.Entry; + import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + /* * #%L * HAPI FHIR Structures - DSTU2 (FHIR v1.0.0) @@ -10,9 +45,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank; * 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. @@ -20,54 +55,14 @@ import static org.apache.commons.lang3.StringUtils.isBlank; * limitations under the License. * #L% */ -import static org.apache.commons.lang3.StringUtils.isNotBlank; - -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.Callable; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; - -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -import org.apache.commons.lang3.StringUtils; -import org.hl7.fhir.dstu2016may.model.*; -import org.hl7.fhir.dstu2016may.model.Conformance.*; -import org.hl7.fhir.dstu2016may.model.Enumerations.ConformanceResourceStatus; -import org.hl7.fhir.dstu2016may.model.Enumerations.ResourceType; -import org.hl7.fhir.dstu2016may.model.OperationDefinition.*; -import org.hl7.fhir.exceptions.FHIRException; -import org.hl7.fhir.instance.model.api.IBaseResource; - -import ca.uhn.fhir.context.*; -import ca.uhn.fhir.parser.DataFormatException; -import ca.uhn.fhir.rest.annotation.*; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; -import ca.uhn.fhir.rest.server.*; -import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; -import ca.uhn.fhir.rest.server.method.*; -import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; -import ca.uhn.fhir.rest.server.method.SearchParameter; -import org.hl7.fhir.instance.model.api.IPrimitiveType; /** * Server FHIR Provider which serves the conformance statement for a RESTful server implementation - * - *

- * 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 - * false. This means that if you are adding anything to the returned conformance instance on each call you should call setCache(false) in your provider constructor. - *

*/ -public class ServerConformanceProvider implements IServerConformanceProvider { +public class ServerConformanceProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProvider.class); - private boolean myCache = true; - private volatile Conformance myConformance; - private IdentityHashMap myOperationBindingToName; - private HashMap> myOperationNameToBindings; private String myPublisher = "Not provided"; - private Callable myServerConfiguration; /** * No-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen. @@ -78,16 +73,19 @@ public class ServerConformanceProvider implements IServerConformanceProvider theServerConfiguration; + public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) { + super(theServerConfiguration); } private void checkBindingForSystemOps(ConformanceRestComponent rest, Set systemOps, BaseMethodBinding nextMethodBinding) { @@ -111,9 +109,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider>> collectMethodBindings() { + private Map>> collectMethodBindings(RequestDetails theRequestDetails) { Map>> resourceToMethods = new TreeMap<>(); - for (ResourceBinding next : getServerConfiguration().getResourceBindings()) { + for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) { String resourceName = next.getResourceName(); for (BaseMethodBinding nextMethodBinding : next.getMethodBindings()) { if (resourceToMethods.containsKey(resourceName) == false) { @@ -122,7 +120,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextMethodBinding : getServerConfiguration().getServerBindings()) { + for (BaseMethodBinding nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) { String resourceName = ""; if (resourceToMethods.containsKey(resourceName) == false) { resourceToMethods.put(resourceName, new ArrayList<>()); @@ -132,8 +130,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider buildDate = getServerConfiguration().getConformanceDate(); + private DateTimeType conformanceDate(RequestDetails theRequestDetails) { + IPrimitiveType buildDate = getServerConfiguration(theRequestDetails).getConformanceDate(); if (buildDate != null && buildDate.getValue() != null) { try { return new DateTimeType(buildDate.getValueAsString()); @@ -173,32 +171,32 @@ public class ServerConformanceProvider implements IServerConformanceProvider systemOps = new HashSet<>(); Set operationNames = new HashSet<>(); - Map>> resourceToMethods = collectMethodBindings(); + Map>> resourceToMethods = collectMethodBindings(theRequestDetails); for (Entry>> nextEntry : resourceToMethods.entrySet()) { if (nextEntry.getKey().isEmpty() == false) { Set resourceOps = new HashSet<>(); ConformanceRestResourceComponent resource = rest.addResource(); String resourceName = nextEntry.getKey(); - RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); + RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName); resource.getTypeElement().setValue(def.getName()); resource.getProfile().setReference((def.getResourceProfile(serverBase))); @@ -274,10 +272,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider includes, - SearchMethodBinding searchMethodBinding) { + SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) { includes.addAll(searchMethodBinding.getIncludes()); List params = searchMethodBinding.getParameters(); @@ -395,7 +392,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextTarget : nextParameter.getDeclaredTypes()) { - RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); + RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget); if (targetDef != null) { ResourceType code; try { @@ -412,40 +409,17 @@ public class ServerConformanceProvider implements IServerConformanceProvider(); - myOperationNameToBindings = new HashMap>(); - Map>> resourceToMethods = collectMethodBindings(); - for (Entry>> nextEntry : resourceToMethods.entrySet()) { - List> 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); - } - } - } - } @Read(type = OperationDefinition.class) - public OperationDefinition readOperationDefinition(@IdParam IdType theId) { + public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) { if (theId == null || theId.hasIdPart() == false) { throw new ResourceNotFoundException(theId); } - List sharedDescriptions = myOperationNameToBindings.get(theId.getIdPart()); + RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails); + Bindings bindings = serverConfiguration.provideBindings(); + + List sharedDescriptions = bindings.getOperationNameToBindings().get(theId.getIdPart()); if (sharedDescriptions == null || sharedDescriptions.isEmpty()) { throw new ResourceNotFoundException(theId); } @@ -457,8 +431,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider inParams = new HashSet(); - Set outParams = new HashSet(); + Set inParams = new HashSet<>(); + Set outParams = new HashSet<>(); for (OperationMethodBinding sharedDescription : sharedDescriptions) { if (isNotBlank(sharedDescription.getDescription())) { @@ -542,9 +516,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider * See the class documentation for an important note if you are extending this class *

+ * @deprecated Since 4.0.0 this does not do anything */ public void setCache(boolean theCache) { - myCache = theCache; + // nothing } /** @@ -557,24 +532,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider searchParameters) { - Collections.sort(searchParameters, new Comparator() { - @Override - public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) { - return theO1.getName().compareTo(theO2.getName()); - } - }); + // ignore } private void sortSearchParameters(List searchParameters) { diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java index a138ceeaff4..050e8e89666 100644 --- a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java +++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2_1Test.java @@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.test.utilities.JettyUtil; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; @@ -152,7 +154,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -178,7 +180,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test { /* * Check the operation definitions themselves */ - OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist")); + OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"), createRequestDetails(rs)); String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef); ourLog.info(def); //@formatter:off @@ -194,7 +196,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test { )); //@formatter:on - andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax")); + andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"), createRequestDetails(rs)); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef); ourLog.info(def); //@formatter:off @@ -210,7 +212,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test { )); //@formatter:on - OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist")); + OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"), createRequestDetails(rs)); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef); ourLog.info(def); //@formatter:off @@ -226,7 +228,7 @@ public class OperationServerWithSearchParamTypesDstu2_1Test { )); //@formatter:on - orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax")); + orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"), createRequestDetails(rs)); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef); ourLog.info(def); //@formatter:off @@ -488,4 +490,12 @@ public class OperationServerWithSearchParamTypesDstu2_1Test { } + + private RequestDetails createRequestDetails(RestfulServer theServer) { + ServletRequestDetails retVal = new ServletRequestDetails(null); + retVal.setServer(theServer); + return retVal; + } + } + diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java index 2120e5aee91..e21f9db071b 100644 --- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java +++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.java @@ -15,19 +15,16 @@ import ca.uhn.fhir.model.primitive.DateTimeDt; import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.annotation.IdParam; -import ca.uhn.fhir.rest.annotation.Initialize; import ca.uhn.fhir.rest.annotation.Metadata; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; -import ca.uhn.fhir.rest.server.IServerConformanceProvider; -import ca.uhn.fhir.rest.server.ResourceBinding; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestulfulServerConfiguration; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.method.*; import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; +import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IPrimitiveType; @@ -36,7 +33,6 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.Map.Entry; -import java.util.concurrent.Callable; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -63,23 +59,13 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; /** * Server FHIR Provider which serves the conformance statement for a RESTful server implementation - * - *

- * 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 - * false. This means that if you are adding anything to the returned conformance instance on each call you should call setCache(false) in your provider constructor. - *

*/ -public class ServerConformanceProvider implements IServerConformanceProvider { +public class ServerConformanceProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider { - private boolean myCache = true; - private volatile Conformance myConformance; - private IdentityHashMap myOperationBindingToName; - private HashMap> myOperationNameToBindings; private String myPublisher = "Not provided"; - private Callable myServerConfiguration; /** - * No-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen. + * No-arg constructor and setter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen. */ public ServerConformanceProvider() { super(); @@ -87,16 +73,19 @@ public class ServerConformanceProvider implements IServerConformanceProvider theServerConfiguration; + public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) { + super(theServerConfiguration); } private void checkBindingForSystemOps(Rest rest, Set systemOps, BaseMethodBinding nextMethodBinding) { @@ -115,9 +104,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider>> collectMethodBindings() { + private Map>> collectMethodBindings(RequestDetails theRequestDetails) { Map>> resourceToMethods = new TreeMap>>(); - for (ResourceBinding next : getServerConfiguration().getResourceBindings()) { + for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) { String resourceName = next.getResourceName(); for (BaseMethodBinding nextMethodBinding : next.getMethodBindings()) { if (resourceToMethods.containsKey(resourceName) == false) { @@ -126,7 +115,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextMethodBinding : getServerConfiguration().getServerBindings()) { + for (BaseMethodBinding nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) { String resourceName = ""; if (resourceToMethods.containsKey(resourceName) == false) { resourceToMethods.put(resourceName, new ArrayList>()); @@ -136,8 +125,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider buildDate = getServerConfiguration().getConformanceDate(); + private DateTimeDt conformanceDate(RequestDetails theRequestDetails) { + IPrimitiveType buildDate = getServerConfiguration(theRequestDetails).getConformanceDate(); if (buildDate != null && buildDate.getValue() != null) { try { return new DateTimeDt(buildDate.getValueAsString()); @@ -185,39 +174,31 @@ public class ServerConformanceProvider implements IServerConformanceProvider systemOps = new HashSet<>(); Set operationNames = new HashSet<>(); - Map>> resourceToMethods = collectMethodBindings(); + Map>> resourceToMethods = collectMethodBindings(theRequestDetails); for (Entry>> nextEntry : resourceToMethods.entrySet()) { if (nextEntry.getKey().isEmpty() == false) { Set resourceOps = new HashSet<>(); RestResource resource = rest.addResource(); String resourceName = nextEntry.getKey(); - RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); + RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName); resource.getTypeElement().setValue(def.getName()); resource.getProfile().setReference(new IdDt(def.getResourceProfile(serverBase))); @@ -287,10 +268,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider includes, SearchMethodBinding searchMethodBinding) { + private void handleSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet includes, SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) { includes.addAll(searchMethodBinding.getIncludes()); List params = searchMethodBinding.getParameters(); - List searchParameters = new ArrayList(); + List searchParameters = new ArrayList<>(); for (IParameter nextParameter : params) { if ((nextParameter instanceof SearchParameter)) { searchParameters.add((SearchParameter) nextParameter); @@ -401,7 +381,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider(nextParameter.getQualifierWhitelist())) { + for (String nextWhitelist : new TreeSet<>(nextParameter.getQualifierWhitelist())) { if (nextWhitelist.startsWith(".")) { param.addChain(nextWhitelist.substring(1)); } @@ -414,7 +394,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextTarget : nextParameter.getDeclaredTypes()) { - RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); + RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget); if (targetDef != null) { ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName()); if (code != null) { @@ -426,38 +406,16 @@ public class ServerConformanceProvider implements IServerConformanceProvider(); - myOperationNameToBindings = new HashMap>(); - - Map>> resourceToMethods = collectMethodBindings(); - for (Entry>> nextEntry : resourceToMethods.entrySet()) { - List> nextMethodBindings = nextEntry.getValue(); - for (BaseMethodBinding nextMethodBinding : nextMethodBindings) { - if (nextMethodBinding instanceof OperationMethodBinding) { - OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; - if (myOperationBindingToName.containsKey(methodBinding)) { - continue; - } - - String name = createOperationName(methodBinding); - myOperationBindingToName.put(methodBinding, name); - if (myOperationNameToBindings.containsKey(name) == false) { - myOperationNameToBindings.put(name, new ArrayList()); - } - myOperationNameToBindings.get(name).add(methodBinding); - } - } - } - } @Read(type = OperationDefinition.class) - public OperationDefinition readOperationDefinition(@IdParam IdDt theId) { + public OperationDefinition readOperationDefinition(@IdParam IdDt theId, RequestDetails theRequestDetails) { if (theId == null || theId.hasIdPart() == false) { throw new ResourceNotFoundException(theId); } - List sharedDescriptions = myOperationNameToBindings.get(theId.getIdPart()); + RestfulServerConfiguration serverConfiguration = getServerConfiguration(theRequestDetails); + Bindings bindings = serverConfiguration.provideBindings(); + + List sharedDescriptions = bindings.getOperationNameToBindings().get(theId.getIdPart()); if (sharedDescriptions == null || sharedDescriptions.isEmpty()) { throw new ResourceNotFoundException(theId); } @@ -467,8 +425,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider inParams = new HashSet(); - Set outParams = new HashSet(); + Set inParams = new HashSet<>(); + Set outParams = new HashSet<>(); for (OperationMethodBinding sharedDescription : sharedDescriptions) { if (isNotBlank(sharedDescription.getDescription())) { @@ -543,23 +501,16 @@ public class ServerConformanceProvider implements IServerConformanceProvider * See the class documentation for an important note if you are extending this class *

+ * @deprecated Since 4.0.0 this does nothing */ + @Deprecated public void setCache(boolean theCache) { - myCache = theCache; + // nothing } @Override public void setRestfulServer(RestfulServer theRestfulServer) { - myServerConfiguration = theRestfulServer::createConfiguration; - } - - private void sortRuntimeSearchParameters(List searchParameters) { - Collections.sort(searchParameters, new Comparator() { - @Override - public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) { - return theO1.getName().compareTo(theO2.getName()); - } - }); + // nothing } private void sortSearchParameters(List searchParameters) { diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java index b2cdc5b05a0..7bf78ecde37 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu2Test.java @@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.test.utilities.JettyUtil; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; @@ -145,7 +147,7 @@ public class OperationServerWithSearchParamTypesDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -170,7 +172,7 @@ public class OperationServerWithSearchParamTypesDstu2Test { /* * Check the operation definitions themselves */ - OperationDefinition andListDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient--andlist")); + OperationDefinition andListDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient--andlist"), createRequestDetails(rs)); String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef); ourLog.info(def); //@formatter:off @@ -405,4 +407,11 @@ public class OperationServerWithSearchParamTypesDstu2Test { } + private RequestDetails createRequestDetails(RestfulServer theServer) { + ServletRequestDetails retVal = new ServletRequestDetails(null); + retVal.setServer(theServer); + return retVal; + } + + } diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderDstu2Test.java index 1ff78efc688..d1f9264e289 100644 --- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderDstu2Test.java +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderDstu2Test.java @@ -16,6 +16,8 @@ import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.AfterClass; import org.junit.Test; @@ -104,7 +106,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -127,7 +129,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -149,7 +151,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-everything")); + OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-everything"), createRequestDetails(rs)); validate(opDef); assertEquals("everything", opDef.getCode()); @@ -167,7 +169,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -200,7 +202,7 @@ public class ServerConformanceProviderDstu2Test { } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -220,7 +222,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -243,7 +245,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -256,7 +258,7 @@ public class ServerConformanceProviderDstu2Test { assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp","Encounter-i-someOp","Patient-i-validate","Encounter-i-validate")); { - OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-someOp")); + OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-someOp"), createRequestDetails(rs)); validate(opDef); Set types = toStrings(opDef.getType()); @@ -271,7 +273,7 @@ public class ServerConformanceProviderDstu2Test { assertEquals("Patient", opDef.getParameter().get(1).getType()); } { - OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter-i-someOp")); + OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Encounter-i-someOp"), createRequestDetails(rs)); validate(opDef); Set types = toStrings(opDef.getType()); @@ -286,7 +288,7 @@ public class ServerConformanceProviderDstu2Test { assertEquals("Encounter", opDef.getParameter().get(1).getType()); } { - OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-validate")); + OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/Patient-i-validate"), createRequestDetails(rs)); validate(opDef); Set types = toStrings(opDef.getType()); @@ -311,7 +313,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info("AAAAAA" + conf); @@ -328,18 +330,18 @@ public class ServerConformanceProviderDstu2Test { ServerConformanceProvider sc = new ServerConformanceProvider(rs) { @Override - public Conformance getServerConformance(HttpServletRequest theRequest) { - return super.getServerConformance(theRequest); + public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { + return super.getServerConformance(theRequest, theRequestDetails); } }; rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); - Conformance sconf = sc.getServerConformance(createHttpServletRequest()); + Conformance sconf = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); assertEquals("OperationDefinition/-is-plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference().getValue()); - OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/-is-plain")); + OperationDefinition opDef = sc.readOperationDefinition(new IdDt("OperationDefinition/-is-plain"), createRequestDetails(rs)); validate(opDef); assertEquals("plain", opDef.getCode()); @@ -366,8 +368,8 @@ public class ServerConformanceProviderDstu2Test { ServerConformanceProvider sc = new ServerConformanceProvider(rs) { @Override - public Conformance getServerConformance(HttpServletRequest theRequest) { - Conformance conformance = super.getServerConformance(theRequest); + public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { + Conformance conformance = super.getServerConformance(theRequest, theRequestDetails); ExtensionDt extensionDt = new ExtensionDt(); ExtensionDt extensionDtToken = new ExtensionDt(); ExtensionDt extensionDtAuthorize = new ExtensionDt(); @@ -392,7 +394,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -410,7 +412,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -440,7 +442,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -460,7 +462,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -496,7 +498,7 @@ public class ServerConformanceProviderDstu2Test { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -532,7 +534,7 @@ public class ServerConformanceProviderDstu2Test { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -566,7 +568,7 @@ public class ServerConformanceProviderDstu2Test { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -602,7 +604,7 @@ public class ServerConformanceProviderDstu2Test { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -629,7 +631,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -648,7 +650,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -667,7 +669,7 @@ public class ServerConformanceProviderDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ValidationResult result = ourCtx.newValidator().validateWithResult(conformance); @@ -943,4 +945,11 @@ public class ServerConformanceProviderDstu2Test { } + private RequestDetails createRequestDetails(RestfulServer theServer) { + ServletRequestDetails retVal = new ServletRequestDetails(null); + retVal.setServer(theServer); + return retVal; + } + + } diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProvider.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProvider.java index 39b20e66c36..b61650fd57b 100644 --- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProvider.java +++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProvider.java @@ -5,19 +5,16 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.annotation.IdParam; -import ca.uhn.fhir.rest.annotation.Initialize; import ca.uhn.fhir.rest.annotation.Metadata; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.server.IServerConformanceProvider; -import ca.uhn.fhir.rest.server.ResourceBinding; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestulfulServerConfiguration; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.method.*; import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; import ca.uhn.fhir.rest.server.method.SearchParameter; +import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.dstu3.model.*; import org.hl7.fhir.dstu3.model.CapabilityStatement.*; @@ -33,7 +30,6 @@ import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.Map.Entry; -import java.util.concurrent.Callable; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -66,17 +62,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * false. This means that if you are adding anything to the returned conformance instance on each call you should call setCache(false) in your provider constructor. *

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

* See the class documentation for an important note if you are extending this class *

+ * + * @deprecated Since 4.0.0 this doesn't do anything */ public ServerCapabilityStatementProvider setCache(boolean theCache) { - myCache = theCache; return this; } @Override public void setRestfulServer(RestfulServer theRestfulServer) { - myServerConfiguration = theRestfulServer::createConfiguration; - } - - private void sortRuntimeSearchParameters(List searchParameters) { - Collections.sort(searchParameters, new Comparator() { - @Override - public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) { - return theO1.getName().compareTo(theO2.getName()); - } - }); + // ignore } private void sortSearchParameters(List searchParameters) { diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java index d26380e8b14..555f6ec0906 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/OperationServerWithSearchParamTypesDstu3Test.java @@ -14,6 +14,8 @@ import java.util.concurrent.TimeUnit; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.test.utilities.JettyUtil; import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; @@ -152,7 +154,7 @@ public class OperationServerWithSearchParamTypesDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -178,7 +180,7 @@ public class OperationServerWithSearchParamTypesDstu3Test { /* * Check the operation definitions themselves */ - OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist")); + OperationDefinition andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist"), createRequestDetails(rs)); String def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef); ourLog.info(def); //@formatter:off @@ -194,7 +196,7 @@ public class OperationServerWithSearchParamTypesDstu3Test { )); //@formatter:on - andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax")); + andListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--andlist-withnomax"), createRequestDetails(rs)); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(andListDef); ourLog.info(def); //@formatter:off @@ -210,7 +212,7 @@ public class OperationServerWithSearchParamTypesDstu3Test { )); //@formatter:on - OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist")); + OperationDefinition orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist"), createRequestDetails(rs)); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef); ourLog.info(def); //@formatter:off @@ -226,7 +228,7 @@ public class OperationServerWithSearchParamTypesDstu3Test { )); //@formatter:on - orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax")); + orListDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient--orlist-withnomax"), createRequestDetails(rs)); def = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(orListDef); ourLog.info(def); //@formatter:off @@ -488,4 +490,11 @@ public class OperationServerWithSearchParamTypesDstu3Test { } + private RequestDetails createRequestDetails(RestfulServer theServer) { + ServletRequestDetails retVal = new ServletRequestDetails(null); + retVal.setServer(theServer); + return retVal; + } + + } diff --git a/hapi-fhir-structures-dstu3/src/test/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProviderDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProviderDstu3Test.java index 7eebf45d480..22c0ea18278 100644 --- a/hapi-fhir-structures-dstu3/src/test/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProviderDstu3Test.java +++ b/hapi-fhir-structures-dstu3/src/test/java/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProviderDstu3Test.java @@ -8,15 +8,17 @@ import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum; import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.ResourceBinding; import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestulfulServerConfiguration; +import ca.uhn.fhir.rest.server.RestfulServerConfiguration; import ca.uhn.fhir.rest.server.method.BaseMethodBinding; import ca.uhn.fhir.rest.server.method.IParameter; import ca.uhn.fhir.rest.server.method.SearchMethodBinding; import ca.uhn.fhir.rest.server.method.SearchParameter; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.validation.FhirValidator; import ca.uhn.fhir.validation.ValidationResult; @@ -106,7 +108,7 @@ public class ServerCapabilityStatementProviderDstu3Test { } } assertTrue(found); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -134,7 +136,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -157,7 +159,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -165,7 +167,7 @@ public class ServerCapabilityStatementProviderDstu3Test { assertEquals(1, conformance.getRest().get(0).getOperation().size()); assertEquals("everything", conformance.getRest().get(0).getOperation().get(0).getName()); - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs)); validate(opDef); assertEquals("everything", opDef.getCode()); assertThat(opDef.getSystem(), is(false)); @@ -185,7 +187,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs)); validate(opDef); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef); @@ -206,7 +208,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -238,7 +240,7 @@ public class ServerCapabilityStatementProviderDstu3Test { } assertTrue(found); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -258,7 +260,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -283,7 +285,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -296,7 +298,7 @@ public class ServerCapabilityStatementProviderDstu3Test { assertThat(operationIdParts, containsInAnyOrder("Patient-i-someOp", "Encounter-i-someOp", "Patient-i-validate", "Encounter-i-validate")); { - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-someOp"), createRequestDetails(rs)); validate(opDef); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); Set types = toStrings(opDef.getResource()); @@ -311,7 +313,7 @@ public class ServerCapabilityStatementProviderDstu3Test { assertEquals("Patient", opDef.getParameter().get(1).getType()); } { - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Encounter-i-someOp"), createRequestDetails(rs)); validate(opDef); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); Set types = toStrings(opDef.getResource()); @@ -326,7 +328,7 @@ public class ServerCapabilityStatementProviderDstu3Test { assertEquals("Encounter", opDef.getParameter().get(1).getType()); } { - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-validate"), createRequestDetails(rs)); validate(opDef); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef)); Set types = toStrings(opDef.getResource()); @@ -351,7 +353,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); @@ -367,15 +369,15 @@ public class ServerCapabilityStatementProviderDstu3Test { ServerCapabilityStatementProvider sc = new ServerCapabilityStatementProvider(rs) { @Override - public CapabilityStatement getServerConformance(HttpServletRequest theRequest) { - return super.getServerConformance(theRequest); + public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { + return super.getServerConformance(theRequest, createRequestDetails(rs)); } }; rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"), createRequestDetails(rs)); validate(opDef); assertEquals("plain", opDef.getCode()); @@ -410,7 +412,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -440,7 +442,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -460,7 +462,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -496,7 +498,7 @@ public class ServerCapabilityStatementProviderDstu3Test { } } assertTrue(found); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -532,7 +534,7 @@ public class ServerCapabilityStatementProviderDstu3Test { } } assertTrue(found); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -565,7 +567,7 @@ public class ServerCapabilityStatementProviderDstu3Test { } } assertTrue(found); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -583,8 +585,8 @@ public class ServerCapabilityStatementProviderDstu3Test { RestfulServer rsNoType = new RestfulServer(ourCtx) { @Override - public RestulfulServerConfiguration createConfiguration() { - RestulfulServerConfiguration retVal = super.createConfiguration(); + public RestfulServerConfiguration createConfiguration() { + RestfulServerConfiguration retVal = super.createConfiguration(); retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z")); return retVal; } @@ -594,14 +596,14 @@ public class ServerCapabilityStatementProviderDstu3Test { rsNoType.setServerConformanceProvider(scNoType); rsNoType.init(createServletConfig()); - CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = scNoType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsNoType)); String confNoType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(confNoType); RestfulServer rsWithType = new RestfulServer(ourCtx) { @Override - public RestulfulServerConfiguration createConfiguration() { - RestulfulServerConfiguration retVal = super.createConfiguration(); + public RestfulServerConfiguration createConfiguration() { + RestfulServerConfiguration retVal = super.createConfiguration(); retVal.setConformanceDate(new InstantDt("2011-02-22T11:22:33Z")); return retVal; } @@ -611,7 +613,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rsWithType.setServerConformanceProvider(scWithType); rsWithType.init(createServletConfig()); - CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformanceWithType = scWithType.getServerConformance(createHttpServletRequest(), createRequestDetails(rsWithType)); String confWithType = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformanceWithType); ourLog.info(confWithType); @@ -630,7 +632,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -649,7 +651,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -668,7 +670,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); ValidationResult result = ourCtx.newValidator().validateWithResult(conformance); @@ -685,7 +687,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); CapabilityStatementRestComponent restComponent = conformance.getRest().get(0); @@ -695,7 +697,7 @@ public class ServerCapabilityStatementProviderDstu3Test { String operationReference = operationComponent.getDefinition().getReference(); assertThat(operationReference, not(nullValue())); - OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference)); + OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference), createRequestDetails(rs)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition)); validate(operationDefinition); assertThat(operationDefinition.getCode(), is(NamedQueryPlainProvider.QUERY_NAME)); @@ -729,7 +731,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance)); CapabilityStatementRestComponent restComponent = conformance.getRest().get(0); @@ -737,7 +739,7 @@ public class ServerCapabilityStatementProviderDstu3Test { String operationReference = operationComponent.getDefinition().getReference(); assertThat(operationReference, not(nullValue())); - OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference)); + OperationDefinition operationDefinition = sc.readOperationDefinition(new IdType(operationReference), createRequestDetails(rs)); ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationDefinition)); validate(operationDefinition); assertThat("The operation name should be the code if no description is set", operationDefinition.getName(), is(NamedQueryResourceProvider.QUERY_NAME)); @@ -772,7 +774,7 @@ public class ServerCapabilityStatementProviderDstu3Test { rs.init(createServletConfig()); - CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest()); + CapabilityStatement conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -781,7 +783,7 @@ public class ServerCapabilityStatementProviderDstu3Test { assertThat(operations.size(), is(1)); assertThat(operations.get(0).getName(), is(TypeLevelOperationProvider.OPERATION_NAME)); - OperationDefinition opDef = sc.readOperationDefinition(new IdType(operations.get(0).getDefinition().getReference())); + OperationDefinition opDef = sc.readOperationDefinition(new IdType(operations.get(0).getDefinition().getReference()), createRequestDetails(rs)); validate(opDef); assertEquals(TypeLevelOperationProvider.OPERATION_NAME, opDef.getCode()); assertThat(opDef.getSystem(), is(false)); @@ -1157,4 +1159,10 @@ public class ServerCapabilityStatementProviderDstu3Test { TestUtil.clearAllStaticFieldsForUnitTest(); } + private RequestDetails createRequestDetails(RestfulServer theServer) { + ServletRequestDetails retVal = new ServletRequestDetails(null); + retVal.setServer(theServer); + return retVal; + } + } diff --git a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java index 773b2dd5d57..4af258ea60a 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/main/java/org/hl7/fhir/instance/conf/ServerConformanceProvider.java @@ -21,17 +21,16 @@ package org.hl7.fhir.instance.conf; */ import static org.apache.commons.lang3.StringUtils.isNotBlank; -import java.text.*; import java.util.*; import java.util.Map.Entry; -import java.util.concurrent.Callable; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.parser.DataFormatException; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.*; import org.hl7.fhir.instance.model.Conformance.*; @@ -65,14 +64,9 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType; * constructor. *

*/ -public class ServerConformanceProvider implements IServerConformanceProvider { +public class ServerConformanceProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider { - private boolean myCache = true; - private volatile Conformance myConformance; - private IdentityHashMap myOperationBindingToName; - private HashMap> myOperationNameToBindings; private String myPublisher = "Not provided"; - private Callable myServerConfiguration; /** * No-arg constructor and seetter so that the ServerConfirmanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen. @@ -83,31 +77,26 @@ public class ServerConformanceProvider implements IServerConformanceProvider theServerConfiguration; + public ServerConformanceProvider(RestfulServerConfiguration theServerConfiguration) { + super(theServerConfiguration); } @Override 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 systemOps, BaseMethodBinding nextMethodBinding) { if (nextMethodBinding.getRestOperationType() != null) { @@ -130,9 +119,9 @@ public class ServerConformanceProvider implements IServerConformanceProvider>> collectMethodBindings() { + private Map>> collectMethodBindings(RequestDetails theRequestDetails) { Map>> resourceToMethods = new TreeMap>>(); - for (ResourceBinding next : getServerConfiguration().getResourceBindings()) { + for (ResourceBinding next : getServerConfiguration(theRequestDetails).getResourceBindings()) { String resourceName = next.getResourceName(); for (BaseMethodBinding nextMethodBinding : next.getMethodBindings()) { if (resourceToMethods.containsKey(resourceName) == false) { @@ -141,10 +130,10 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextMethodBinding : getServerConfiguration().getServerBindings()) { + for (BaseMethodBinding nextMethodBinding : getServerConfiguration(theRequestDetails).getServerBindings()) { String resourceName = ""; if (resourceToMethods.containsKey(resourceName) == false) { - resourceToMethods.put(resourceName, new ArrayList>()); + resourceToMethods.put(resourceName, new ArrayList<>()); } resourceToMethods.get(resourceName).add(nextMethodBinding); } @@ -166,45 +155,45 @@ public class ServerConformanceProvider implements IServerConformanceProvider systemOps = new HashSet(); - Set operationNames = new HashSet(); + Set systemOps = new HashSet<>(); + Set operationNames = new HashSet<>(); - Map>> resourceToMethods = collectMethodBindings(); + Map>> resourceToMethods = collectMethodBindings(theRequestDetails); for (Entry>> nextEntry : resourceToMethods.entrySet()) { if (nextEntry.getKey().isEmpty() == false) { - Set resourceOps = new HashSet(); + Set resourceOps = new HashSet<>(); ConformanceRestResourceComponent resource = rest.addResource(); String resourceName = nextEntry.getKey(); - RuntimeResourceDefinition def = getServerConfiguration().getFhirContext().getResourceDefinition(resourceName); + RuntimeResourceDefinition def = serverConfiguration.getFhirContext().getResourceDefinition(resourceName); resource.getTypeElement().setValue(def.getName()); ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE)); - String serverBase = getServerConfiguration().getServerAddressStrategy().determineServerBase(servletContext, theRequest); + String serverBase = serverConfiguration.getServerAddressStrategy().determineServerBase(servletContext, theRequest); resource.getProfile().setReference((def.getResourceProfile(serverBase))); TreeSet includes = new TreeSet<>(); @@ -258,11 +247,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider buildDate = getServerConfiguration().getConformanceDate(); + private DateTimeType conformanceDate(RequestDetails theRequestDetails) { + IPrimitiveType buildDate = getServerConfiguration(theRequestDetails).getConformanceDate(); if (buildDate != null && buildDate.getValue() != null) { try { return new DateTimeType(buildDate.getValueAsString()); @@ -324,13 +312,13 @@ public class ServerConformanceProvider implements IServerConformanceProvider includes, - SearchMethodBinding searchMethodBinding) { + private void handleSearchMethodBinding(ConformanceRestResourceComponent resource, + RuntimeResourceDefinition def, TreeSet includes, + SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) { includes.addAll(searchMethodBinding.getIncludes()); List params = searchMethodBinding.getParameters(); - List searchParameters = new ArrayList(); + List searchParameters = new ArrayList<>(); for (IParameter nextParameter : params) { if ((nextParameter instanceof SearchParameter)) { searchParameters.add((SearchParameter) nextParameter); @@ -388,7 +376,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider nextTarget : nextParameter.getDeclaredTypes()) { - RuntimeResourceDefinition targetDef = getServerConfiguration().getFhirContext().getResourceDefinition(nextTarget); + RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget); if (targetDef != null) { ResourceType code; try { @@ -405,38 +393,14 @@ public class ServerConformanceProvider implements IServerConformanceProvider(); - myOperationNameToBindings = new HashMap<>(); - Map>> resourceToMethods = collectMethodBindings(); - for (Entry>> nextEntry : resourceToMethods.entrySet()) { - List> nextMethodBindings = nextEntry.getValue(); - for (BaseMethodBinding nextMethodBinding : nextMethodBindings) { - if (nextMethodBinding instanceof OperationMethodBinding) { - OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding; - if (myOperationBindingToName.containsKey(methodBinding)) { - continue; - } - - String name = createOperationName(methodBinding); - myOperationBindingToName.put(methodBinding, name); - if (myOperationNameToBindings.containsKey(name) == false) { - myOperationNameToBindings.put(name, new ArrayList<>()); - } - myOperationNameToBindings.get(name).add(methodBinding); - } - } - } - } @Read(type = OperationDefinition.class) - public OperationDefinition readOperationDefinition(@IdParam IdType theId) { + public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) { if (theId == null || theId.hasIdPart() == false) { throw new ResourceNotFoundException(theId); } - List sharedDescriptions = myOperationNameToBindings.get(theId.getIdPart()); + List sharedDescriptions = getServerConfiguration(theRequestDetails).provideBindings().getOperationNameToBindings().get(theId.getIdPart()); if (sharedDescriptions == null || sharedDescriptions.isEmpty()) { throw new ResourceNotFoundException(theId); } @@ -508,9 +472,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider + * @deprecated Since 4.0.0 this method doesn't do anything */ + @Deprecated public void setCache(boolean theCache) { - myCache = theCache; + // nothing } /** @@ -524,15 +490,6 @@ public class ServerConformanceProvider implements IServerConformanceProvider searchParameters) { - Collections.sort(searchParameters, new Comparator() { - @Override - public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) { - return theO1.getName().compareTo(theO2.getName()); - } - }); - } - private void sortSearchParameters(List searchParameters) { Collections.sort(searchParameters, new Comparator() { @Override diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderHl7OrgDstu2Test.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderHl7OrgDstu2Test.java index 2372fc56342..0971be5778f 100644 --- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderHl7OrgDstu2Test.java +++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderHl7OrgDstu2Test.java @@ -14,6 +14,8 @@ import java.util.*; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import org.hl7.fhir.instance.conf.ServerConformanceProvider; import org.hl7.fhir.instance.model.*; import org.hl7.fhir.instance.model.Conformance.*; @@ -62,7 +64,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -85,14 +87,14 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); assertEquals(1, conformance.getRest().get(0).getOperation().size()); assertEquals("$everything", conformance.getRest().get(0).getOperation().get(0).getName()); - assertEquals("OperationDefinition/everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference()); + assertEquals("OperationDefinition/Patient-i-everything", conformance.getRest().get(0).getOperation().get(0).getDefinition().getReference()); } @@ -107,7 +109,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/everything")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/Patient-i-everything"), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef); ourLog.info(conf); @@ -127,7 +129,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -159,7 +161,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -179,7 +181,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -214,7 +216,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -231,18 +233,18 @@ public class ServerConformanceProviderHl7OrgDstu2Test { ServerConformanceProvider sc = new ServerConformanceProvider(rs) { @Override - public Conformance getServerConformance(HttpServletRequest theRequest) { - return super.getServerConformance(theRequest); + public Conformance getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) { + return super.getServerConformance(theRequest, theRequestDetails); } }; rs.setServerConformanceProvider(sc); rs.init(createServletConfig()); - Conformance sconf = sc.getServerConformance(createHttpServletRequest()); - assertEquals("OperationDefinition/plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference()); + Conformance sconf = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); + assertEquals("OperationDefinition/-is-plain", sconf.getRest().get(0).getOperation().get(0).getDefinition().getReference()); - OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/plain")); + OperationDefinition opDef = sc.readOperationDefinition(new IdType("OperationDefinition/-is-plain"), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(opDef); ourLog.info(conf); @@ -273,7 +275,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -303,7 +305,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -323,7 +325,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -355,7 +357,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { } } assertTrue(found); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -376,7 +378,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -395,7 +397,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); String conf = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); ourLog.info(conf); @@ -414,7 +416,7 @@ public class ServerConformanceProviderHl7OrgDstu2Test { rs.init(createServletConfig()); - Conformance conformance = sc.getServerConformance(createHttpServletRequest()); + Conformance conformance = sc.getServerConformance(createHttpServletRequest(), createRequestDetails(rs)); assertTrue(ourCtx.newValidator().validateWithResult(conformance).isSuccessful()); } @@ -597,4 +599,10 @@ public class ServerConformanceProviderHl7OrgDstu2Test { } + private RequestDetails createRequestDetails(RestfulServer theServer) { + ServletRequestDetails retVal = new ServletRequestDetails(null); + retVal.setServer(theServer); + return retVal; + } + } diff --git a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.java b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.java index d5e50236bd0..2b51d539c3d 100644 --- a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.java +++ b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.java @@ -5,19 +5,16 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.parser.DataFormatException; import ca.uhn.fhir.rest.annotation.IdParam; -import ca.uhn.fhir.rest.annotation.Initialize; import ca.uhn.fhir.rest.annotation.Metadata; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.server.IServerConformanceProvider; -import ca.uhn.fhir.rest.server.ResourceBinding; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestulfulServerConfiguration; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.server.*; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.method.*; -import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; import ca.uhn.fhir.rest.server.method.SearchParameter; +import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType; +import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -28,13 +25,11 @@ import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; import org.hl7.fhir.r4.model.OperationDefinition.OperationDefinitionParameterComponent; import org.hl7.fhir.r4.model.OperationDefinition.OperationKind; import org.hl7.fhir.r4.model.OperationDefinition.OperationParameterUse; -import org.hl7.fhir.r4.model.codesystems.UnknownContentCode; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.Map.Entry; -import java.util.concurrent.Callable; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -67,17 +62,10 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; * false. This means that if you are adding anything to the returned conformance instance on each call you should call setCache(false) in your provider constructor. *

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

* See the class documentation for an important note if you are extending this class *

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