Handle extension errors Also proper signalling of those errors
Project: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/repo Commit: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/commit/08db7b15 Tree: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/tree/08db7b15 Diff: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/diff/08db7b15 Branch: refs/heads/master Commit: 08db7b15ce4239e243bac3ed4766f505842d7ac3 Parents: 3b81013 Author: Carlos Sierra <[email protected]> Authored: Fri Aug 25 14:36:24 2017 +0200 Committer: Carlos Sierra <[email protected]> Committed: Fri Aug 25 14:36:24 2017 +0200 ---------------------------------------------------------------------- jax-rs.itests/src/main/java/test/JaxrsTest.java | 201 ++++++++++++++++++- .../internal/AriesJaxRSServiceRuntime.java | 37 +++- .../internal/CXFJaxRsServiceRegistrator.java | 45 ++++- .../aries/jax/rs/whiteboard/internal/Utils.java | 36 +--- .../jax/rs/whiteboard/internal/Whiteboard.java | 159 ++++++++++++--- 5 files changed, 401 insertions(+), 77 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/08db7b15/jax-rs.itests/src/main/java/test/JaxrsTest.java ---------------------------------------------------------------------- diff --git a/jax-rs.itests/src/main/java/test/JaxrsTest.java b/jax-rs.itests/src/main/java/test/JaxrsTest.java index 1ed4a6c..9857ae4 100644 --- a/jax-rs.itests/src/main/java/test/JaxrsTest.java +++ b/jax-rs.itests/src/main/java/test/JaxrsTest.java @@ -46,6 +46,7 @@ import test.types.TestHelper; import javax.ws.rs.client.Client; import javax.ws.rs.client.WebTarget; +import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.core.Application; import javax.ws.rs.core.Response; @@ -870,21 +871,32 @@ public class JaxrsTest extends TestHelper { } @Test - public void testStandaloneFilter() { + public void testStandaloneFilter() throws InterruptedException { Client client = createClient(); WebTarget webTarget = client. target("http://localhost:8080"). path("test"); - ServiceRegistration<?> filterRegistration = null; + JaxRSServiceRuntime runtime = getJaxRSServiceRuntime(); ServiceRegistration<?> serviceRegistration = null; try { + RuntimeDTO runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + serviceRegistration = registerAddon(new TestAddon()); - filterRegistration = registerExtension("Filter"); + ServiceRegistration<?> filterRegistration = registerExtension( + "Filter"); + + runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 1, runtimeDTO.defaultApplication.extensionDTOs.length); Response response = webTarget.request().get(); @@ -893,13 +905,139 @@ public class JaxrsTest extends TestHelper { response.readEntity(String.class)); assertEquals("true", response.getHeaders().getFirst("Filtered")); + + filterRegistration.unregister(); + + runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); } finally { if (serviceRegistration != null) { serviceRegistration.unregister(); } - if (filterRegistration != null) { - filterRegistration.unregister(); + } + } + + @Test + public void testInvalidExtension() throws InterruptedException { + Client client = createClient(); + + WebTarget webTarget = client. + target("http://localhost:8080"). + path("test"); + + JaxRSServiceRuntime runtime = getJaxRSServiceRuntime(); + + ServiceRegistration<?> serviceRegistration = null; + + try { + RuntimeDTO runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + + serviceRegistration = registerAddon(new TestAddon()); + + ServiceRegistration<?> filterRegistration = + registerInvalidExtension("Filter"); + + runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + + assertEquals(1, runtimeDTO.failedExtensionDTOs.length); + assertEquals( + (long)filterRegistration.getReference().getProperty( + "service.id"), + runtimeDTO.failedExtensionDTOs[0].serviceId); + assertEquals( + DTOConstants.FAILURE_REASON_NOT_AN_EXTENSION_TYPE, + runtimeDTO.failedExtensionDTOs[0].failureReason); + + Response response = webTarget.request().get(); + + assertEquals( + "This should say hello", "Hello test", + response.readEntity(String.class)); + + assertNull(response.getHeaders().getFirst("Filtered")); + + filterRegistration.unregister(); + + runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + + assertEquals(0, runtimeDTO.failedExtensionDTOs.length); + } + finally { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + } + } + } + + @Test + public void testUngettableExtension() throws InterruptedException { + Client client = createClient(); + + WebTarget webTarget = client. + target("http://localhost:8080"). + path("test"); + + JaxRSServiceRuntime runtime = getJaxRSServiceRuntime(); + + ServiceRegistration<?> serviceRegistration = null; + + try { + RuntimeDTO runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + + serviceRegistration = registerAddon(new TestAddon()); + + ServiceRegistration<?> filterRegistration = + registerUngettableExtension("Filter"); + + runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + + assertEquals(1, runtimeDTO.failedExtensionDTOs.length); + assertEquals( + (long)filterRegistration.getReference().getProperty( + "service.id"), + runtimeDTO.failedExtensionDTOs[0].serviceId); + assertEquals( + DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE, + runtimeDTO.failedExtensionDTOs[0].failureReason); + + Response response = webTarget.request().get(); + + assertEquals( + "This should say hello", "Hello test", + response.readEntity(String.class)); + + assertNull(response.getHeaders().getFirst("Filtered")); + + filterRegistration.unregister(); + + runtimeDTO = runtime.getRuntimeDTO(); + + assertEquals( + 0, runtimeDTO.defaultApplication.extensionDTOs.length); + + assertEquals(0, runtimeDTO.failedExtensionDTOs.length); + } + finally { + if (serviceRegistration != null) { + serviceRegistration.unregister(); } } } @@ -1060,9 +1198,62 @@ public class JaxrsTest extends TestHelper { } return bundleContext.registerService( + ContainerResponseFilter.class, testFilter, properties); + } + + private ServiceRegistration<?> registerInvalidExtension( + String name, Object... keyValues) { + + TestFilter testFilter = new TestFilter(); + + Dictionary<String, Object> properties = new Hashtable<>(); + + properties.put(JAX_RS_EXTENSION, true); + properties.put(JAX_RS_NAME, name); + + for (int i = 0; i < keyValues.length; i = i + 2) { + properties.put(keyValues[i].toString(), keyValues[i + 1]); + } + + return bundleContext.registerService( Object.class, testFilter, properties); } + private ServiceRegistration<?> registerUngettableExtension( + String name, Object... keyValues) { + + Dictionary<String, Object> properties = new Hashtable<>(); + + properties.put(JAX_RS_EXTENSION, true); + properties.put(JAX_RS_NAME, name); + + for (int i = 0; i < keyValues.length; i = i + 2) { + properties.put(keyValues[i].toString(), keyValues[i + 1]); + } + + return bundleContext.registerService( + ContainerResponseFilter.class, + new ServiceFactory<ContainerResponseFilter>() { + @Override + public ContainerResponseFilter getService( + Bundle bundle, + ServiceRegistration<ContainerResponseFilter> + serviceRegistration) { + + return null; + } + + @Override + public void ungetService( + Bundle bundle, + ServiceRegistration<ContainerResponseFilter> + serviceRegistration, + ContainerResponseFilter containerResponseFilter) { + + } + }, properties); + } + private ServiceRegistration<Application> registerUngettableApplication( Object... keyValues) { http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/08db7b15/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/AriesJaxRSServiceRuntime.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/AriesJaxRSServiceRuntime.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/AriesJaxRSServiceRuntime.java index a098f82..2d2706e 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/AriesJaxRSServiceRuntime.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/AriesJaxRSServiceRuntime.java @@ -69,12 +69,19 @@ public class AriesJaxRSServiceRuntime implements JaxRSServiceRuntime { private TreeSet<ServiceReference<?>> _ungettableExtensions = new TreeSet<>(); private TreeSet<ServiceReference<?>> _dependentServices = new TreeSet<>(); + + private TreeSet<ServiceReference<?>> _invalidExtensions = new TreeSet<>(); + private Map<String, Object> _defaultApplicationProperties; public void addDependentService(ServiceReference<?> serviceReference) { _dependentServices.add(serviceReference); } + public void addInvalidExtension(ServiceReference<?> serviceReference) { + _invalidExtensions.add(serviceReference); + } + public void clearDefaultApplication() { _defaultApplicationProperties = Collections.emptyMap(); } @@ -107,6 +114,10 @@ public class AriesJaxRSServiceRuntime implements JaxRSServiceRuntime { _erroredApplications.remove(serviceReference); } + public void removeInvalidExtension(ServiceReference<?> serviceReference) { + _invalidExtensions.remove(serviceReference); + } + public boolean removeNotGettableApplication( ServiceReference<Application> serviceReference) { @@ -247,16 +258,23 @@ public class AriesJaxRSServiceRuntime implements JaxRSServiceRuntime { FailedResourceDTO[]::new ); - runtimeDTO.failedExtensionDTOs = unreferenciableExtensionsDTOStream().map( - sr -> buildFailedExtensionDTO( - DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE, sr) - ).toArray( - FailedExtensionDTO[]::new - ); + runtimeDTO.failedExtensionDTOs = Stream.concat( + unreferenciableExtensionsDTOStream(), + invalidExtensionsDTOStream() + ).toArray( + FailedExtensionDTO[]::new + ); return runtimeDTO; } + private Stream<FailedExtensionDTO> invalidExtensionsDTOStream() { + return _invalidExtensions.stream().map( + sr -> buildFailedExtensionDTO( + DTOConstants.FAILURE_REASON_NOT_AN_EXTENSION_TYPE, sr) + ); + } + private Stream<FailedResourceDTO> dependentServiceStreamDTO() { return _dependentServices.stream().map( sr -> buildFailedResourceDTO( @@ -282,8 +300,11 @@ public class AriesJaxRSServiceRuntime implements JaxRSServiceRuntime { return failedExtensionDTO; } - private Stream<ServiceReference<?>> unreferenciableExtensionsDTOStream() { - return _ungettableExtensions.stream(); + private Stream<FailedExtensionDTO> unreferenciableExtensionsDTOStream() { + return _ungettableExtensions.stream().map( + sr -> buildFailedExtensionDTO( + DTOConstants.FAILURE_REASON_SERVICE_NOT_GETTABLE, sr) + ); } private FailedResourceDTO buildFailedResourceDTO( http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/08db7b15/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java index 50d51a7..e06a907 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java @@ -18,11 +18,15 @@ package org.apache.aries.jax.rs.whiteboard.internal; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.stream.Stream; import javax.ws.rs.core.Application; +import javax.ws.rs.core.Feature; import org.apache.aries.jax.rs.whiteboard.internal.Utils.ComparableResourceProvider; +import org.apache.aries.jax.rs.whiteboard.internal.Utils.ServiceTuple; import org.apache.cxf.Bus; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; @@ -33,13 +37,16 @@ import org.apache.cxf.jaxrs.model.OperationResourceInfo; import org.apache.cxf.jaxrs.provider.json.JSONProvider; import org.apache.cxf.jaxrs.utils.ResourceUtils; import org.apache.cxf.message.Message; +import org.osgi.framework.ServiceReference; + +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.canonicalize; public class CXFJaxRsServiceRegistrator { private volatile boolean _closed = false; private final Application _application; private final Bus _bus; - private final Collection<Object> _providers = new ArrayList<>(); + private final Collection<ServiceTuple<?>> _providers = new ArrayList<>(); private Server _server; private final Collection<ResourceProvider> _services = new ArrayList<>(); @@ -60,12 +67,12 @@ public class CXFJaxRsServiceRegistrator { rewire(); } - public void addProvider(Utils.ServiceTuple<?> tuple) { + public void addProvider(ServiceTuple<?> tuple) { if (_closed) { return; } - _providers.add(tuple.getService()); + _providers.add(tuple); rewire(); } @@ -92,12 +99,12 @@ public class CXFJaxRsServiceRegistrator { rewire(); } - public void removeProvider(Utils.ServiceTuple<?> tuple) { + public void removeProvider(ServiceTuple<?> tuple) { if (_closed) { return; } - _providers.remove(tuple.getService()); + _providers.remove(tuple); rewire(); } @@ -166,8 +173,32 @@ public class CXFJaxRsServiceRegistrator { jaxRsServerFactoryBean.setProvider(jsonProvider); - for (Object provider : _providers) { - jaxRsServerFactoryBean.setProvider(provider); + for (ServiceTuple<?> provider : _providers) { + jaxRsServerFactoryBean.setProvider( + (Feature) featureContext -> { + ServiceReference<?> serviceReference = + provider.getServiceReference(); + + String[] interfaces = canonicalize( + serviceReference.getProperty("objectClass")); + + Class[] classes = Arrays.stream(interfaces).flatMap( + className -> { + try { + return Stream.of(Class.forName(className)); + } + catch (ClassNotFoundException e) { + return Stream.empty(); + } + } + ).toArray( + Class[]::new + ); + + featureContext.register(provider.getService(), classes); + + return true; + }); } for (ResourceProvider resourceProvider: _services) { http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/08db7b15/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Utils.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Utils.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Utils.java index 058c1a8..e013c14 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Utils.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Utils.java @@ -48,6 +48,16 @@ import static org.apache.aries.osgi.functional.OSGi.register; */ public class Utils { + public static String[] canonicalize(Object propertyValue) { + if (propertyValue == null) { + return new String[0]; + } + if (propertyValue instanceof String[]) { + return (String[]) propertyValue; + } + return new String[]{propertyValue.toString()}; + } + public static String generateApplicationName( PropertyHolder propertyHolder) { @@ -109,32 +119,6 @@ public class Utils { } } - public static OSGi<?> safeRegisterGeneric( - ServiceReference<?> serviceReference, - String applicationName, - CXFJaxRsServiceRegistrator registrator, - AriesJaxRSServiceRuntime runtime) { - - if (isExtension(serviceReference)) { - return safeRegisterExtension( - serviceReference, applicationName, registrator, runtime); - } - else { - return safeRegisterEndpoint( - serviceReference, applicationName, registrator, runtime); - } - } - - private static boolean isExtension(ServiceReference<?> serviceReference) { - Object extensionProperty = serviceReference.getProperty( - "osgi.jaxrs.extension"); - - return - (extensionProperty != null) && - (extensionProperty instanceof Boolean) && - ((boolean) extensionProperty); - } - public static OSGi<?> safeRegisterExtension( ServiceReference<?> serviceReference, String applicationName, CXFJaxRsServiceRegistrator registrator, http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/08db7b15/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Whiteboard.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Whiteboard.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Whiteboard.java index 5a586fc..02e1b73 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Whiteboard.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Whiteboard.java @@ -35,29 +35,46 @@ import org.osgi.service.http.runtime.HttpServiceRuntime; import org.osgi.service.jaxrs.runtime.JaxRSServiceRuntime; import javax.servlet.Servlet; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.container.DynamicFeature; import javax.ws.rs.core.Application; +import javax.ws.rs.core.Feature; +import javax.ws.rs.ext.ContextResolver; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.ParamConverterProvider; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Dictionary; import java.util.HashMap; +import java.util.HashSet; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; import java.util.function.Function; import static java.lang.String.format; import static org.apache.aries.jax.rs.whiteboard.internal.AriesJaxRSServiceRuntime.getApplicationName; +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.canonicalize; import static org.apache.aries.jax.rs.whiteboard.internal.Utils.deployRegistrator; import static org.apache.aries.jax.rs.whiteboard.internal.Utils.generateApplicationName; import static org.apache.aries.jax.rs.whiteboard.internal.Utils.getProperties; import static org.apache.aries.jax.rs.whiteboard.internal.Utils.highestPer; import static org.apache.aries.jax.rs.whiteboard.internal.Utils.onlyGettables; -import static org.apache.aries.jax.rs.whiteboard.internal.Utils.safeRegisterGeneric; +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.safeRegisterEndpoint; +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.safeRegisterExtension; import static org.apache.aries.jax.rs.whiteboard.internal.Utils.service; -import static org.apache.aries.osgi.functional.OSGi.NOOP; import static org.apache.aries.osgi.functional.OSGi.all; import static org.apache.aries.osgi.functional.OSGi.bundleContext; import static org.apache.aries.osgi.functional.OSGi.just; +import static org.apache.aries.osgi.functional.OSGi.nothing; +import static org.apache.aries.osgi.functional.OSGi.onClose; import static org.apache.aries.osgi.functional.OSGi.register; import static org.apache.aries.osgi.functional.OSGi.serviceReferences; import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT; @@ -85,9 +102,24 @@ public class Whiteboard { ServiceTuple::getServiceReference).andThen( sr -> getApplicationBase(sr::getProperty)); + public static final Collection<String> SUPPORTED_EXTENSION_INTERFACES = new HashSet<>( + Arrays.asList( + ContainerRequestFilter.class.getName(), + ContainerResponseFilter.class.getName(), + ReaderInterceptor.class.getName(), + WriterInterceptor.class.getName(), + MessageBodyReader.class.getName(), + MessageBodyWriter.class.getName(), + ContextResolver.class.getName(), + ExceptionMapper.class.getName(), + ParamConverterProvider.class.getName(), + Feature.class.getName(), + DynamicFeature.class.getName() + )); + public static final String DEFAULT_NAME = ".default"; - public static OSGi<Void> createWhiteboard(Dictionary<String, ?> configuration) { + public static OSGi<?> createWhiteboard(Dictionary<String, ?> configuration) { AriesJaxRSServiceRuntime runtime = new AriesJaxRSServiceRuntime(); Map<String, ?> configurationMap = Maps.from(configuration); @@ -99,18 +131,27 @@ public class Whiteboard { just(new ServiceRegistrationChangeCounter(runtimeRegistration)).flatMap(counter -> just(runtimeRegistration.getReference()).flatMap(runtimeReference -> all( - countChanges( + ignore(countChanges( whiteboardApplications( runtimeReference, runtime, configurationMap), - counter), - countChanges( - whiteBoardApplicationSingletons( + counter)), + ignore(countChanges( + whiteBoardApplicationResources( bundleContext, runtimeReference, defaultApplicationReference, runtime), - counter) + counter)), + ignore(countChanges( + whiteBoardApplicationExtensions( + bundleContext, runtimeReference, + defaultApplicationReference, runtime), + counter)) )))))); } + private static OSGi<Void> ignore(OSGi<?> program) { + return program.map(t -> { return null;}); + } + private static OSGi<Collection<String>> bestEffortCalculationOfEnpoints(Filter filter) { Collection<String> endPoints = new ArrayList<>(); @@ -127,16 +168,6 @@ public class Whiteboard { ); } - private static String[] canonicalize(Object propertyValue) { - if (propertyValue == null) { - return new String[0]; - } - if (propertyValue instanceof String[]) { - return (String[]) propertyValue; - } - return new String[]{propertyValue.toString()}; - } - private static ExtensionManagerBus createBus( BundleContext bundleContext, Map<String, ?> configuration) { @@ -232,7 +263,7 @@ public class Whiteboard { ApplicationReference applicationReference, AriesJaxRSServiceRuntime runtime, OSGi<?> program) { - String[] extensionDependencies = canonicalize( + String[] extensionDependencies = Utils.canonicalize( serviceReference.getProperty(JAX_RS_EXTENSION_SELECT)); if (extensionDependencies.length > 0) { @@ -273,34 +304,89 @@ public class Whiteboard { return program; } - private static OSGi<?> whiteBoardApplicationSingletons( + private static OSGi<?> whiteBoardApplicationResources( BundleContext bundleContext, ServiceReference<?> jaxRsRuntimeServiceReference, ApplicationReference defaultApplicationReference, AriesJaxRSServiceRuntime runtime) { return - serviceReferences(getApplicationSingletonsFilter()). + serviceReferences(getResourcesFilter()). filter(new TargetFilter<>(jaxRsRuntimeServiceReference)). - flatMap(endpointReference -> - chooseApplication(endpointReference, defaultApplicationReference). + flatMap(resourceReference -> + chooseApplication( + resourceReference, just(defaultApplicationReference)). flatMap(applicationReference -> waitForExtensionDependencies( - bundleContext, endpointReference, applicationReference, runtime, - safeRegisterGeneric( - endpointReference, + bundleContext, resourceReference, applicationReference, + runtime, + safeRegisterEndpoint( + resourceReference, applicationReference.getApplicationName(), applicationReference.getRegistrator(), runtime) ))); } + private static OSGi<?> whiteBoardApplicationExtensions( + BundleContext bundleContext, + ServiceReference<?> jaxRsRuntimeServiceReference, + ApplicationReference defaultApplicationReference, + AriesJaxRSServiceRuntime runtime) { + return + onlySupportedInterfaces( + serviceReferences(getApplicationExtensionsFilter()). + filter(new TargetFilter<>(jaxRsRuntimeServiceReference)), + runtime::addInvalidExtension, runtime::removeInvalidExtension). + flatMap(endpointReference -> + chooseApplication( + endpointReference, + all( + just(defaultApplicationReference), + allApplicationReferences())). + flatMap(applicationReference -> + waitForExtensionDependencies( + bundleContext, endpointReference, applicationReference, runtime, + safeRegisterExtension( + endpointReference, + applicationReference.getApplicationName(), + applicationReference.getRegistrator(), runtime) + ))); + } + + private static OSGi<ServiceReference<Object>> onlySupportedInterfaces( + OSGi<ServiceReference<Object>> program, + Consumer<ServiceReference<?>> onInvalidAdded, + Consumer<ServiceReference<?>> onInvalidRemoved) { + + return program.flatMap(sr -> { + if (signalsValidInterface(sr)) { + return just(sr); + } + else { + onInvalidAdded.accept(sr); + return + onClose(() -> onInvalidRemoved.accept(sr)).then(nothing()); + } + }); + } + + private static boolean signalsValidInterface( + ServiceReference<Object> serviceReference) { + + String[] objectClasses = canonicalize(serviceReference.getProperty( + "objectClass")); + + return Arrays.stream(objectClasses). + anyMatch(SUPPORTED_EXTENSION_INTERFACES::contains); + } + private static OSGi<ApplicationReference> chooseApplication( - ServiceReference<?> serviceReference, ApplicationReference theDefault) { + ServiceReference<?> serviceReference, OSGi<ApplicationReference> theDefault) { Object applicationSelectProperty = serviceReference.getProperty( JAX_RS_APPLICATION_SELECT); if (applicationSelectProperty == null) { - return just(theDefault); + return theDefault; } String applicationName = getApplicationName( @@ -316,11 +402,22 @@ public class Whiteboard { )); } - private static String getApplicationSingletonsFilter() { + public static OSGi<ApplicationReference> allApplicationReferences() { + return + serviceReferences(CXFJaxRsServiceRegistrator.class). + flatMap(registratorReference -> + just(getApplicationName(registratorReference::getProperty)). + flatMap(applicationName -> + service(registratorReference).flatMap(registrator -> + just(new ApplicationReference(applicationName, registrator)) + ))); + } + + private static String getApplicationExtensionsFilter() { return format( - "(&(!(objectClass=%s))(|%s%s))", + "(&(!(objectClass=%s))(%s=%s)%s)", ApplicationExtensionRegistration.class.getName(), - getExtensionsFilter(), getResourcesFilter()); + JAX_RS_EXTENSION, true, getExtensionsFilter()); } private static OSGi<?> whiteboardApplications(
