| /* |
| * 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 org.apache.aries.jax.rs.whiteboard.internal.cxf.CxfJaxrsServiceRegistrator; |
| import org.apache.aries.jax.rs.whiteboard.internal.cxf.PrototypeServiceReferenceResourceProvider; |
| import org.apache.aries.jax.rs.whiteboard.internal.cxf.SingletonServiceReferenceResourceProvider; |
| import org.apache.aries.jax.rs.whiteboard.internal.utils.Utils; |
| import org.apache.aries.jax.rs.whiteboard.internal.utils.PropertyHolder; |
| import org.apache.aries.jax.rs.whiteboard.internal.utils.ServiceTuple; |
| import org.apache.aries.component.dsl.CachingServiceReference; |
| import org.apache.aries.component.dsl.OSGi; |
| import org.apache.aries.component.dsl.OSGiResult; |
| import org.apache.cxf.Bus; |
| import org.apache.cxf.bus.extension.ExtensionManagerBus; |
| import org.apache.cxf.jaxrs.lifecycle.ResourceProvider; |
| import org.apache.cxf.transport.servlet.CXFNonSpringServlet; |
| import org.osgi.framework.*; |
| import org.osgi.framework.wiring.BundleWiring; |
| import org.osgi.service.http.context.ServletContextHelper; |
| import org.osgi.service.jaxrs.runtime.JaxrsServiceRuntime; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| 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.*; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import java.util.concurrent.atomic.AtomicLong; |
| import java.util.function.Consumer; |
| import java.util.function.Function; |
| import java.util.function.Supplier; |
| import java.util.stream.Stream; |
| |
| import static java.lang.String.format; |
| import static java.util.stream.Collectors.toMap; |
| import static org.apache.aries.jax.rs.whiteboard.internal.AriesJaxrsServiceRuntime.getServiceName; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.LogUtils.ifDebugEnabled; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.LogUtils.ifErrorEnabled; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.canonicalize; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.canonicalizeAddress; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.getApplicationProperties; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.getString; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.highestPer; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.mergePropertyMaps; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.onlyGettables; |
| import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.updateProperty; |
| import static org.apache.aries.component.dsl.OSGi.NOOP; |
| import static org.apache.aries.component.dsl.OSGi.all; |
| import static org.apache.aries.component.dsl.OSGi.changeContext; |
| import static org.apache.aries.component.dsl.OSGi.effects; |
| import static org.apache.aries.component.dsl.OSGi.ignore; |
| import static org.apache.aries.component.dsl.OSGi.just; |
| import static org.apache.aries.component.dsl.OSGi.nothing; |
| import static org.apache.aries.component.dsl.OSGi.once; |
| import static org.apache.aries.component.dsl.OSGi.register; |
| import static org.apache.aries.component.dsl.OSGi.serviceReferences; |
| import static org.apache.aries.component.dsl.Utils.accumulateInMap; |
| import static org.apache.aries.component.dsl.Utils.highest; |
| import static org.osgi.framework.Constants.SERVICE_PID; |
| import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_NAME; |
| import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_CONTEXT_PATH; |
| 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_ASYNC_SUPPORTED; |
| import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_SERVLET_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_DEFAULT_APPLICATION; |
| 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 static org.osgi.service.jaxrs.whiteboard.JaxrsWhiteboardConstants.JAX_RS_WHITEBOARD_TARGET; |
| |
| /** |
| * @author Carlos Sierra Andrés |
| */ |
| public class Whiteboard { |
| |
| public static final Map<String, Class<?>> SUPPORTED_EXTENSION_INTERFACES = |
| Collections.unmodifiableMap( |
| Stream.of(ContainerRequestFilter.class, |
| ContainerResponseFilter.class, |
| ReaderInterceptor.class, |
| WriterInterceptor.class, |
| MessageBodyReader.class, |
| MessageBodyWriter.class, |
| ContextResolver.class, |
| ExceptionMapper.class, |
| ParamConverterProvider.class, |
| Feature.class, |
| DynamicFeature.class, |
| org.apache.cxf.feature.Feature.class, |
| org.apache.cxf.jaxrs.ext.ContextProvider.class) |
| .collect(toMap(Class::getName, Function.identity()))); |
| |
| static final String DEFAULT_NAME = ".default"; |
| |
| private static final Logger _log = LoggerFactory.getLogger( |
| Whiteboard.class); |
| private final String _applicationBasePrefix; |
| private final Registry<CxfJaxrsServiceRegistrator> _applicationRegistry = |
| new Registry<>(); |
| |
| private final AriesJaxrsServiceRuntime _runtime; |
| private final Map<String, ?> _configurationMap; |
| private volatile BundleContext _bundleContext; |
| private volatile ServiceRegistrationChangeCounter _counter; |
| private volatile ServiceReference<JaxrsServiceRuntime> _runtimeReference; |
| private final OSGi<Void> _program; |
| private final List<Object> _endpoints = new ArrayList<>(); |
| private volatile ServiceRegistration<JaxrsServiceRuntime> |
| _runtimeRegistration; |
| private OSGiResult _osgiResult; |
| |
| private Whiteboard(Dictionary<String, ?> configuration) { |
| _runtime = new AriesJaxrsServiceRuntime(this); |
| _configurationMap = Maps.from(configuration); |
| |
| _applicationBasePrefix = canonicalizeAddress( |
| getString(_configurationMap.get("application.base.prefix"))); |
| |
| _program = |
| all( |
| ignore(registerDefaultApplication()), |
| ignore(getAllServices()) |
| ); |
| } |
| |
| public static Whiteboard createWhiteboard( |
| Dictionary<String, ?> configuration) { |
| |
| return new Whiteboard(configuration); |
| } |
| |
| public void start(BundleContext bundleContext) { |
| _bundleContext = bundleContext; |
| _runtimeRegistration = registerJaxRSServiceRuntime( |
| new HashMap<>(_configurationMap)); |
| _runtimeReference = _runtimeRegistration.getReference(); |
| _counter = new ServiceRegistrationChangeCounter(_runtimeRegistration); |
| _osgiResult = _program.run(bundleContext); |
| } |
| |
| public void stop() { |
| _osgiResult.close(); |
| _runtimeRegistration.unregister(); |
| _applicationRegistry.close(); |
| } |
| |
| public void addHttpEndpoints(List<String> endpoints) { |
| synchronized (_runtimeRegistration) { |
| _endpoints.addAll(endpoints); |
| |
| updateProperty( |
| _runtimeRegistration, JAX_RS_SERVICE_ENDPOINT, _endpoints); |
| } |
| } |
| |
| public ServiceReference<JaxrsServiceRuntime> getServiceReference() { |
| return _runtimeReference; |
| } |
| |
| private OSGi<?> applicationExtensions( |
| OSGi<CachingServiceReference<Object>> extensions) { |
| |
| return |
| onlyValid( |
| onlySupportedInterfaces( |
| extensions, |
| _runtime::addInvalidExtension, |
| _runtime::removeInvalidExtension), |
| _runtime::addInvalidExtension, |
| _runtime::removeInvalidExtension). |
| flatMap(extensionReference -> |
| chooseApplication( |
| extensionReference, |
| _runtime::addApplicationDependentExtension, |
| _runtime::removeApplicationDependentExtension). |
| flatMap(registrator -> |
| waitForExtensionDependencies( |
| extensionReference, |
| registrator, |
| er -> |
| _runtime.addDependentExtensionInApplication( |
| registrator.getProperties(), er), |
| er -> |
| _runtime.removeDependentExtensionFromApplication( |
| registrator.getProperties(), er)). |
| then( |
| safeRegisterExtension(extensionReference, registrator) |
| ))); |
| } |
| |
| private OSGi<?> applicationResources( |
| OSGi<CachingServiceReference<Object>> resources) { |
| |
| return |
| onlyValid( |
| resources, _runtime::addInvalidResource, |
| _runtime::removeInvalidResource). |
| flatMap(resourceReference -> |
| chooseApplication( |
| resourceReference, |
| _runtime::addApplicationDependentResource, |
| _runtime::removeApplicationDependentResource). |
| flatMap(registrator -> |
| waitForExtensionDependencies( |
| resourceReference, registrator, |
| _runtime::addDependentService, |
| _runtime::removeDependentService). |
| then( |
| safeRegisterEndpoint(resourceReference, registrator) |
| ))); |
| } |
| |
| @SuppressWarnings({ "rawtypes", "unchecked" }) |
| private OSGi<?> getAllServices() { |
| OSGi<CachingServiceReference<Object>> applicationsForWhiteboard = |
| (OSGi)getApplicationsForWhiteboard(); |
| return |
| highestPer( |
| sr -> just(getServiceName(sr::getProperty)), |
| countChanges( |
| all( |
| getResourcesForWhiteboard(), |
| getApplicationExtensionsForWhiteboard(), |
| applicationsForWhiteboard |
| ) |
| ), |
| this::registerShadowedService, |
| this::unregisterShadowedService |
| ). |
| effects( |
| _runtime::addServiceForName, |
| _runtime::removedServiceForName |
| ). |
| distribute( |
| p -> ignore(applications((OSGi)p.filter(this::isApplication))), |
| p -> ignore(applicationResources(p.filter(this::isResource))), |
| p -> ignore(applicationExtensions(p.filter(this::isExtension))) |
| ); |
| } |
| |
| private boolean isApplication(CachingServiceReference<?> sr) { |
| return _applicationsFilter.match(sr.getServiceReference()); |
| } |
| |
| private boolean isExtension(CachingServiceReference<?> sr) { |
| return _extensionsFilter.match(sr.getServiceReference()); |
| } |
| |
| private boolean isResource(CachingServiceReference<?> sr) { |
| return _resourcesFilter.match(sr.getServiceReference()); |
| } |
| |
| private <T> boolean matchesWhiteboard(CachingServiceReference<T> ref) { |
| String target = (String)ref.getProperty(JAX_RS_WHITEBOARD_TARGET); |
| |
| if (target == null) { |
| return true; |
| } |
| |
| Filter filter; |
| |
| try { |
| filter = FrameworkUtil.createFilter(target); |
| } |
| catch (InvalidSyntaxException ise) { |
| if (_log.isErrorEnabled()) { |
| _log.error( |
| "Invalid '{}' filter syntax in {}", |
| JAX_RS_WHITEBOARD_TARGET, ref); |
| } |
| |
| return false; |
| } |
| |
| return filter.match(_runtimeReference); |
| } |
| |
| private void registerShadowedService(CachingServiceReference<?> sr) { |
| if (isApplication(sr)) { |
| _runtime.addClashingApplication(sr); |
| } |
| if (isExtension(sr)) { |
| _runtime.addClashingExtension(sr); |
| } |
| if (isResource(sr)) { |
| _runtime.addClashingResource(sr); |
| } |
| } |
| |
| private void unregisterShadowedService(CachingServiceReference<?> sr) { |
| if (isApplication(sr)) { |
| _runtime.removeClashingApplication(sr); |
| } |
| if (isExtension(sr)) { |
| _runtime.removeClashingExtension(sr); |
| } |
| if (isResource(sr)) { |
| _runtime.removeClashingResource(sr); |
| } |
| } |
| |
| private static <T> OSGi<? extends ResourceProvider> getResourceProvider( |
| ServiceTuple<T> serviceTuple) { |
| |
| CachingServiceReference<T> cachingServiceReference = |
| serviceTuple.getCachingServiceReference(); |
| |
| String scope = Utils.getString(cachingServiceReference.getProperty("service.scope")); |
| |
| if (Objects.equals(scope, "prototype")) { |
| boolean applicationScoped = |
| Boolean.parseBoolean( |
| getString( |
| cachingServiceReference.getProperty( |
| "org.apache.aries.jax.rs.whiteboard.application.scoped"))); |
| if (applicationScoped) { |
| return just( |
| serviceTuple.getServiceObjects().getService() |
| ).effects( |
| __ -> {}, |
| serviceTuple.getServiceObjects()::ungetService |
| ).map( |
| service -> new SingletonServiceReferenceResourceProvider( |
| cachingServiceReference, service) |
| ); |
| } |
| |
| return just( |
| new PrototypeServiceReferenceResourceProvider( |
| cachingServiceReference, |
| serviceTuple.getService().getClass(), |
| serviceTuple.getServiceObjects()) |
| ).effects( |
| __ -> {}, |
| __ -> serviceTuple.dispose(), |
| __ -> {}, |
| __ -> {} |
| ); |
| } |
| else { |
| return just( |
| new SingletonServiceReferenceResourceProvider( |
| serviceTuple.getCachingServiceReference(), |
| serviceTuple.getService() |
| )); |
| } |
| } |
| |
| private static <T> OSGi<CachingServiceReference<T>> onlyValid( |
| OSGi<CachingServiceReference<T>> serviceReferences, |
| Consumer<CachingServiceReference<T>> onAddingInvalid, |
| Consumer<CachingServiceReference<T>> onRemovingInvalid) { |
| |
| return serviceReferences.flatMap(serviceReference -> { |
| |
| OSGi<CachingServiceReference<T>> error = effects( |
| () -> onAddingInvalid.accept(serviceReference), |
| () -> onRemovingInvalid.accept(serviceReference) |
| ). |
| effects( |
| ifDebugEnabled(_log, () -> "Invalid service {}"), |
| ifDebugEnabled(_log, () -> "Invalid service {} is gone") |
| ). |
| then( |
| nothing() |
| ); |
| |
| Object propertyObject = serviceReference.getProperty(JAX_RS_NAME); |
| |
| if (propertyObject != null && |
| !propertyObject.toString().equals(JAX_RS_DEFAULT_APPLICATION) && |
| propertyObject.toString().startsWith(".")) { |
| |
| if (_log.isWarnEnabled()) { |
| _log.warn( |
| "Invalid property {} in service {}", |
| JAX_RS_DEFAULT_APPLICATION, serviceReference); |
| } |
| |
| return error; |
| } |
| |
| if (!testFilters( |
| serviceReference.getProperty(JAX_RS_APPLICATION_SELECT))) { |
| |
| if (_log.isWarnEnabled()) { |
| _log.warn( |
| "Invalid value for property {} in service {}", |
| JAX_RS_APPLICATION_SELECT, serviceReference); |
| } |
| |
| return error; |
| } |
| |
| if (!testFilters( |
| serviceReference.getProperty(JAX_RS_EXTENSION_SELECT))) { |
| |
| if (_log.isWarnEnabled()) { |
| _log.warn( |
| "Invalid value for property {} in service {}", |
| JAX_RS_EXTENSION_SELECT, serviceReference); |
| } |
| |
| return error; |
| } |
| |
| return just(serviceReference); |
| }); |
| } |
| |
| private static boolean testFilters(Object propertyObject) { |
| if (propertyObject != null) { |
| try { |
| String[] properties = canonicalize(propertyObject); |
| |
| for (String property : properties) { |
| FrameworkUtil.createFilter(property); |
| } |
| } |
| catch (InvalidSyntaxException e) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| private OSGi<ApplicationReferenceWithContext> waitForApplicationContext( |
| OSGi<CachingServiceReference<Application>> application, |
| Consumer<CachingServiceReference<Application>> onWaitingForContext, |
| Consumer<CachingServiceReference<Application>> onResolvedContext) { |
| |
| return application.flatMap(serviceReference -> { |
| Object propertyObject = serviceReference.getProperty( |
| HTTP_WHITEBOARD_CONTEXT_SELECT); |
| |
| if (propertyObject == null) { |
| propertyObject = _configurationMap.get( |
| HTTP_WHITEBOARD_CONTEXT_SELECT); |
| |
| if (propertyObject == null) { |
| return just( |
| new ApplicationReferenceWithContext( |
| null, serviceReference)); |
| } |
| } |
| |
| String contextSelect = propertyObject.toString(); |
| |
| try { |
| FrameworkUtil.createFilter(contextSelect); |
| } |
| catch (InvalidSyntaxException e) { |
| return effects( |
| () -> _runtime.addInvalidApplication(serviceReference), |
| () -> _runtime.removeInvalidApplication(serviceReference) |
| ).then( |
| nothing() |
| ); |
| } |
| |
| return |
| effects( |
| () -> onWaitingForContext.accept(serviceReference), |
| () -> onResolvedContext.accept(serviceReference) |
| ).then( |
| highest( |
| serviceReferences(ServletContextHelper.class, contextSelect) |
| ).flatMap( |
| sr -> just( |
| new ApplicationReferenceWithContext(sr, serviceReference)) |
| ).effects( |
| __ -> onResolvedContext.accept(serviceReference), |
| __ -> onWaitingForContext.accept(serviceReference) |
| )); |
| }); |
| } |
| |
| private OSGi<?> applications( |
| OSGi<CachingServiceReference<Application>> applications) { |
| |
| OSGi<CachingServiceReference<Application>> validApplications = |
| onlyValid( |
| applications, |
| _runtime::addInvalidApplication, |
| _runtime::removeInvalidApplication); |
| |
| OSGi<ApplicationReferenceWithContext> applicationsWithContext = |
| waitForApplicationContext( |
| validApplications, |
| _runtime::addContextDependentApplication, |
| _runtime::removeContextDependentApplication); |
| |
| OSGi<ApplicationReferenceWithContext> highestRankedPerPath = |
| highestPer( |
| arwc -> just(arwc.getActualBasePath()), |
| applicationsWithContext, |
| t -> _runtime.addShadowedApplication( |
| t.getApplicationReference(), t.getActualBasePath()), |
| t -> _runtime.removeShadowedApplication( |
| t.getApplicationReference()) |
| ); |
| |
| return highestRankedPerPath.flatMap(application -> |
| onlyGettables( |
| waitForReadyService( |
| just(application.getApplicationReference())), |
| _runtime::addNotGettableApplication, |
| _runtime::removeNotGettableApplication, _log). |
| recoverWith( |
| (t, e) -> |
| just(t).map( |
| ServiceTuple::getCachingServiceReference |
| ).effects( |
| _runtime::addErroredApplication, |
| _runtime::removeErroredApplication |
| ).then( |
| nothing() |
| ) |
| ). |
| effects( |
| __ -> {}, |
| this::clearApplicationState |
| ).flatMap(at -> |
| deployApplication(at, application.getContextReference()).foreach( |
| registrator -> |
| _runtime.setApplicationForPath( |
| getApplicationBase( |
| at.getCachingServiceReference()::getProperty), |
| at.getCachingServiceReference(), |
| registrator), |
| registrator -> |
| _runtime.unsetApplicationForPath( |
| getApplicationBase( |
| at.getCachingServiceReference()::getProperty)) |
| ) |
| )); |
| } |
| |
| private ExtensionManagerBus createBus( |
| Map<String, ServiceTuple<Object>> extensions) { |
| |
| BundleWiring wiring = _bundleContext.getBundle().adapt( |
| BundleWiring.class); |
| |
| Map<String, Object> properties = new HashMap<>(_configurationMap); |
| properties.putIfAbsent( |
| "replace.loopback.address.with.localhost", "false"); |
| |
| HashMap<Class<?>, Object> cxfExtensions = new HashMap<>(); |
| |
| if (extensions.isEmpty()) { |
| cxfExtensions = null; |
| } |
| else { |
| for (Map.Entry<String, ServiceTuple<Object>> entry : |
| extensions.entrySet()) { |
| |
| String className = entry.getKey(); |
| |
| ServiceTuple<Object> serviceTuple = entry.getValue(); |
| |
| ClassLoader classLoader = getClassLoader(serviceTuple); |
| |
| try { |
| Class<?> clazz = classLoader.loadClass(className); |
| |
| cxfExtensions.put(clazz, serviceTuple.getService()); |
| } |
| catch (Exception e) { |
| if (_log.isErrorEnabled()) { |
| _log.error("Could not load extension for CXF bus", e); |
| } |
| } |
| } |
| } |
| |
| if (_log.isDebugEnabled()) { |
| _log.debug( |
| "Creating CXF Bus with extensions {} and properties {}", |
| extensions, properties); |
| } |
| |
| ExtensionManagerBus bus = new ExtensionManagerBus( |
| cxfExtensions, properties, wiring.getClassLoader()); |
| |
| bus.initialize(); |
| |
| if (_log.isDebugEnabled()) { |
| _log.debug( |
| "Created CXF Bus with extensions {} and properties {}", |
| extensions, properties); |
| } |
| |
| return bus; |
| } |
| |
| private void clearApplicationState(ServiceTuple<Application> tuple) { |
| CachingServiceReference<?> |
| cachingServiceReference = tuple.getCachingServiceReference(); |
| |
| _runtime.unregisterApplicationExtensions(cachingServiceReference); |
| } |
| |
| private OSGi<CxfJaxrsServiceRegistrator> applicationMatching( |
| String filter) { |
| |
| return _applicationRegistry.waitForService(filter); |
| } |
| |
| private OSGi<CxfJaxrsServiceRegistrator> deployApplication( |
| ServiceTuple<Application> tuple, |
| CachingServiceReference<ServletContextHelper> contextReference) { |
| |
| CachingServiceReference<Application> serviceReference = |
| tuple.getCachingServiceReference(); |
| |
| Map<String, Object> properties = getApplicationProperties( |
| serviceReference); |
| |
| properties.put( |
| "original.service.id", |
| serviceReference.getProperty("service.id")); |
| |
| properties.put( |
| "original.service.bundleid", |
| serviceReference.getProperty("service.bundleid")); |
| |
| return |
| getCxfExtensions(tuple.getCachingServiceReference()). |
| flatMap(extensions -> |
| createRegistrator(extensions, tuple, properties). |
| flatMap(registrator -> |
| waitForApplicationDependencies( |
| tuple.getCachingServiceReference(), |
| _applicationRegistry.registerService( |
| registrator, registrator.getProperties())). |
| then( |
| registerCXFServletService( |
| registrator.getBus(), properties, contextReference). |
| then( |
| just(registrator) |
| )))); |
| } |
| |
| public OSGi<Map<String, ServiceTuple<Object>>> getCxfExtensions( |
| CachingServiceReference<Application> applicationReference) { |
| |
| OSGi<ServiceTuple<Object>> cxfExtensionsForApplication = |
| onlyGettables( |
| serviceReferences("(cxf.extension=true)").filter( |
| sr -> { |
| Object appFilter = sr.getProperty( |
| JAX_RS_APPLICATION_SELECT); |
| |
| if (appFilter == null) { |
| return true; |
| } |
| else { |
| try { |
| Filter filter = FrameworkUtil.createFilter( |
| appFilter.toString()); |
| |
| return filter.match( |
| applicationReference.getServiceReference()); |
| } |
| catch (InvalidSyntaxException e) { |
| return false; |
| } |
| } |
| } |
| ).filter(this::matchesWhiteboard), |
| __ -> {}, __ -> {}, _log); |
| |
| return accumulateInMap( |
| cxfExtensionsForApplication, |
| st -> just( |
| Arrays.asList( |
| canonicalize( |
| st.getCachingServiceReference(). |
| getProperty("objectClass")))), |
| OSGi::just); |
| } |
| |
| private ClassLoader getClassLoader(ServiceTuple<?> serviceTuple) { |
| return serviceTuple. |
| getCachingServiceReference(). |
| getServiceReference(). |
| getBundle(). |
| adapt(BundleWiring.class). |
| getClassLoader(); |
| } |
| |
| private OSGi<CxfJaxrsServiceRegistrator> createRegistrator( |
| Map<String, ServiceTuple<Object>> extensions, |
| ServiceTuple<Application> tuple, Map<String, Object> props) { |
| |
| return |
| just(() -> new CxfJaxrsServiceRegistrator( |
| createBus(extensions), tuple, props, _runtime)). |
| effects( |
| __ -> {}, |
| CxfJaxrsServiceRegistrator::enable, |
| CxfJaxrsServiceRegistrator::close, |
| __ -> {}); |
| } |
| |
| private OSGi<CachingServiceReference<Object>> |
| getApplicationExtensionsForWhiteboard() { |
| |
| return serviceReferences(_extensionsFilter.toString()). |
| filter(this::matchesWhiteboard); |
| } |
| |
| private OSGi<CachingServiceReference<Application>> |
| getApplicationsForWhiteboard() { |
| |
| return |
| serviceReferences( |
| Application.class, _applicationsFilter.toString()). |
| filter(this::matchesWhiteboard); |
| } |
| |
| private String getApplicationReadyServiceFilter( |
| CachingServiceReference<Application> reference) { |
| |
| Object applicationReadyServiceFilter = |
| _configurationMap.get("application.ready.service.filter"); |
| |
| if (applicationReadyServiceFilter == null) { |
| applicationReadyServiceFilter = |
| reference.getProperty("application.ready.service.filter"); |
| } |
| |
| if (applicationReadyServiceFilter != null) { |
| return String.valueOf(applicationReadyServiceFilter); |
| } |
| |
| return null; |
| } |
| |
| private OSGi<CachingServiceReference<Object>> getResourcesForWhiteboard() { |
| return serviceReferences(_resourcesFilter.toString()). |
| filter(this::matchesWhiteboard); |
| } |
| |
| private OSGi<ServiceRegistration<Application>> |
| registerDefaultApplication() { |
| |
| return OSGi.register( |
| Application.class, DefaultApplication::new, |
| () -> { |
| Object defaultApplicationBase = _configurationMap.get( |
| "default.application.base"); |
| |
| if (defaultApplicationBase == null || |
| !(defaultApplicationBase instanceof String)) { |
| |
| defaultApplicationBase = "/"; |
| } |
| |
| Map<String, Object> properties = new HashMap<>(); |
| |
| mergePropertyMaps(properties, _configurationMap); |
| |
| properties.put(JAX_RS_NAME, DEFAULT_NAME); |
| properties.put(JAX_RS_APPLICATION_BASE, defaultApplicationBase); |
| properties.put("service.ranking", Integer.MIN_VALUE); |
| properties.put( |
| JAX_RS_WHITEBOARD_TARGET, |
| "(" + SERVICE_PID + "=" + _configurationMap.get(SERVICE_PID) |
| + ")"); |
| |
| return properties; |
| }); |
| } |
| |
| private ServiceRegistration<JaxrsServiceRuntime> |
| registerJaxRSServiceRuntime(Map<String, Object> properties) { |
| |
| properties.putIfAbsent(Constants.SERVICE_RANKING, Integer.MIN_VALUE); |
| |
| return _bundleContext.registerService( |
| JaxrsServiceRuntime.class, _runtime, new Hashtable<>(properties)); |
| } |
| |
| public void removeHttpEndpoints(List<String> endpoints) { |
| synchronized (_runtimeRegistration) { |
| _endpoints.removeAll(endpoints); |
| |
| updateProperty( |
| _runtimeRegistration, JAX_RS_SERVICE_ENDPOINT, _endpoints); |
| } |
| } |
| |
| private <T> OSGi<?> safeRegisterEndpoint( |
| CachingServiceReference<T> serviceReference, |
| CxfJaxrsServiceRegistrator registrator) { |
| |
| Map registratorProperties = registrator.getProperties(); |
| |
| Bundle originalBundle = _bundleContext.getBundle( |
| (long)registratorProperties.get("service.bundleid")); |
| |
| return |
| changeContext( |
| originalBundle.getBundleContext(), |
| onlyGettables( |
| just(serviceReference), |
| _runtime::addNotGettableEndpoint, |
| _runtime::removeNotGettableEndpoint, |
| _log |
| ) |
| ).recoverWith((t, e) -> |
| just(serviceReference). |
| effects( |
| _runtime::addErroredEndpoint, |
| _runtime::removeErroredEndpoint). |
| effects( |
| ifErrorEnabled( |
| _log, |
| () -> "ServiceReference {} for endpoint produced " + |
| "error: {}", |
| e), |
| ifErrorEnabled( |
| _log, |
| () -> "Errored ServiceReference {} for endpoint left") |
| ). |
| then(nothing()) |
| ).flatMap( |
| Whiteboard::getResourceProvider |
| ).effects( |
| rp -> _runtime.addApplicationEndpoint( |
| registratorProperties::get, serviceReference, |
| registrator.getBus(), rp.getResourceClass()), |
| rp -> _runtime.removeApplicationEndpoint( |
| registratorProperties::get, serviceReference) |
| ).effects( |
| registrator::add, |
| registrator::remove |
| ).effects( |
| ifDebugEnabled( |
| _log, |
| () -> "Registered endpoint " + |
| serviceReference.getServiceReference() + " into application " + |
| getServiceName(registratorProperties::get) |
| ), |
| ifDebugEnabled( |
| _log, |
| () -> "Unregistered endpoint " + |
| serviceReference.getServiceReference() + " from application " + |
| getServiceName(registratorProperties::get) |
| ) |
| |
| ); |
| } |
| |
| private OSGi<?> safeRegisterExtension( |
| CachingServiceReference<?> serviceReference, |
| CxfJaxrsServiceRegistrator registrator) { |
| |
| Map properties = registrator.getProperties(); |
| |
| Bundle originalBundle = _bundleContext.getBundle( |
| (long)properties.get("service.bundleid")); |
| |
| return |
| just(() -> getServiceName(properties::get)). |
| flatMap(applicationName -> |
| changeContext( |
| originalBundle.getBundleContext(), |
| onlyGettables( |
| just(serviceReference), |
| _runtime::addNotGettableExtension, |
| _runtime::removeNotGettableExtension, |
| _log |
| ) |
| ).recoverWith( |
| (t, e) -> |
| just(t.getCachingServiceReference()). |
| effects( |
| _runtime::addErroredExtension, |
| _runtime::removeErroredExtension |
| ). |
| effects( |
| ifErrorEnabled( |
| _log, |
| () -> "ServiceReference {} for extension " + |
| "produced error: {}", |
| e), |
| ifErrorEnabled( |
| _log, |
| () -> "Errored ServiceReference {} for extension " + |
| "left") |
| ). |
| then(nothing()) |
| ).effects( |
| registrator::addProvider, |
| registrator::removeProvider |
| ).effects( |
| t -> _runtime.addApplicationExtension( |
| properties::get, serviceReference, |
| t.getService().getClass()), |
| __ -> _runtime.removeApplicationExtension( |
| properties::get, serviceReference) |
| ). |
| effects( |
| ifDebugEnabled( |
| _log, |
| () -> |
| "Registered extension " + |
| serviceReference.getServiceReference() + |
| " into application " + |
| getServiceName(properties::get) |
| ), |
| ifDebugEnabled( |
| _log, |
| () -> |
| "Unregistered extension " + |
| serviceReference.getServiceReference() + |
| " from application " + |
| getServiceName(properties::get) |
| ) |
| |
| ). |
| effects( |
| __ -> registrator.registerExtension( |
| serviceReference), |
| __ -> registrator.unregisterExtension( |
| serviceReference) |
| )); |
| } |
| |
| |
| |
| private OSGi<CxfJaxrsServiceRegistrator> |
| waitForApplicationDependencies( |
| CachingServiceReference<Application> applicationReference, |
| OSGi<CxfJaxrsServiceRegistrator> registrators) { |
| |
| return registrators.flatMap(registrator -> { |
| String[] extensionDependencies = canonicalize( |
| applicationReference.getProperty(JAX_RS_EXTENSION_SELECT)); |
| |
| OSGi<CxfJaxrsServiceRegistrator> program = just(registrator); |
| |
| if (extensionDependencies.length == 0) { |
| return program; |
| } |
| |
| for (String extensionDependency : extensionDependencies) { |
| if (_log.isDebugEnabled()) { |
| _log.debug( |
| "Application {} has a dependency on {}", |
| registrator, extensionDependency); |
| } |
| |
| try { |
| Filter extensionFilter = _bundleContext.createFilter( |
| extensionDependency); |
| |
| if (extensionFilter.match(_runtimeReference)) { |
| if(_log.isDebugEnabled()) { |
| _log.debug( |
| "Application dependency {} provided by " + |
| "whiteboard {}", |
| extensionDependency, _runtimeReference); |
| } |
| |
| continue; |
| } |
| } |
| catch (InvalidSyntaxException e) { |
| return program. |
| effects( |
| ifErrorEnabled( |
| _log, |
| () -> String.format( |
| "Application %s has invalid dependency %s", |
| registrator, extensionDependency)), |
| ifErrorEnabled( |
| _log, |
| () -> String.format( |
| "Application %s with invalid dependency " + |
| "has left", |
| registrator)) |
| ). |
| effects( |
| __ -> _runtime.addErroredApplication( |
| applicationReference), |
| __ -> _runtime.removeErroredApplication( |
| applicationReference) |
| ).then( |
| nothing() |
| ); |
| } |
| |
| program = |
| once( |
| registrator.waitForExtension(extensionDependency). |
| flatMap( |
| sr -> { |
| Object applicationSelectProperty = |
| sr.getProperty(JAX_RS_APPLICATION_SELECT); |
| |
| if (applicationSelectProperty == null) { |
| return just(registrator); |
| } |
| |
| Filter filter; |
| |
| try { |
| filter = _bundleContext.createFilter( |
| applicationSelectProperty.toString()); |
| } |
| catch (InvalidSyntaxException e) { |
| return nothing(); |
| } |
| |
| if (filter.match( |
| applicationReference. |
| getServiceReference())) { |
| |
| return just(registrator); |
| } |
| |
| return nothing(); |
| } |
| )).effects( |
| __ -> {}, |
| __ -> _runtime.addDependentApplication( |
| applicationReference) |
| ). |
| effects( |
| ifDebugEnabled( |
| _log, |
| () -> "Application "+ registrator + |
| " dependency " + extensionDependency + |
| " has been fullfiled"), |
| ifDebugEnabled( |
| _log, |
| () -> "Application "+ registrator + |
| " dependency " + extensionDependency + |
| " has gone") |
| ). |
| then(program); |
| } |
| |
| program = effects( |
| () -> _runtime.addDependentApplication(applicationReference), |
| () -> _runtime.removeDependentApplication(applicationReference) |
| ).then(program); |
| |
| program = program.effects( |
| __ -> _runtime.removeDependentApplication(applicationReference), |
| __ -> {} |
| ); |
| |
| return program; |
| }); |
| } |
| |
| private OSGi<CachingServiceReference<Application>> waitForReadyService( |
| OSGi<CachingServiceReference<Application>> program) { |
| |
| return program.flatMap(reference -> { |
| String applicationReadyServiceFilter = |
| getApplicationReadyServiceFilter(reference); |
| |
| if (applicationReadyServiceFilter != null) { |
| return effects( |
| () -> _runtime.addDependentApplication(reference), |
| () -> _runtime.removeDependentApplication(reference) |
| ).then( |
| once(serviceReferences(applicationReadyServiceFilter)). |
| effects( |
| ifDebugEnabled( |
| _log, |
| () -> |
| "Ready service for " + reference + |
| " has been tracked"), |
| ifDebugEnabled( |
| _log, |
| () -> "Ready service for " + reference + |
| " is gone") |
| ). |
| then(just(reference). |
| effects( |
| __ -> {}, |
| __ -> _runtime.addDependentApplication( |
| reference))) |
| ).effects( |
| _runtime::removeDependentApplication, |
| __ -> {} |
| ); |
| } |
| |
| return just(reference); |
| }); |
| } |
| |
| private OSGi<?> waitForExtensionDependencies( |
| CachingServiceReference<?> reference, |
| CxfJaxrsServiceRegistrator cxfJaxrsServiceRegistrator, |
| Consumer<CachingServiceReference<?>> onAddingDependent, |
| Consumer<CachingServiceReference<?>> onRemovingDependent) { |
| |
| Map<String, ?> applicationRegistratorProperties = |
| cxfJaxrsServiceRegistrator.getProperties(); |
| |
| String[] extensionDependencies = canonicalize( |
| reference.getProperty(JAX_RS_EXTENSION_SELECT)); |
| |
| OSGi<CachingServiceReference<?>> program = just(reference); |
| |
| if (extensionDependencies.length == 0) { |
| return program; |
| } |
| |
| for (String extensionDependency : extensionDependencies) { |
| if (_log.isDebugEnabled()) { |
| _log.debug( |
| "Extension {} has a dependency on {}", |
| reference, extensionDependency); |
| } |
| |
| try { |
| String finalExtensionDependency = extensionDependency.replace( |
| "(objectClass=", "(original.objectClass="); |
| |
| Filter extensionFilter = _bundleContext.createFilter( |
| finalExtensionDependency); |
| |
| if (extensionFilter.match(_runtimeReference) || |
| extensionFilter.matches( |
| applicationRegistratorProperties)) |
| { |
| continue; |
| } |
| |
| program = |
| once( |
| cxfJaxrsServiceRegistrator.waitForExtension( |
| extensionDependency). |
| effects( |
| __ -> {}, |
| __ -> onAddingDependent.accept(reference) |
| ) |
| ).effects( |
| ifDebugEnabled( |
| _log, |
| () -> "Extension " + reference + |
| " dependency " + extensionDependency + |
| " has been fullfiled"), |
| ifDebugEnabled( |
| _log, |
| () -> "Extension " + reference + |
| " dependency " + extensionDependency + |
| " has gone") |
| ). |
| then(program); |
| } |
| catch (InvalidSyntaxException e) { |
| |
| } |
| } |
| |
| program = effects( |
| () -> onAddingDependent.accept(reference), |
| () -> onRemovingDependent.accept(reference)). |
| then(program); |
| |
| program = program.effects( |
| __ -> onRemovingDependent.accept(reference), |
| __ -> {} |
| ); |
| |
| return program; |
| } |
| |
| String getApplicationBase(PropertyHolder properties) { |
| return _applicationBasePrefix + getString( |
| properties.get(JAX_RS_APPLICATION_BASE)); |
| } |
| |
| private OSGi<CxfJaxrsServiceRegistrator> |
| chooseApplication( |
| CachingServiceReference<?> serviceReference, |
| Consumer<CachingServiceReference<?>> onWaiting, |
| Consumer<CachingServiceReference<?>> onResolved) { |
| |
| Object applicationSelectProperty = serviceReference.getProperty( |
| JAX_RS_APPLICATION_SELECT); |
| |
| if (applicationSelectProperty == null) { |
| return applicationMatching( |
| String.format("(%s=%s)", JAX_RS_NAME, DEFAULT_NAME)); |
| } |
| |
| return |
| just(AtomicInteger::new).flatMap(counter -> |
| effects( |
| () -> onWaiting.accept(serviceReference), |
| () -> { |
| onResolved.accept(serviceReference); |
| |
| counter.set(0); |
| }).then( |
| applicationMatching(applicationSelectProperty.toString()). |
| effects( |
| __ -> { |
| if (counter.getAndIncrement() == 0) { |
| onResolved.accept(serviceReference); |
| } |
| }, |
| __ -> { |
| if (counter.decrementAndGet() == 0) { |
| onWaiting.accept(serviceReference); |
| } |
| }) |
| )); |
| } |
| |
| private <T> OSGi<T> countChanges(OSGi<T> program) { |
| |
| return program.effects( |
| __ -> {}, |
| __ -> _counter.inc(), |
| __ -> {}, |
| __ -> _counter.inc() |
| ); |
| } |
| |
| private static CXFNonSpringServlet createCXFServlet(Bus bus) { |
| @SuppressWarnings("serial") |
| CXFNonSpringServlet cxfNonSpringServlet = new CXFNonSpringServlet() { |
| |
| @Override |
| public void destroyBus() { |
| } |
| |
| }; |
| |
| cxfNonSpringServlet.setBus(bus); |
| |
| return cxfNonSpringServlet; |
| } |
| |
| private static OSGi<CachingServiceReference<Object>> |
| onlySupportedInterfaces( |
| OSGi<CachingServiceReference<Object>> program, |
| Consumer<CachingServiceReference<?>> onInvalidAdded, |
| Consumer<CachingServiceReference<?>> onInvalidRemoved) { |
| |
| return program.flatMap(sr -> { |
| if (signalsValidInterface(sr)) { |
| return just(sr); |
| } |
| else { |
| return effects( |
| () -> onInvalidAdded.accept(sr), |
| () -> onInvalidRemoved.accept(sr)). |
| then(nothing()); |
| } |
| }); |
| } |
| |
| private OSGi<ServiceRegistration<Servlet>> registerCXFServletService( |
| Bus bus, Map<String, Object> serviceProperties, |
| CachingServiceReference<ServletContextHelper> contextReference) { |
| |
| String address = canonicalizeAddress( |
| getApplicationBase(serviceProperties::get)); |
| |
| String applicationName = getServiceName(serviceProperties::get); |
| |
| Supplier<Map<String, ?>> contextPropertiesSup; |
| |
| OSGi<?> program = effects(NOOP, NOOP); |
| |
| if (contextReference == null) { |
| contextPropertiesSup = () -> { |
| HashMap<String, Object> contextProperties = new HashMap<>(); |
| |
| Utils.mergePropertyMaps(contextProperties, serviceProperties); |
| |
| Utils.mergePropertyMaps(contextProperties, _configurationMap); |
| |
| contextProperties.putIfAbsent( |
| HTTP_WHITEBOARD_TARGET, "(osgi.http.endpoint=*)"); |
| |
| String contextName; |
| |
| if ("".equals(address)) { |
| contextName = HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME; |
| } else { |
| contextName = "context.for" + applicationName; |
| } |
| |
| contextProperties.put( |
| HTTP_WHITEBOARD_CONTEXT_NAME, contextName); |
| contextProperties.put( |
| HTTP_WHITEBOARD_CONTEXT_PATH, |
| address.equals("") ? "/" : address); |
| |
| return contextProperties; |
| }; |
| |
| if (!"".equals(address)) { |
| program = OSGi.register( |
| ServletContextHelper.class, |
| () -> new ServletContextHelper( |
| _bundleContext.getBundle( |
| (long)serviceProperties.get( |
| "original.service.bundleid"))) { |
| }, |
| contextPropertiesSup); |
| } |
| } |
| else { |
| contextPropertiesSup = () -> { |
| HashMap<String, Object> properties = new HashMap<>(); |
| |
| properties.put( |
| HTTP_WHITEBOARD_CONTEXT_NAME, |
| contextReference.getProperty(HTTP_WHITEBOARD_CONTEXT_NAME)); |
| |
| return properties; |
| }; |
| } |
| |
| Supplier<Map<String, ?>> servletPropertiesSup = () -> { |
| HashMap<String, Object> servletProperties = new HashMap<>(); |
| |
| Utils.mergePropertyMaps(servletProperties, serviceProperties); |
| |
| Utils.mergePropertyMaps(servletProperties, _configurationMap); |
| |
| Map<String, ?> contextProperties = contextPropertiesSup.get(); |
| |
| servletProperties.put( |
| HTTP_WHITEBOARD_CONTEXT_SELECT, |
| format("(%s=%s)", HTTP_WHITEBOARD_CONTEXT_NAME, |
| contextProperties.get(HTTP_WHITEBOARD_CONTEXT_NAME))); |
| servletProperties.putIfAbsent( |
| HTTP_WHITEBOARD_TARGET, "(osgi.http.endpoint=*)"); |
| servletProperties.putIfAbsent( |
| "servlet.init.hide-service-list-page", "true"); |
| |
| if (contextReference == null) { |
| servletProperties.put(HTTP_WHITEBOARD_SERVLET_PATTERN, "/*"); |
| } |
| else { |
| servletProperties.put( |
| HTTP_WHITEBOARD_SERVLET_PATTERN, address + "/*"); |
| } |
| servletProperties.put( |
| HTTP_WHITEBOARD_SERVLET_ASYNC_SUPPORTED, true); |
| servletProperties.put( |
| HTTP_WHITEBOARD_SERVLET_NAME, "cxf-servlet"); |
| |
| return servletProperties; |
| }; |
| |
| return program.then( |
| register( |
| Servlet.class, |
| new PrototypeServiceFactory<Servlet>() { |
| @Override |
| public Servlet getService( |
| Bundle bundle, |
| ServiceRegistration<Servlet> registration) { |
| |
| return createCXFServlet(bus); |
| } |
| |
| @Override |
| public void ungetService( |
| Bundle bundle, |
| ServiceRegistration<Servlet> registration, |
| Servlet service) { |
| |
| } |
| }, |
| servletPropertiesSup)); |
| } |
| |
| private static boolean signalsValidInterface( |
| CachingServiceReference<Object> serviceReference) { |
| |
| String[] objectClasses = canonicalize(serviceReference.getProperty( |
| "objectClass")); |
| |
| return Arrays.stream(objectClasses). |
| anyMatch(SUPPORTED_EXTENSION_INTERFACES::containsKey); |
| } |
| |
| private interface ChangeCounter { |
| |
| void inc(); |
| |
| } |
| |
| private static class ServiceRegistrationChangeCounter |
| implements ChangeCounter{ |
| |
| private static final String changecount = "service.changecount"; |
| private final AtomicLong _atomicLong = new AtomicLong(); |
| private final ServiceRegistration<?> _serviceRegistration; |
| |
| ServiceRegistrationChangeCounter( |
| ServiceRegistration<?> serviceRegistration) { |
| |
| _serviceRegistration = serviceRegistration; |
| } |
| |
| @Override |
| public void inc() { |
| long l = _atomicLong.incrementAndGet(); |
| |
| synchronized (_serviceRegistration) { |
| updateProperty(_serviceRegistration, changecount, l); |
| } |
| } |
| } |
| |
| private static final Filter _extensionsFilter; |
| |
| private static final Filter _resourcesFilter; |
| |
| private static Filter _applicationsFilter; |
| |
| static { |
| try { |
| _applicationsFilter = FrameworkUtil.createFilter( |
| format( |
| "(&(objectClass=%s)(%s=*))", Application.class.getName(), |
| JAX_RS_APPLICATION_BASE)); |
| _extensionsFilter = FrameworkUtil.createFilter( |
| format("(%s=true)", JAX_RS_EXTENSION)); |
| _resourcesFilter = FrameworkUtil.createFilter( |
| format("(%s=true)", JAX_RS_RESOURCE)); |
| } |
| catch (InvalidSyntaxException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| private class ApplicationReferenceWithContext |
| implements Comparable<ApplicationReferenceWithContext> { |
| |
| @Override |
| public int compareTo(ApplicationReferenceWithContext o) { |
| return _applicationReference.compareTo(o._applicationReference); |
| } |
| |
| private CachingServiceReference<ServletContextHelper> _contextReference; |
| private CachingServiceReference<Application> _applicationReference; |
| |
| public ApplicationReferenceWithContext( |
| CachingServiceReference<ServletContextHelper> contextReference, |
| CachingServiceReference<Application> applicationReference) { |
| |
| _contextReference = contextReference; |
| _applicationReference = applicationReference; |
| } |
| |
| public String getActualBasePath() { |
| String applicationBase = getApplicationBase( |
| _applicationReference::getProperty); |
| |
| if (_contextReference == null) { |
| return applicationBase; |
| } |
| |
| Object property = _contextReference.getProperty( |
| HTTP_WHITEBOARD_CONTEXT_PATH); |
| |
| if (property == null) { |
| return applicationBase; |
| } |
| |
| String contextPath = property.toString(); |
| |
| return contextPath + applicationBase; |
| } |
| |
| public CachingServiceReference<ServletContextHelper> |
| getContextReference() { |
| |
| return _contextReference; |
| } |
| |
| public CachingServiceReference<Application> getApplicationReference() { |
| return _applicationReference; |
| } |
| |
| } |
| |
| } |