blob: 8cf4ea3804f5f8173443194aec555ca2656f29bd [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.ace.http.listener;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import javax.servlet.Servlet;
import org.apache.ace.http.listener.constants.HttpConstants;
import org.apache.felix.dm.DependencyActivatorBase;
import org.apache.felix.dm.DependencyManager;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.service.http.HttpService;
import org.osgi.service.log.LogService;
/**
* Service responsible for registrating Servlets at HttpServices.
* <p>
*
* When a Servlet is being added or removed, the callback methods in this class are being called via the
* DependencyManager. A Servlet is being added to all HttpServices currently available or removed from all available
* HttpServices.
* <p>
*
* In case a HttpService is being added or removed, other callback methods are being called via the DependencyManager.
* When a HttpService is added, all previously registered Servlets are being registered to this new HttpService. In case
* of removal, all Servlet endpoints are being removed from the HttpService that is going to be removed.
* <p>
*/
public class Activator extends DependencyActivatorBase {
private static final String INIT_PREFIX = "init.";
private final Set<ServiceReference<HttpService>> m_httpServices = new HashSet<>();
private final Map<ServiceReference<Servlet>, String> m_servlets = new HashMap<>();
private volatile LogService m_log; // injected
private BundleContext m_context;
@Override
public synchronized void init(BundleContext context, DependencyManager manager) throws Exception {
m_context = context;
manager.add(createComponent()
.setImplementation(this)
.add(createServiceDependency()
.setService(LogService.class)
.setRequired(false))
.add(createServiceDependency()
.setService(HttpService.class)
.setAutoConfig(false)
.setCallbacks("addHttpService", "removeHttpService"))
.add(createServiceDependency()
.setService(Servlet.class, "(" + HttpConstants.ENDPOINT + "=*)")
.setAutoConfig(false)
.setCallbacks("addServlet", "changeServlet", "removeServlet")));
}
/**
* Callback method used in case a Servlet is being added. This Servlet is being added to all available HttpServices
* under the endpoint configured via the Configurator.
*
* @param ref
* reference to the Servlet
*/
public synchronized void addServlet(ServiceReference<Servlet> ref) {
// register servlet to all HttpServices
String endpoint = (String) ref.getProperty(HttpConstants.ENDPOINT);
m_servlets.put(ref, endpoint);
Servlet servlet = m_context.getService(ref);
Dictionary<String, Object> initParams = getInitParams(ref);
for (ServiceReference<HttpService> reference : m_httpServices) {
HttpService httpService = m_context.getService(reference);
try {
if ((httpService != null) && (endpoint != null) && (servlet != null)) {
httpService.registerServlet(endpoint, servlet, initParams, null);
}
else {
m_log.log(LogService.LOG_WARNING, "Unable to register servlet with endpoint '" + endpoint + "'");
}
}
catch (Exception e) {
m_log.log(LogService.LOG_WARNING, "Already registered under existing endpoint", e);
}
}
}
private Dictionary<String, Object> getInitParams(ServiceReference<?> ref) {
Dictionary<String, Object> initParams = new Hashtable<>();
for (String key : ref.getPropertyKeys()) {
if (key.startsWith(INIT_PREFIX)) {
initParams.put(key.substring(INIT_PREFIX.length()), ref.getProperty(key));
}
}
return initParams;
}
/**
* Callback method used in case a Servlet is being changed. This Servlet is removed and then added again.
*
* @param ref
* reference to the Servlet
*/
public synchronized void changeServlet(ServiceReference<Servlet> ref) {
removeServlet(ref, m_servlets.get(ref));
addServlet(ref);
}
/**
* Callback method used in case a Servlet is being removed. This Servlet is being removed from all available
* HttpServices using the endpoint configured via the Configurator.
*
* @param ref
* reference to the Servlet
*/
public synchronized void removeServlet(ServiceReference<Servlet> ref) {
// remove servlet from all HttpServices
String endpoint = (String) ref.getProperty(HttpConstants.ENDPOINT);
removeServlet(ref, endpoint);
}
private void removeServlet(ServiceReference<Servlet> ref, String endpoint) {
m_servlets.remove(ref);
for (ServiceReference<HttpService> reference : m_httpServices) {
HttpService httpService = m_context.getService(reference);
if ((httpService != null) && (endpoint != null)) {
try {
httpService.unregister(endpoint);
}
catch (Exception e) {
m_log.log(LogService.LOG_WARNING, "Servlet cannot be unregistered, maybe not registered under this endpoint", e);
}
}
}
}
/**
* Callback method used in case a HttpService is being added. To this Service all previously registered Servlet are
* added under the endpoints of the Servlets (which are configured via the Configurator).
*
* @param ref
* reference to the Service
*/
public synchronized void addHttpService(ServiceReference<HttpService> ref, HttpService httpService) {
m_httpServices.add(ref);
// register all servlets to this new HttpService
for (ServiceReference<Servlet> reference : m_servlets.keySet()) {
Servlet servlet = m_context.getService(reference);
String endpoint = (String) reference.getProperty(HttpConstants.ENDPOINT);
if ((servlet != null) && (endpoint != null)) {
Dictionary<String, Object> initParams = getInitParams(reference);
try {
httpService.registerServlet(endpoint, servlet, initParams, null);
}
catch (Exception e) {
m_log.log(LogService.LOG_WARNING, "Already registered under existing endpoint", e);
}
}
}
}
/**
* Callback method used in case a HttpService is being removed. From this Service all previously registered Servlet
* are removed using the endpoints of the Servlets (which are configured via the Configurator).
*
* @param ref
* reference to the Service
*/
public synchronized void removeHttpService(ServiceReference<HttpService> ref, HttpService httpService) {
m_httpServices.remove(ref);
// remove references from the unregistered HttpService
unregisterEndpoints(httpService);
}
@Override
public synchronized void destroy(BundleContext context, DependencyManager arg1) throws Exception {
for (ServiceReference<HttpService> httpRef : m_httpServices) {
HttpService httpService = m_context.getService(httpRef);
if (httpService != null) {
unregisterEndpoints(httpService);
}
}
m_httpServices.clear();
m_servlets.clear();
m_context = null;
}
/**
* Unregisters all Servlets (via their endpoints) from the HttpService being passed to this method.
*
* @param httpService
* the HttpService that is being unregistered
*/
private void unregisterEndpoints(HttpService httpService) {
for (ServiceReference<Servlet> reference : m_servlets.keySet()) {
String endpoint = (String) reference.getProperty(HttpConstants.ENDPOINT);
if (endpoint != null) {
try {
httpService.unregister(endpoint);
}
catch (Exception e) {
m_log.log(LogService.LOG_WARNING, "Servlet cannot be unregistered, maybe not registered under this endpoint", e);
}
}
}
}
}