blob: 375ba79ebe4ce304e25d91aed9beff6abf1f7ba9 [file] [log] [blame]
/*
* 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.activator;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.ext.RuntimeDelegate;
import javax.ws.rs.sse.SseEventSource;
import org.apache.aries.jax.rs.whiteboard.internal.client.ClientBuilderFactory;
import org.apache.aries.jax.rs.whiteboard.internal.utils.PropertyHolder;
import org.apache.aries.component.dsl.OSGi;
import org.apache.aries.component.dsl.OSGiResult;
import org.apache.cxf.bus.osgi.CXFActivator;
import org.apache.cxf.jaxrs.impl.RuntimeDelegateImpl;
import org.apache.cxf.jaxrs.sse.client.SseEventSourceBuilderImpl;
import org.osgi.annotation.bundle.Header;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.http.runtime.HttpServiceRuntime;
import org.osgi.service.jaxrs.client.SseEventSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.lang.String.format;
import static org.apache.aries.component.dsl.OSGi.coalesce;
import static org.apache.aries.component.dsl.OSGi.configuration;
import static org.apache.aries.jax.rs.whiteboard.internal.utils.LogUtils.ifInfoEnabled;
import static org.apache.aries.jax.rs.whiteboard.internal.utils.LogUtils.debugTracking;
import static org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.canonicalize;
import static org.apache.aries.jax.rs.whiteboard.internal.Whiteboard.createWhiteboard;
import static org.apache.aries.component.dsl.OSGi.all;
import static org.apache.aries.component.dsl.OSGi.bundles;
import static org.apache.aries.component.dsl.OSGi.configurations;
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.once;
import static org.apache.aries.component.dsl.OSGi.register;
import static org.apache.aries.component.dsl.OSGi.serviceReferences;
import static org.osgi.framework.Bundle.ACTIVE;
import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT;
import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.HTTP_WHITEBOARD_TARGET;
@Header(name = Constants.BUNDLE_ACTIVATOR, value = "${@class}")
public class CxfJaxrsBundleActivator implements BundleActivator {
public static final List<Class<?>> INTERNALLY_REQUIRED_CLASSES;
private static final Logger _log = LoggerFactory.getLogger(
CxfJaxrsBundleActivator.class);
static {
Class<?> xmlLocation;
try {
xmlLocation = com.sun.xml.bind.annotation.XmlLocation.class;
} catch (NoClassDefFoundError e) {
// Swallow it
xmlLocation = null;
}
Class<?> wstxInputFactory = com.ctc.wstx.stax.WstxInputFactory.class;
INTERNALLY_REQUIRED_CLASSES = xmlLocation == null ? Collections.singletonList(wstxInputFactory) :
Arrays.asList(wstxInputFactory, xmlLocation);
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
}
@Override
public void start(BundleContext bundleContext) throws Exception {
RuntimeDelegate.setInstance(new RuntimeDelegateImpl());
if (_log.isDebugEnabled()) {
_log.debug("Starting the whiteboard factory");
}
OSGi<?> runWhiteboards =
bundles(ACTIVE)
.filter(b -> b.equals(FrameworkUtil.getBundle(CXFActivator.class)))
.then(
all(
configurations("org.apache.aries.jax.rs.whiteboard"),
coalesce(
configuration("org.apache.aries.jax.rs.whiteboard.default"),
just(() -> {
Dictionary<String, Object> properties =
new Hashtable<>();
properties.put(
Constants.SERVICE_PID,
"org.apache.aries.jax.rs.whiteboard.default");
return properties;
})
)
).filter(
c -> !Objects.equals(c.get("enabled"), "false")
).
effects(
debugTracking(_log, () -> "whiteboard configuration")
).flatMap(configuration ->
runWhiteboard(bundleContext, configuration)
));
_defaultOSGiResult =
all(
ignore(registerClient()),
ignore(registerSseEventSourceFactory()),
ignore(runWhiteboards)
)
.run(bundleContext);
if (_log.isDebugEnabled()) {
_log.debug("Whiteboard factory started");
}
}
@Override
public void stop(BundleContext context) throws Exception {
if (_log.isDebugEnabled()) {
_log.debug("Stopping whiteboard factory");
}
_defaultOSGiResult.close();
if (_log.isDebugEnabled()) {
_log.debug("Stopped whiteboard factory");
}
RuntimeDelegate.setInstance(null);
}
private OSGiResult _defaultOSGiResult;
private static String endpointFilter(PropertyHolder configuration) {
Object whiteBoardTargetProperty = configuration.get(
HTTP_WHITEBOARD_TARGET);
String targetFilter =
whiteBoardTargetProperty != null ?
whiteBoardTargetProperty.toString() :
"(osgi.http.endpoint=*)";
return format(
"(&(objectClass=%s)%s)", HttpServiceRuntime.class.getName(),
targetFilter);
}
private static OSGi<?> registerClient() {
return register(
ClientBuilder.class, new ClientBuilderFactory(),
(Map<String, Object>) null).
effects(
ifInfoEnabled(_log, () -> "Registered ClientBuilder"),
ifInfoEnabled(_log, () -> "Unregistered ClientBuilder")
);
}
private static OSGi<?> registerSseEventSourceFactory() {
return register(
SseEventSourceFactory.class, new SseEventSourceFactory() {
@Override
public SseEventSource.Builder newBuilder(WebTarget target) {
return new SseEventSourceBuilderImpl(){{target(target);}};
}
@Override
public SseEventSource newSource(WebTarget target) {
return newBuilder(target).build();
}
},
new Hashtable<>()).
effects(
ifInfoEnabled(_log, () -> "Registered SseEventSourceFactory"),
ifInfoEnabled(_log, () -> "Unregistered SseEventSourceFactory")
);
}
private static OSGi<?> runWhiteboard(
BundleContext bundleContext, Dictionary<String, ?> configuration) {
OSGi<List<String>> endpoints =
serviceReferences(endpointFilter(configuration::get)
).map(
r -> Arrays.asList(
canonicalize(r.getProperty(HTTP_SERVICE_ENDPOINT)))
);
return
once(
serviceReferences(
endpointFilter(configuration::get),
__ -> false //never reload
).then(
just(createWhiteboard(configuration)).
effects(
ifInfoEnabled(
_log,
() -> "created whiteboard from configuration: " +
configuration),
ifInfoEnabled(
_log,
() -> "destroyed whiteboard from configuration: " +
configuration)
)
.flatMap(
whiteboard ->
all(
effects(
() -> whiteboard.start(bundleContext),
whiteboard::stop),
ignore(
endpoints.effects(
whiteboard::addHttpEndpoints,
whiteboard::removeHttpEndpoints)
).
effects(
debugTracking(
_log,
() -> "endpoint for whiteboard: " +
whiteboard)
)
)
))
);
}
}