blob: 4aaf3ae8c6ac9f5de7ad658413cc6ef03d46a904 [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.cxf.dosgi.dsw.handlers;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.apache.cxf.Bus;
import org.apache.cxf.bus.CXFBusFactory;
import org.apache.cxf.dosgi.dsw.Constants;
import org.apache.cxf.dosgi.dsw.util.OsgiUtils;
import org.apache.cxf.transport.http.DestinationRegistry;
import org.apache.cxf.transport.http.DestinationRegistryImpl;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceException;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.HttpService;
import org.osgi.util.tracker.ServiceTracker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpServiceManager {
private static final Logger LOG = LoggerFactory.getLogger(HttpServiceManager.class);
private ServiceTracker tracker;
private BundleContext bundleContext;
private Map<Long, String> exportedAliases = Collections.synchronizedMap(new HashMap<Long, String>());
private String httpBase;
private String cxfServletAlias;
public HttpServiceManager(BundleContext bundleContext, String httpBase, String cxfServletAlias) {
this(bundleContext, httpBase, cxfServletAlias,
new ServiceTracker(bundleContext, HttpService.class.getName(), null));
this.tracker.open();
}
// Only for tests
public HttpServiceManager(BundleContext bundleContext,
String httpBase, String cxfServletAlias,
ServiceTracker tracker) {
this.bundleContext = bundleContext;
this.tracker = tracker;
this.httpBase = getWithDefault(httpBase, "http://" + LocalHostUtil.getLocalIp() + ":8181");
this.cxfServletAlias = getWithDefault(cxfServletAlias, "/cxf");
}
private String getWithDefault(String value, String defaultValue) {
return value == null ? defaultValue : value;
}
public Bus registerServletAndGetBus(String contextRoot, BundleContext callingContext,
ServiceReference sref) {
Bus bus = new CXFBusFactory().createBus();
bus.setExtension(new DestinationRegistryImpl(), DestinationRegistry.class);
CXFNonSpringServlet cxf = new CXFNonSpringServlet();
cxf.setBus(bus);
try {
HttpService httpService = getHttpService();
httpService.registerServlet(contextRoot, cxf, new Hashtable<String, String>(),
getHttpContext(callingContext, httpService));
registerUnexportHook(sref, contextRoot);
LOG.info("Successfully registered CXF DOSGi servlet at " + contextRoot);
} catch (Exception e) {
throw new ServiceException("CXF DOSGi: problem registering CXF HTTP Servlet", e);
}
return bus;
}
protected HttpService getHttpService() {
Object service = tracker.getService();
if (service == null) {
throw new RuntimeException("No HTTPService found");
}
return (HttpService) service;
}
public String getServletContextRoot(Map<String, Object> sd) {
return OsgiUtils.getFirstNonEmptyStringProperty(sd,
Constants.WS_HTTP_SERVICE_CONTEXT,
Constants.WS_HTTP_SERVICE_CONTEXT_OLD,
Constants.WSDL_HTTP_SERVICE_CONTEXT,
Constants.RS_HTTP_SERVICE_CONTEXT);
}
private HttpContext getHttpContext(BundleContext bc, HttpService httpService) {
HttpContext httpContext = httpService.createDefaultHttpContext();
return new SecurityDelegatingHttpContext(bc, httpContext);
}
/**
* This listens for service removal events and "un-exports" the service
* from the HttpService.
*
* @param sref the service reference to track
* @param alias the HTTP servlet context alias
*/
private void registerUnexportHook(ServiceReference sref, String alias) {
final Long sid = (Long) sref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
LOG.debug("Registering service listener for service with ID {}", sid);
String previous = exportedAliases.put(sid, alias);
if (previous != null) {
LOG.warn("Overwriting service export for service with ID {}", sid);
}
try {
Filter f = bundleContext.createFilter("(" + org.osgi.framework.Constants.SERVICE_ID + "=" + sid + ")");
if (f != null) {
bundleContext.addServiceListener(new UnregisterListener(), f.toString());
} else {
LOG.warn("Service listener could not be started. The service will not be automatically unexported.");
}
} catch (InvalidSyntaxException e) {
LOG.warn("Service listener could not be started. The service will not be automatically unexported.", e);
}
}
protected String getDefaultAddress(Class<?> type) {
return "/" + type.getName().replace('.', '/');
}
protected String getAbsoluteAddress(String contextRoot, String relativeEndpointAddress) {
if (relativeEndpointAddress.startsWith("http")) {
return relativeEndpointAddress;
}
String effContextRoot = contextRoot == null ? cxfServletAlias : contextRoot;
return this.httpBase + effContextRoot + relativeEndpointAddress;
}
public void close() {
tracker.close();
}
private final class UnregisterListener implements ServiceListener {
public void serviceChanged(ServiceEvent event) {
if (!(event.getType() == ServiceEvent.UNREGISTERING)) {
return;
}
final ServiceReference sref = event.getServiceReference();
final Long sid = (Long) sref.getProperty(org.osgi.framework.Constants.SERVICE_ID);
final String alias = exportedAliases.remove(sid);
if (alias == null) {
LOG.error("Unable to unexport HTTP servlet for service class '{}',"
+ " service-id {}: no servlet alias found",
sref.getProperty(org.osgi.framework.Constants.OBJECTCLASS), sid);
return;
}
LOG.debug("Unexporting HTTP servlet for alias '{}'", alias);
try {
HttpService http = getHttpService();
http.unregister(alias);
} catch (Exception e) {
LOG.warn("An exception occurred while unregistering service for HTTP servlet alias '{}'", alias, e);
}
}
}
}