Repository: aries-jax-rs-whiteboard Updated Branches: refs/heads/master 7a47410aa -> ba62d9220
multiple, configurable whiteboards Signed-off-by: Raymond Augé <[email protected]> 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/506532b3 Tree: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/tree/506532b3 Diff: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/diff/506532b3 Branch: refs/heads/master Commit: 506532b3d500b1c50be9795c6945d8fec6145644 Parents: 7a47410 Author: Raymond Auge <[email protected]> Authored: Fri Jun 30 23:32:27 2017 -0400 Committer: Raymond Auge <[email protected]> Committed: Sun Jul 2 16:05:26 2017 -0400 ---------------------------------------------------------------------- .../main/java/test/WhiteboardFactoryTest.java | 117 +++++++ .../activator/CXFJaxRsBundleActivator.java | 223 +++----------- .../internal/AriesJaxRSServiceRuntime.java | 74 +++++ .../internal/CXFJaxRsServiceRegistrator.java | 1 - .../aries/jax/rs/whiteboard/internal/Maps.java | 39 +++ .../jax/rs/whiteboard/internal/Strings.java | 44 +++ .../jax/rs/whiteboard/internal/Whiteboard.java | 305 +++++++++++++++++++ .../internal/WhiteboardServiceFactory.java | 66 ++++ 8 files changed, 689 insertions(+), 180 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/jax-rs.itests/src/main/java/test/WhiteboardFactoryTest.java ---------------------------------------------------------------------- diff --git a/jax-rs.itests/src/main/java/test/WhiteboardFactoryTest.java b/jax-rs.itests/src/main/java/test/WhiteboardFactoryTest.java new file mode 100644 index 0000000..810dcc2 --- /dev/null +++ b/jax-rs.itests/src/main/java/test/WhiteboardFactoryTest.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.Hashtable; + +import org.junit.Test; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; +import org.osgi.service.cm.Configuration; +import org.osgi.service.cm.ConfigurationAdmin; +import org.osgi.service.jaxrs.runtime.JaxRSServiceRuntime; +import org.osgi.util.tracker.ServiceTracker; + +public class WhiteboardFactoryTest { + + @Test + public void testDefaultDefaultWhiteboardConfig() throws Exception { + ServiceTracker<JaxRSServiceRuntime, JaxRSServiceRuntime> runtimeTracker = + new ServiceTracker<>( + bundleContext, JaxRSServiceRuntime.class, null); + + try { + runtimeTracker.open(); + + JaxRSServiceRuntime runtime = runtimeTracker.waitForService(5000); + + assertNotNull(runtime); + + ServiceReference<JaxRSServiceRuntime> serviceReference = runtimeTracker.getServiceReference(); + + assertNotNull(serviceReference); + + assertEquals(1, runtimeTracker.size()); + } + finally { + runtimeTracker.close(); + } + } + + @Test + public void testCreateNewInstance() throws Exception { + ServiceTracker<ConfigurationAdmin, ConfigurationAdmin> configTracker = + new ServiceTracker<>( + bundleContext, ConfigurationAdmin.class, null); + + ServiceTracker<JaxRSServiceRuntime, JaxRSServiceRuntime> runtimeTracker = + new ServiceTracker<>( + bundleContext, JaxRSServiceRuntime.class, null); + + try { + configTracker.open(); + runtimeTracker.open(); + + JaxRSServiceRuntime runtime = runtimeTracker.waitForService(5000); + + assertNotNull(runtime); + + ServiceReference<JaxRSServiceRuntime> serviceReference = runtimeTracker.getServiceReference(); + + assertNotNull(serviceReference); + + assertEquals(1, runtimeTracker.size()); + + int trackingCount = runtimeTracker.getTrackingCount(); + + ConfigurationAdmin admin = configTracker.waitForService(5000); + + Configuration configuration = admin.createFactoryConfiguration( + "org.apache.aries.jax.rs.whiteboard", "?"); + + configuration.update(new Hashtable<>()); + + do { + Thread.sleep(50); + } + while (runtimeTracker.getTrackingCount() <= trackingCount); + + assertEquals(2, runtimeTracker.size()); + + configuration.delete(); + + do { + Thread.sleep(50); + } + while (runtimeTracker.getTrackingCount() <= trackingCount); + + assertEquals(1, runtimeTracker.size()); + } + finally { + runtimeTracker.close(); + configTracker.close(); + } + } + + private BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext(); + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java index d2a9204..4fa17c8 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java @@ -17,216 +17,81 @@ package org.apache.aries.jax.rs.whiteboard.activator; -import javax.servlet.Servlet; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.core.Application; +import java.util.Dictionary; +import java.util.Hashtable; +import java.util.concurrent.Executors; + import javax.ws.rs.ext.RuntimeDelegate; -import org.apache.aries.jax.rs.whiteboard.internal.CXFJaxRsServiceRegistrator; -import org.apache.aries.jax.rs.whiteboard.internal.ClientBuilderFactory; -import org.apache.aries.jax.rs.whiteboard.internal.DefaultApplication; -import org.apache.aries.jax.rs.whiteboard.internal.DefaultWeb; -import org.apache.aries.osgi.functional.OSGi; -import org.apache.aries.osgi.functional.OSGiResult; -import org.apache.cxf.Bus; -import org.apache.cxf.BusFactory; -import org.apache.cxf.bus.CXFBusFactory; -import org.apache.cxf.transport.servlet.CXFNonSpringServlet; +import org.apache.aries.jax.rs.whiteboard.internal.WhiteboardServiceFactory; +import org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; -import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; -import org.osgi.framework.wiring.BundleWiring; -import org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedServiceFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Dictionary; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Map; - -import static java.lang.String.format; -import static org.apache.aries.jax.rs.whiteboard.internal.Utils.*; -import static org.apache.aries.osgi.functional.OSGi.just; -import static org.apache.aries.osgi.functional.OSGi.serviceReferences; -import static org.apache.aries.osgi.functional.OSGi.services; -import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.*; -import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME; -import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT; -import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME; -import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN; -import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_APPLICATION_SELECT; - public class CXFJaxRsBundleActivator implements BundleActivator { private static final Logger _log = LoggerFactory.getLogger(CXFJaxRsBundleActivator.class); - private OSGiResult<?> _applicationsResult; - private OSGiResult<?> _applicationSingletonsResult; - private BundleContext _bundleContext; - private Bus _bus; - private ServiceRegistration<ClientBuilder> _clientBuilder; - private ServiceRegistration<DefaultWeb> _defaultWeb; - private OSGiResult<?> _extensionsResult; - private OSGiResult<?> _singletonsResult; + static { + RuntimeDelegate.setInstance(new RuntimeDelegateImpl()); + } + + private ServiceRegistration<ManagedServiceFactory> _serviceRegistration; + private WhiteboardServiceFactory _whiteboardServiceFactory; + private String _defaultName; @Override public void start(BundleContext bundleContext) throws Exception { - _bundleContext = bundleContext; - if (_log.isDebugEnabled()) { - _log.debug("Beginning initialization"); + _log.debug("Starting the whiteboard factory"); } - initRuntimeDelegate(bundleContext); - - // TODO make the context path of the JAX-RS Whiteboard configurable. - _bus = BusFactory.newInstance( - CXFBusFactory.class.getName()).createBus(); - registerCXFServletService(_bus); - - OSGi<?> applications = - repeatInOrder( - serviceReferences(Application.class, getApplicationFilter())). - flatMap(ref -> - just( - CXFJaxRsServiceRegistrator.getProperties( - ref, JAX_RS_APPLICATION_BASE)). - flatMap(properties -> - service(ref).flatMap(application -> - cxfRegistrator(_bus, application, properties) - ))); - - _applicationsResult = applications.run(bundleContext); - - OSGi<?> applicationSingletons = - serviceReferences(format("(%s=*)", JAX_RS_APPLICATION_SELECT)). - flatMap(ref -> - just(ref.getProperty(JAX_RS_APPLICATION_SELECT).toString()). - flatMap(applicationFilter -> - services(CXFJaxRsServiceRegistrator.class, applicationFilter). - flatMap(registrator -> - safeRegisterGeneric(ref, registrator) - ))); - - _applicationSingletonsResult = applicationSingletons.run(bundleContext); - - Map<String, Object> properties = new HashMap<>(); - properties.put(JAX_RS_APPLICATION_BASE, "/"); - properties.put(JAX_RS_NAME, ".default"); - - CXFJaxRsServiceRegistrator defaultServiceRegistrator = - new CXFJaxRsServiceRegistrator( - _bus, new DefaultApplication(), properties); - - OSGi<?> extensions = - serviceReferences(getExtensionFilter()).flatMap(ref -> - waitForExtensionDependencies(ref, - safeRegisterExtension(ref, defaultServiceRegistrator) - ) - ); - - _extensionsResult = extensions.run(bundleContext); - - OSGi<?> singletons = - serviceReferences(getSingletonsFilter()). - flatMap(serviceReference -> - waitForExtensionDependencies(serviceReference, - safeRegisterEndpoint( - serviceReference, defaultServiceRegistrator) - ) - ); - - _singletonsResult = singletons.run(bundleContext); - - Dictionary<String, Object> dictionary = new Hashtable<>(); - dictionary.put(JAX_RS_APPLICATION_SELECT, "(osgi.jaxrs.name=.default)"); - dictionary.put(JAX_RS_RESOURCE, "true"); - dictionary.put(Constants.SERVICE_RANKING, -1); - - _defaultWeb = _bundleContext.registerService( - DefaultWeb.class, new DefaultWeb(), dictionary); - _clientBuilder = _bundleContext.registerService( - ClientBuilder.class, new ClientBuilderFactory(), null); - } - - @Override - public void stop(BundleContext context) throws Exception { - _clientBuilder.unregister(); - _defaultWeb.unregister(); - _applicationsResult.close(); - _applicationSingletonsResult.close(); - _extensionsResult.close(); - _singletonsResult.close(); - } + _whiteboardServiceFactory = new WhiteboardServiceFactory(bundleContext); - private static String buildExtensionFilter(String filter) { - return String.format("(&%s%s)", getExtensionFilter(), filter); - } + _defaultName = _whiteboardServiceFactory.getName() + ".default"; - 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()}; - } + Dictionary<String, Object> properties = new Hashtable<>(); + properties.put(Constants.SERVICE_PID, _whiteboardServiceFactory.getName()); - private static CXFNonSpringServlet createCXFServlet(Bus bus) { - CXFNonSpringServlet cxfNonSpringServlet = new CXFNonSpringServlet(); - cxfNonSpringServlet.setBus(bus); - return cxfNonSpringServlet; - } + _serviceRegistration = bundleContext.registerService( + ManagedServiceFactory.class, _whiteboardServiceFactory, properties); - private static String getApplicationFilter() { - return format("(%s=*)", JAX_RS_APPLICATION_BASE); - } + if (_log.isDebugEnabled()) { + _log.debug("Whiteboard factory started"); + } - private static String getExtensionFilter() { - return format("(%s=*)", JAX_RS_EXTENSION); - } + Executors.newSingleThreadExecutor().submit(() -> { + try { + Dictionary<String, Object> defaultConfiguration = new Hashtable<>(); - private static String getSingletonsFilter() { - return format("(%s=true)", JAX_RS_RESOURCE); - } + defaultConfiguration.put(Constants.SERVICE_PID, _defaultName); - /** - * Initialize instance so it is never looked up again - * @param bundleContext - */ - private void initRuntimeDelegate(BundleContext bundleContext) { - RuntimeDelegate.setInstance(new org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl()); + _whiteboardServiceFactory.updated(_defaultName, defaultConfiguration); + } catch (ConfigurationException ce) { + _log.error("Configuration error", ce); + } + }); } - private ServiceRegistration<Servlet> registerCXFServletService(Bus bus) { - Dictionary<String, Object> properties = new Hashtable<>(); - properties.put(HTTP_WHITEBOARD_CONTEXT_SELECT, - format("(%s=%s)", HTTP_WHITEBOARD_CONTEXT_NAME, - HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME)); - properties.put(HTTP_WHITEBOARD_SERVLET_PATTERN, "/*"); - properties.put(Constants.SERVICE_RANKING, -1); - CXFNonSpringServlet cxfNonSpringServlet = createCXFServlet(bus); - return _bundleContext.registerService( - Servlet.class, cxfNonSpringServlet, properties); - } + @Override + public void stop(BundleContext context) throws Exception { + if (_log.isDebugEnabled()) { + _log.debug("Stopping whiteboard factory"); + } - private static OSGi<?> waitForExtensionDependencies( - ServiceReference<?> serviceReference, OSGi<?> program) { + _serviceRegistration.unregister(); - String[] extensionDependencies = canonicalize( - serviceReference.getProperty(JAX_RS_EXTENSION_SELECT)); + _whiteboardServiceFactory.deleted(_defaultName); - for (String extensionDependency : extensionDependencies) { - program = - serviceReferences(buildExtensionFilter(extensionDependency)). - then(program); + if (_log.isDebugEnabled()) { + _log.debug("Stopped whiteboard factory"); } - - return program; } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/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 new file mode 100644 index 0000000..536cd23 --- /dev/null +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/AriesJaxRSServiceRuntime.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.aries.jax.rs.whiteboard.internal; + +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.cxf.Bus; +import org.apache.cxf.transport.servlet.CXFNonSpringServlet; +import org.osgi.service.jaxrs.runtime.JaxRSServiceRuntime; +import org.osgi.service.jaxrs.runtime.dto.RequestInfoDTO; +import org.osgi.service.jaxrs.runtime.dto.RuntimeDTO; + +public class AriesJaxRSServiceRuntime + extends HttpServlet implements JaxRSServiceRuntime { + + private static final long serialVersionUID = 1L; + + private final Bus _bus; + private final CXFNonSpringServlet _cxfNonSpringServlet; + + public AriesJaxRSServiceRuntime(Bus bus) { + _bus = bus; + + CXFNonSpringServlet cxfNonSpringServlet = new CXFNonSpringServlet(); + cxfNonSpringServlet.setBus(_bus); + + _cxfNonSpringServlet = cxfNonSpringServlet; + } + + @Override + public RequestInfoDTO calculateRequestInfoDTO(String path) { + return null; + } + + @Override + public RuntimeDTO getRuntimeDTO() { + return null; + } + + @Override + public void init(ServletConfig config) throws ServletException { + _cxfNonSpringServlet.init(config); + } + + @Override + protected void service( + HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + _cxfNonSpringServlet.service(request, response); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/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 e89f6f6..43c9f1a 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 @@ -28,7 +28,6 @@ import java.util.Set; import java.util.TreeSet; import javax.ws.rs.core.Application; -import javax.ws.rs.ext.RuntimeDelegate; import org.apache.cxf.Bus; import org.apache.cxf.endpoint.Server; http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Maps.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Maps.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Maps.java new file mode 100644 index 0000000..a5f1b48 --- /dev/null +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Maps.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.aries.jax.rs.whiteboard.internal; + +import java.util.Dictionary; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +public class Maps { + + public static <K, V> Map<K, V> from(Dictionary<K, V> dictionary) { + Map<K, V> map = new HashMap<>(); + + for (Enumeration<K> keys = dictionary.keys(); keys.hasMoreElements();) { + K k = keys.nextElement(); + + map.put(k, dictionary.get(k)); + } + + return map; + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Strings.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Strings.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Strings.java new file mode 100644 index 0000000..7fc2ac5 --- /dev/null +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Strings.java @@ -0,0 +1,44 @@ +package org.apache.aries.jax.rs.whiteboard.internal; + +import java.lang.reflect.ParameterizedType; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +public class Strings { + + @SuppressWarnings({"unchecked" }) + public static Optional<List<String>> stringPlus(Object obj) { + if (obj == null) { + return Optional.empty(); + } + + List<String> strings = new ArrayList<>(); + + if (obj instanceof String) { + strings.add((String)obj); + } + else if (Collection.class.isInstance(obj) && + (ParameterizedType.class.isAssignableFrom(obj.getClass())) && + ((ParameterizedType)obj).getActualTypeArguments()[0].equals(String.class)) { + + for (String item : (Collection<String>)obj) { + strings.add(item); + } + } + else if (obj.getClass().isArray() && + String.class.isAssignableFrom(obj.getClass().getComponentType())) { + + for (String item : (String[])obj) { + strings.add(item); + } + } + else { + return Optional.empty(); + } + + return Optional.of(strings); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/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 new file mode 100644 index 0000000..a15b07f --- /dev/null +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/Whiteboard.java @@ -0,0 +1,305 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.aries.jax.rs.whiteboard.internal; + +import static java.lang.String.format; +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.cxfRegistrator; +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.repeatInOrder; +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.safeRegisterGeneric; +import static org.apache.aries.jax.rs.whiteboard.internal.Utils.service; +import static org.apache.aries.osgi.functional.OSGi.just; +import static org.apache.aries.osgi.functional.OSGi.serviceReferences; +import static org.apache.aries.osgi.functional.OSGi.services; +import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_SELECT; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_PATTERN; +import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET; +import static org.osgi.service.jaxrs.runtime.JaxRSServiceRuntimeConstants.JAX_RS_SERVICE_ENDPOINT; +import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_APPLICATION_BASE; +import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_APPLICATION_SELECT; +import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_EXTENSION; +import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_EXTENSION_SELECT; +import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_NAME; +import static org.osgi.service.jaxrs.whiteboard.JaxRSWhiteboardConstants.JAX_RS_RESOURCE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; +import java.util.Optional; + +import javax.servlet.Servlet; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.core.Application; + +import org.apache.aries.osgi.functional.OSGi; +import org.apache.aries.osgi.functional.OSGiResult; +import org.apache.cxf.Bus; +import org.apache.cxf.bus.extension.ExtensionManagerBus; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.Filter; +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.osgi.framework.ServiceRegistration; +import org.osgi.framework.wiring.BundleWiring; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.http.runtime.HttpServiceRuntime; +import org.osgi.service.jaxrs.runtime.JaxRSServiceRuntime; +import org.osgi.util.tracker.ServiceTracker; + +public class Whiteboard implements AutoCloseable { + + public Whiteboard( + BundleContext bundleContext, Map<String, Object> configuration) + throws ConfigurationException { + + BundleWiring wiring = bundleContext.getBundle().adapt(BundleWiring.class); + + configuration.put(_ID, configuration.get(Constants.SERVICE_PID)); + + ExtensionManagerBus bus = new ExtensionManagerBus(null, configuration, wiring.getClassLoader()); + + bus.initialize(); + + _runtimeRegistration = registerJaxRSServiceRuntime(bundleContext, bus, configuration); + + OSGi<?> applications = + repeatInOrder( + serviceReferences(Application.class, getApplicationFilter())). + flatMap(ref -> + just( + CXFJaxRsServiceRegistrator.getProperties( + ref, JAX_RS_APPLICATION_BASE)). + flatMap(properties -> + service(ref).flatMap(application -> + cxfRegistrator(bus, application, properties) + ))); + + _applicationsResult = applications.run(bundleContext); + + OSGi<?> applicationSingletons = + serviceReferences(format("(%s=*)", JAX_RS_APPLICATION_SELECT)). + flatMap(ref -> + just(ref.getProperty(JAX_RS_APPLICATION_SELECT).toString()). + flatMap(applicationFilter -> + services(CXFJaxRsServiceRegistrator.class, applicationFilter). + flatMap(registrator -> + safeRegisterGeneric(ref, registrator) + ))); + + _applicationSingletonsResult = applicationSingletons.run(bundleContext); + + Map<String, Object> properties = new HashMap<>(); + properties.put(JAX_RS_APPLICATION_BASE, "/"); + properties.put(JAX_RS_NAME, ".default"); + + CXFJaxRsServiceRegistrator defaultServiceRegistrator = + new CXFJaxRsServiceRegistrator( + bus, new DefaultApplication(), properties); + + OSGi<?> extensions = + serviceReferences(getExtensionFilter()).flatMap(ref -> + waitForExtensionDependencies(ref, + safeRegisterExtension(ref, defaultServiceRegistrator) + ) + ); + + _extensionsResult = extensions.run(bundleContext); + + OSGi<?> singletons = + serviceReferences(getSingletonsFilter()). + flatMap(serviceReference -> + waitForExtensionDependencies(serviceReference, + safeRegisterEndpoint( + serviceReference, defaultServiceRegistrator) + ) + ); + + _singletonsResult = singletons.run(bundleContext); + + Dictionary<String, Object> dictionary = new Hashtable<>(); + dictionary.put(JAX_RS_APPLICATION_SELECT, "(osgi.jaxrs.name=.default)"); + dictionary.put(JAX_RS_RESOURCE, "true"); + dictionary.put(Constants.SERVICE_RANKING, -1); + + _defaultWeb = bundleContext.registerService( + DefaultWeb.class, new DefaultWeb(), dictionary); + _clientBuilder = bundleContext.registerService( + ClientBuilder.class, new ClientBuilderFactory(), null); + } + + @Override + public void close() { + _clientBuilder.unregister(); + _defaultWeb.unregister(); + _applicationsResult.close(); + _applicationSingletonsResult.close(); + _extensionsResult.close(); + _singletonsResult.close(); + _runtimeRegistration.unregister(); + } + + private void bestEffortCalculationOfEnpoints( + Dictionary<String, Object> properties, BundleContext bundleContext) + throws ConfigurationException { + + String targetFilter = (String)properties.get(HTTP_WHITEBOARD_TARGET); + + Filter filter; + + try { + filter = bundleContext.createFilter(format( + "(&(objectClass=%s)%s)", + HttpServiceRuntime.class.getName(), + targetFilter)); + } + catch (InvalidSyntaxException ise) { + throw new ConfigurationException( + HTTP_WHITEBOARD_TARGET, format("Invalid syntax for filter {}", targetFilter)); + } + + ServiceTracker<HttpServiceRuntime, HttpServiceRuntime> httpRuntimeTracker = + new ServiceTracker<>(bundleContext, filter, null); + + httpRuntimeTracker.open(); + + try { + httpRuntimeTracker.waitForService(1000); + } + catch (InterruptedException ie) { + } + + Optional.ofNullable( + httpRuntimeTracker.getServiceReferences() + ).ifPresent( + array -> { + Collection<String> endPoints = new ArrayList<>(); + + Arrays.stream(array).forEach( + reference -> Strings.stringPlus( + reference.getProperty(HTTP_SERVICE_ENDPOINT) + ).ifPresent( + values -> values.stream().forEach( + value -> { + endPoints.add(value); + } + ) + ) + ); + + properties.put(JAX_RS_SERVICE_ENDPOINT, endPoints); + } + ); + } + + private static String buildExtensionFilter(String filter) { + return String.format("(&%s%s)", getExtensionFilter(), filter); + } + + 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 String getApplicationFilter() { + return format("(%s=*)", JAX_RS_APPLICATION_BASE); + } + + private static String getExtensionFilter() { + return format("(%s=*)", JAX_RS_EXTENSION); + } + + private static String getSingletonsFilter() { + return format("(%s=true)", JAX_RS_RESOURCE); + } + + private ServiceRegistration<?> registerJaxRSServiceRuntime( + BundleContext bundleContext, Bus bus, Map<String, Object> configuration) + throws ConfigurationException { + + Dictionary<String, Object> properties = new Hashtable<>(configuration); + + properties.put( + HTTP_WHITEBOARD_TARGET, + configuration.computeIfAbsent( + HTTP_WHITEBOARD_TARGET, + k -> "(osgi.http.endpoint=*)")); + + properties.put( + HTTP_WHITEBOARD_CONTEXT_SELECT, + configuration.computeIfAbsent( + HTTP_WHITEBOARD_CONTEXT_SELECT, + k -> format( + "(%s=%s)", + HTTP_WHITEBOARD_CONTEXT_NAME, + HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME))); + + properties.put( + HTTP_WHITEBOARD_SERVLET_PATTERN, + configuration.computeIfAbsent( + HTTP_WHITEBOARD_SERVLET_PATTERN, + k -> "/*")); + + properties.put(Constants.SERVICE_RANKING, -1); + + bestEffortCalculationOfEnpoints(properties, bundleContext); + + return bundleContext.registerService( + new String[] {JaxRSServiceRuntime.class.getName(), Servlet.class.getName()}, + new AriesJaxRSServiceRuntime(bus), properties); + } + + private static OSGi<?> waitForExtensionDependencies( + ServiceReference<?> serviceReference, OSGi<?> program) { + + String[] extensionDependencies = canonicalize( + serviceReference.getProperty(JAX_RS_EXTENSION_SELECT)); + + for (String extensionDependency : extensionDependencies) { + program = + serviceReferences(buildExtensionFilter(extensionDependency)). + then(program); + } + + return program; + } + + private static final String _ID = "org.apache.cxf.bus.id"; + + private final OSGiResult<?> _applicationsResult; + private final OSGiResult<?> _applicationSingletonsResult; + private final ServiceRegistration<ClientBuilder> _clientBuilder; + private final ServiceRegistration<DefaultWeb> _defaultWeb; + private final OSGiResult<?> _extensionsResult; + private final ServiceRegistration<?> _runtimeRegistration; + private final OSGiResult<?> _singletonsResult; + +} http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/506532b3/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/WhiteboardServiceFactory.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/WhiteboardServiceFactory.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/WhiteboardServiceFactory.java new file mode 100644 index 0000000..8b41700 --- /dev/null +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/WhiteboardServiceFactory.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.aries.jax.rs.whiteboard.internal; + +import java.util.Dictionary; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.osgi.framework.BundleContext; +import org.osgi.service.cm.ConfigurationException; +import org.osgi.service.cm.ManagedServiceFactory; + +public class WhiteboardServiceFactory implements ManagedServiceFactory { + + public WhiteboardServiceFactory(BundleContext bundleContext) { + _bundleContext = bundleContext; + } + + @Override + public String getName() { + return "org.apache.aries.jax.rs.whiteboard"; + } + + @Override + @SuppressWarnings("unchecked") + public void updated(String pid, Dictionary<String, ?> configuration) + throws ConfigurationException { + + Whiteboard whiteboard = _whiteboards.remove(pid); + + if (whiteboard != null) { + whiteboard.close(); + } + + _whiteboards.put( + pid, new Whiteboard(_bundleContext, (Map<String, Object>)Maps.from(configuration))); + } + + @Override + public void deleted(String pid) { + Whiteboard whiteboard = _whiteboards.remove(pid); + + if (whiteboard != null) { + whiteboard.close(); + } + } + + private final BundleContext _bundleContext; + private final Map<String, Whiteboard> _whiteboards = new ConcurrentHashMap<>(); + +} \ No newline at end of file
