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 299cf0744be..51591ed0fec 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 @@ -91,10 +91,13 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.jar.Manifest; @@ -106,7 +109,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank; /** * This class is the central class for the HAPI FHIR Plain Server framework. - * + *

* See HAPI FHIR Plain Server * for information on how to use this framework. */ @@ -184,7 +187,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer> getProviderMethodBindings(Object theProvider) { + Set> retVal = new HashSet<>(); + for (ResourceBinding resourceBinding : getResourceBindings()) { + for (BaseMethodBinding methodBinding : resourceBinding.getMethodBindings()) { + if (theProvider.equals(methodBinding.getProvider())) { + retVal.add(methodBinding); + } + } + } + + return retVal; + } + /** * Provides the resource providers for this server */ @@ -1001,8 +1017,8 @@ public class RestfulServer extends HttpServlet implements IRestfulServer resourceNames, Object theProvider) { for (String resourceName : resourceNames) { - myResourceNameToBinding.remove(resourceName); + ResourceBinding resourceBinding = myResourceNameToBinding.get(resourceName); + if (resourceBinding == null) { + continue; + } + + for (Iterator> it = resourceBinding.getMethodBindings().iterator(); it.hasNext(); ) { + BaseMethodBinding binding = it.next(); + if (theProvider.equals(binding.getProvider())) { + it.remove(); + ourLog.info("{} binding of {} was removed", resourceName, binding); + } + } + + if (resourceBinding.getMethodBindings().isEmpty()) { + myResourceNameToBinding.remove(resourceName); + } } } diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/RestfulServerTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/RestfulServerTest.java index a0ce231ff05..95c67bec9bb 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/RestfulServerTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/RestfulServerTest.java @@ -3,14 +3,19 @@ package ca.uhn.fhir.rest.server; import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.rest.annotation.Create; import ca.uhn.fhir.rest.annotation.Metadata; +import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.ResourceParam; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.server.IFhirVersionServer; import ca.uhn.fhir.rest.api.server.RequestDetails; +import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseConformance; +import org.hl7.fhir.instance.model.api.IBaseMetaType; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -21,12 +26,10 @@ import org.mockito.junit.jupiter.MockitoExtension; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import java.io.Serializable; +import java.util.List; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class RestfulServerTest { @@ -43,6 +46,32 @@ public class RestfulServerTest { restfulServer.init(); } + private void mockResource(Class theClass) { + RuntimeResourceDefinition resourceDefinitionMock = mock(RuntimeResourceDefinition.class); + String className = theClass.getSimpleName(); + lenient().when(resourceDefinitionMock.getName()).thenReturn(className); + lenient().when(myCtx.getResourceDefinition(className)).thenReturn(resourceDefinitionMock); + lenient().when(myCtx.getResourceType(theClass)).thenReturn(className); + } + + @Test + public void testRegisterProvidersWithMethodBindings() { + mockResource(MyResource.class); + mockResource(MyResource2.class); + + MyProvider provider = new MyProvider(); + restfulServer.registerProvider(provider); + MyProvider2 provider2 = new MyProvider2(); + restfulServer.registerProvider(provider2); + + assertFalse(restfulServer.getProviderMethodBindings(provider).isEmpty()); + assertFalse(restfulServer.getProviderMethodBindings(provider2).isEmpty()); + + restfulServer.unregisterProvider(provider); + assertTrue(restfulServer.getProviderMethodBindings(provider).isEmpty()); + assertFalse(restfulServer.getProviderMethodBindings(provider2).isEmpty()); + } + @Test public void testRegisterProviders() { //test register Plain Provider @@ -123,4 +152,89 @@ public class RestfulServerTest { } } + private static class MyProvider implements IResourceProvider { + @Operation(name = "SHOW_ME_THE_MONEY", typeName = "MyResource") + public IBaseBundle match() { + return mock(IBaseBundle.class); + } + + @Override + public Class getResourceType() { + return MyResource.class; + } + } + + private static class MyProvider2 implements IResourceProvider { + @Operation(name = "SHOW_ME_MORE_MONEY", typeName = "MyResource2") + public IBaseBundle match() { + return mock(IBaseBundle.class); + } + + @Override + public Class getResourceType() { + return MyResource2.class; + } + } + + private static class MyResource implements IBaseResource { + + @Override + public boolean isEmpty() { + return false; + } + + @Override + public boolean hasFormatComment() { + return false; + } + + @Override + public List getFormatCommentsPre() { + return null; + } + + @Override + public List getFormatCommentsPost() { + return null; + } + + @Override + public Object getUserData(String theName) { + return null; + } + + @Override + public void setUserData(String theName, Object theValue) { + + } + + @Override + public IBaseMetaType getMeta() { + return null; + } + + @Override + public IIdType getIdElement() { + return null; + } + + @Override + public IBaseResource setId(String theId) { + return null; + } + + @Override + public IBaseResource setId(IIdType theId) { + return null; + } + + @Override + public FhirVersionEnum getStructureFhirVersionEnum() { + return null; + } + } + + private static class MyResource2 extends MyResource { + } + }