blob: 9004aae95f0071f05cd6894dcb5c4e99925eb01f [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.unomi.rest;
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
import org.apache.cxf.Bus;
import org.apache.cxf.BusFactory;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.feature.LoggingFeature;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.openapi.OpenApiCustomizer;
import org.apache.cxf.jaxrs.openapi.OpenApiFeature;
import org.apache.cxf.jaxrs.security.JAASAuthenticationFilter;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.ext.ExceptionMapper;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
@Component
public class RestServer {
private static final Logger logger = LoggerFactory.getLogger(RestServer.class.getName());
private Server server;
private BundleContext bundleContext;
private ServiceTracker jaxRSServiceTracker;
private List<ExceptionMapper> exceptionMappers = new ArrayList<>();
private long timeOfLastUpdate = System.currentTimeMillis();
private Timer refreshTimer = null;
private long startupDelay = 1000L;
final List<Object> serviceBeans = new CopyOnWriteArrayList<>();
@Reference
public void addExceptionMapper(ExceptionMapper exceptionMapper) {
this.exceptionMappers.add(exceptionMapper);
timeOfLastUpdate = System.currentTimeMillis();
refreshServer();
}
public void removeExceptionMapper(ExceptionMapper exceptionMapper) {
this.exceptionMappers.remove(exceptionMapper);
timeOfLastUpdate = System.currentTimeMillis();
refreshServer();
}
@Activate
public void activate(ComponentContext componentContext) throws Exception {
this.bundleContext = componentContext.getBundleContext();
Filter filter = bundleContext.createFilter("(osgi.jaxrs.resource=true)");
jaxRSServiceTracker = new ServiceTracker(bundleContext, filter, new ServiceTrackerCustomizer() {
@Override
public Object addingService(ServiceReference reference) {
Object serviceBean = bundleContext.getService(reference);
logger.info("Registering JAX RS service " + serviceBean.getClass().getName());
serviceBeans.add(serviceBean);
timeOfLastUpdate = System.currentTimeMillis();
refreshServer();
return serviceBean;
}
@Override
public void modifiedService(ServiceReference reference, Object service) {
logger.info("Refreshing JAX RS server because service " + service.getClass().getName() + " was modified.");
timeOfLastUpdate = System.currentTimeMillis();
refreshServer();
}
@Override
public void removedService(ServiceReference reference, Object service) {
Object serviceBean = bundleContext.getService(reference);
logger.info("Removing JAX RS service " + serviceBean.getClass().getName());
serviceBeans.remove(serviceBean);
timeOfLastUpdate = System.currentTimeMillis();
refreshServer();
}
});
jaxRSServiceTracker.open();
}
@Deactivate
public void deactivate() throws Exception {
jaxRSServiceTracker.close();
if (server != null) {
server.destroy();
}
}
private synchronized void refreshServer() {
long now = System.currentTimeMillis();
logger.info("Time (millis) since last update: {}", now - timeOfLastUpdate);
if (now - timeOfLastUpdate < startupDelay) {
if (refreshTimer != null) {
return;
}
TimerTask task = new TimerTask() {
public void run() {
refreshTimer = null;
refreshServer();
logger.info("Refreshed server task performed on: " + new Date() +
" Thread's name: " + Thread.currentThread().getName());
}
};
refreshTimer = new Timer("Timer-Refresh-REST-API");
refreshTimer.schedule(task, startupDelay);
return;
}
if (server != null) {
logger.info("Shutting down JAX RS Endpoint... ");
server.destroy();
}
final OpenApiFeature openApiFeature = new OpenApiFeature();
openApiFeature.setContactEmail("dev@unomi.apache.org");
openApiFeature.setLicense("Apache 2.0 License");
openApiFeature.setLicenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html");
openApiFeature.setScan(false);
openApiFeature.setUseContextBasedConfig(true); //Set<String> resourceClasses = serviceBeans.stream().map(service -> service.getClass().getName()).collect(toSet());
OpenApiCustomizer customizer = new OpenApiCustomizer();
customizer.setDynamicBasePath(true);
openApiFeature.setCustomizer(customizer);
JAXRSServerFactoryBean jaxrsServerFactoryBean = new JAXRSServerFactoryBean();
jaxrsServerFactoryBean.setAddress("/");
Bus bus = BusFactory.getDefaultBus();
// bus.getFeatures().add(new LoggingFeature());
bus.getFeatures().add(new LoggingFeature());
bus.getFeatures().add(new org.apache.cxf.metrics.MetricsFeature());
jaxrsServerFactoryBean.setBus(bus);
jaxrsServerFactoryBean.setProvider(
new JacksonJaxbJsonProvider(
new org.apache.unomi.persistence.spi.CustomObjectMapper(),
JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS));
jaxrsServerFactoryBean.setProvider(new org.apache.cxf.rs.security.cors.CrossOriginResourceSharingFilter());
JAASAuthenticationFilter jaasFilter = new org.apache.cxf.jaxrs.security.JAASAuthenticationFilter();
jaasFilter.setContextName("karaf");
jaasFilter.setRoleClassifier("ROLE_");
jaasFilter.setRealmName("cxs");
jaxrsServerFactoryBean.setProvider(jaasFilter);
for (ExceptionMapper exceptionMapper : exceptionMappers) {
jaxrsServerFactoryBean.setProvider(exceptionMapper);
}
jaxrsServerFactoryBean.setServiceBeans(serviceBeans);
jaxrsServerFactoryBean.getFeatures().add(openApiFeature);
if (serviceBeans.size() > 0) {
logger.info("Starting JAX RS Endpoint...");
server = jaxrsServerFactoryBean.create();
}
}
}