/*******************************************************************************
 * Copyright (c) 2014, 2019 Raymond Augé and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     Raymond Augé - bug fixes and enhancements
 ******************************************************************************/

package org.eclipse.equinox.http.servlet.internal;

import static org.osgi.service.http.runtime.HttpServiceRuntimeConstants.HTTP_SERVICE_ENDPOINT;
import static org.osgi.service.http.whiteboard.HttpWhiteboardConstants.*;

import java.io.IOException;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.http.*;
import org.eclipse.equinox.http.servlet.context.ContextPathCustomizer;
import org.eclipse.equinox.http.servlet.internal.context.*;
import org.eclipse.equinox.http.servlet.internal.dto.ExtendedErrorPageDTO;
import org.eclipse.equinox.http.servlet.internal.dto.ExtendedFailedServletContextDTO;
import org.eclipse.equinox.http.servlet.internal.error.*;
import org.eclipse.equinox.http.servlet.internal.registration.PreprocessorRegistration;
import org.eclipse.equinox.http.servlet.internal.servlet.HttpSessionTracker;
import org.eclipse.equinox.http.servlet.internal.servlet.Match;
import org.eclipse.equinox.http.servlet.internal.util.*;
import org.eclipse.equinox.http.servlet.session.HttpSessionInvalidator;
import org.osgi.framework.*;
import org.osgi.framework.dto.ServiceReferenceDTO;
import org.osgi.service.http.HttpContext;
import org.osgi.service.http.NamespaceException;
import org.osgi.service.http.context.ServletContextHelper;
import org.osgi.service.http.runtime.HttpServiceRuntime;
import org.osgi.service.http.runtime.dto.*;
import org.osgi.service.http.whiteboard.Preprocessor;
import org.osgi.service.log.Logger;
import org.osgi.service.log.LoggerFactory;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
 * @author Raymond Augé
 */
public class HttpServiceRuntimeImpl
	implements
		HttpServiceRuntime,
		ServiceTrackerCustomizer<ServletContextHelper, AtomicReference<ContextController>> {

	@SuppressWarnings("unchecked")
	public HttpServiceRuntimeImpl(
		BundleContext trackingContext, BundleContext consumingContext,
		ServletContext parentServletContext, Dictionary<String, Object> attributes) {

		this.trackingContext = trackingContext;
		this.consumingContext = consumingContext;

		this.errorPageServiceFilter = createErrorPageFilter(consumingContext);
		this.servletServiceFilter = createServletFilter(consumingContext);
		this.resourceServiceFilter = createResourceFilter(consumingContext);
		this.filterServiceFilter = createFilterFilter(consumingContext);
		this.listenerServiceFilter = createListenerFilter(consumingContext);

		this.parentServletContext = parentServletContext;
		this.attributes = new UMDictionaryMap<String, Object>(attributes);
		this.targetFilter = "(" + Activator.UNIQUE_SERVICE_ID + "=" + this.attributes.get(Activator.UNIQUE_SERVICE_ID) + ")";  //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
		this.httpSessionTracker = new HttpSessionTracker(this);
		this.invalidatorReg = trackingContext.registerService(HttpSessionInvalidator.class, this.httpSessionTracker, attributes);

		loggerFactoryTracker = new ServiceTracker<>(consumingContext, LoggerFactory.class, new ServiceTrackerCustomizer<LoggerFactory, Logger>() {
			@Override
			public Logger addingService(ServiceReference<LoggerFactory> reference) {
				return getConsumingContext().getService(reference).getLogger(HttpServiceRuntimeImpl.class);
			}
			@Override
			public void modifiedService(ServiceReference<LoggerFactory> reference, Logger service) {
				// ignore
			}
			@Override
			public void removedService(ServiceReference<LoggerFactory> reference, Logger service) {
				// ignore
			}
		});
		loggerFactoryTracker.open();

		contextServiceTracker =
			new ServiceTracker<ServletContextHelper, AtomicReference<ContextController>>(
				trackingContext, ServletContextHelper.class, this);

		preprocessorServiceTracker =
			new ServiceTracker<Preprocessor, AtomicReference<PreprocessorRegistration>>(
				trackingContext, Preprocessor.class, new PreprocessorCustomizer(this));

		contextPathCustomizerHolder = new ContextPathCustomizerHolder(consumingContext, contextServiceTracker);
		contextPathAdaptorTracker = new ServiceTracker<ContextPathCustomizer, ContextPathCustomizer>(
			consumingContext, ContextPathCustomizer.class, contextPathCustomizerHolder);

		Hashtable<String, Object> defaultContextProps = new Hashtable<String, Object>();
		defaultContextProps.put(HTTP_WHITEBOARD_CONTEXT_NAME, HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
		defaultContextProps.put(Constants.SERVICE_RANKING, Integer.MIN_VALUE);
		defaultContextProps.put(HTTP_WHITEBOARD_CONTEXT_PATH, Const.SLASH);
		defaultContextProps.put(HTTP_WHITEBOARD_TARGET, this.targetFilter);
		defaultContextProps.put(HTTP_SERVICE_CONTEXT_PROPERTY, HTTP_WHITEBOARD_DEFAULT_CONTEXT_NAME);
		defaultContextReg = (ServiceRegistration<DefaultServletContextHelper>) consumingContext.registerService(
			new String [] {ServletContextHelper.class.getName(), DefaultServletContextHelper.class.getName()}, new DefaultServletContextHelperFactory(), defaultContextProps);
	}

	public synchronized void open() {
		contextPathAdaptorTracker.open();
		contextServiceTracker.open();
		preprocessorServiceTracker.open();
	}

	@Override
	public synchronized AtomicReference<ContextController> addingService(
		ServiceReference<ServletContextHelper> serviceReference) {

		AtomicReference<ContextController> result = new AtomicReference<ContextController>();
		if (!matches(serviceReference)) {
			return result;
		}

		try {
			ContextController contextController = new ContextController(
				trackingContext, consumingContext, serviceReference, parentServletContext, this);

			controllerMap.put(serviceReference, contextController);

			result.set(contextController);
		}
		catch (HttpWhiteboardFailureException hwfe) {
			debug(hwfe.getMessage(), hwfe);

			recordFailedServletContextDTO(serviceReference, 0, hwfe.getFailureReason());
		}
		catch (Throwable t) {
			error(t.getMessage(), t);

			recordFailedServletContextDTO(serviceReference, 0, DTOConstants.FAILURE_REASON_EXCEPTION_ON_INIT);
		}
		finally {
			incrementServiceChangecount();
		}

		return result;
	}

	public String adaptContextPath(String contextPath, ServiceReference<ServletContextHelper> helper) {
		ContextPathCustomizer pathAdaptor = contextPathCustomizerHolder.getHighestRanked();
		if (pathAdaptor != null) {
			String contextPrefix = pathAdaptor.getContextPathPrefix(helper);
			if (contextPrefix != null && !contextPrefix.isEmpty() && !contextPrefix.equals(Const.SLASH)) {
				if (!contextPrefix.startsWith(Const.SLASH)) {
					contextPrefix = Const.SLASH + contextPrefix;
				}
				// make sure we do not append SLASH context path here
				if (contextPath == null || contextPath.equals(Const.SLASH)) {
					contextPath = Const.BLANK;
				}
				return contextPrefix + contextPath;
			}
		}
		return contextPath;
	}

	public BundleContext getConsumingContext() {
		return consumingContext;
	}

	public String getDefaultContextSelectFilter(ServiceReference<?> httpWhiteBoardService) {
		ContextPathCustomizer pathAdaptor = contextPathCustomizerHolder.getHighestRanked();
		if (pathAdaptor != null) {
			return pathAdaptor.getDefaultContextSelectFilter(httpWhiteBoardService);
		}
		return null;
	}

	public boolean isDefaultContext(ContextController contextController) {
		ServiceReference<?> thisReference = defaultContextReg.getReference();
		ServiceReference<ServletContextHelper> contextReference = contextController.getServiceReference();
		if (thisReference == null) throw new NullPointerException("Default Context Service reference is null. " + this); //$NON-NLS-1$
		if (contextReference == null) throw new NullPointerException("Context Service reference is null. " + contextController); //$NON-NLS-1$
		return thisReference.equals(contextReference);
	}

	public boolean isFailedResourceDTO(ServiceReference<?> serviceReference) {
		return failedResourceDTOs.containsKey(serviceReference);
	}

	public boolean isFailedServletDTO(ServiceReference<?> serviceReference) {
		return failedServletDTOs.containsKey(serviceReference);
	}

	public boolean isFailedErrorPageDTO(ServiceReference<?> serviceReference) {
		return failedErrorPageDTOs.containsKey(serviceReference);
	}

	@Override
	public synchronized RequestInfoDTO calculateRequestInfoDTO(String path) {
		RequestInfoDTO requestInfoDTO = new RequestInfoDTO();

		requestInfoDTO.path = path;

		try {
			getDispatchTargets(path, requestInfoDTO);
		}
		catch (Exception e) {
			throw new RuntimeException(e);
		}

		return requestInfoDTO;
	}

	public synchronized void destroy() {
		invalidatorReg.unregister();

		try {
			defaultContextReg.unregister();
		}
		catch (IllegalStateException ise) {
			// ignore
		}

		contextServiceTracker.close();
		contextPathAdaptorTracker.close();
		preprocessorServiceTracker.close();

		controllerMap.clear();
		preprocessorMap.clear();
		registeredObjects.clear();
		legacyContextMap.clear();

		failedErrorPageDTOs.clear();
		failedFilterDTOs.clear();
		failedListenerDTOs.clear();
		failedPreprocessorDTOs.clear();
		failedResourceDTOs.clear();
		failedServletContextDTOs.clear();
		failedServletDTOs.clear();

		httpSessionTracker.clear();
		registeredObjects.clear();
		scheduledExecutor.shutdown();
		loggerFactoryTracker.close();
	}

	public DispatchTargets getDispatchTargets(
		String pathString, RequestInfoDTO requestInfoDTO) {

		Path path = new Path(pathString);

		String queryString = path.getQueryString();
		String requestURI = path.getRequestURI();

		// perfect match
		DispatchTargets dispatchTargets = getDispatchTargets(
			requestURI, null, queryString, Match.EXACT, requestInfoDTO);

		if (dispatchTargets == null) {
			// extension match

			dispatchTargets = getDispatchTargets(
				requestURI, path.getExtension(), queryString, Match.EXTENSION,
				requestInfoDTO);
		}

		if (dispatchTargets == null) {
			// regex match
			dispatchTargets = getDispatchTargets(
				requestURI, null, queryString, Match.REGEX, requestInfoDTO);
		}

		if (dispatchTargets == null) {
			// handle with servlet mapped to '/'
			// the servletpath is the requestURI minus the contextpath and the pathinfo is null
			dispatchTargets = getDispatchTargets(
				requestURI, null, queryString, Match.DEFAULT_SERVLET,
				requestInfoDTO);
		}

		if (dispatchTargets == null && Const.SLASH.equals(pathString)) {
			// handle with servlet mapped to '' (empty string)
			// the pathinfo is '/' and the servletpath and contextpath are the empty string ("")
			dispatchTargets = getDispatchTargets(
				requestURI, null, queryString, Match.CONTEXT_ROOT,
				requestInfoDTO);
		}

		return dispatchTargets;
	}

	public HttpSessionTracker getHttpSessionTracker() {
		return httpSessionTracker;
	}

	public Set<Object> getRegisteredObjects() {
		return registeredObjects;
	}

	public String getTargetFilter() {
		return targetFilter;
	}

	public ServletContext getParentServletContext() {
		return parentServletContext;
	}

	public List<String> getHttpServiceEndpoints() {
		return StringPlus.from(
			attributes.get(HTTP_SERVICE_ENDPOINT));
	}

	@Override
	public synchronized RuntimeDTO getRuntimeDTO() {
		RuntimeDTO runtimeDTO = new RuntimeDTO();

		runtimeDTO.failedErrorPageDTOs = getFailedErrorPageDTOs();
		runtimeDTO.failedFilterDTOs = getFailedFilterDTOs();
		runtimeDTO.failedListenerDTOs = getFailedListenerDTOs();
		runtimeDTO.failedPreprocessorDTOs = getFailedPreprocessorDTOs();
		runtimeDTO.failedResourceDTOs = getFailedResourceDTOs();
		runtimeDTO.failedServletContextDTOs = getFailedServletContextDTO();
		runtimeDTO.failedServletDTOs = getFailedServletDTOs();
		runtimeDTO.preprocessorDTOs = getPreprocessorDTOs();
		runtimeDTO.serviceDTO = getServiceDTO();
		runtimeDTO.servletContextDTOs = getServletContextDTOs();

		return runtimeDTO;
	}

	private FailedErrorPageDTO[] getFailedErrorPageDTOs() {
		Collection<FailedErrorPageDTO> fepDTOs = failedErrorPageDTOs.values();

		List<FailedErrorPageDTO> copies = new ArrayList<FailedErrorPageDTO>();

		for (FailedErrorPageDTO failedErrorPageDTO : fepDTOs) {
			copies.add(DTOUtil.clone(failedErrorPageDTO));
		}

		return copies.toArray(new FailedErrorPageDTO[0]);
	}

	private ServiceReferenceDTO getServiceDTO() {
		ServiceReferenceDTO[] services = consumingContext.getBundle().adapt(ServiceReferenceDTO[].class);
		for (ServiceReferenceDTO serviceDTO : services) {
			String[] serviceTypes = (String[]) serviceDTO.properties.get(Constants.OBJECTCLASS);
			for (String type : serviceTypes) {
				if (HttpServiceRuntime.class.getName().equals(type)) {
					return serviceDTO;
				}
			}
		}
		return null;
	}

	public void debug(String message) {
		Logger logger = loggerFactoryTracker.getService();
		if (logger == null) {
			parentServletContext.log(String.valueOf(message));
		}
		else {
			logger.debug(String.valueOf(message));
		}
	}

	public void debug(String message, Throwable t) {
		Logger logger = loggerFactoryTracker.getService();
		if (logger == null) {
			parentServletContext.log(String.valueOf(message), t);
		}
		else {
			logger.debug(String.valueOf(message), t);
		}
	}

	public void error(String message, Throwable t) {
		Logger logger = loggerFactoryTracker.getService();
		if (logger == null) {
			parentServletContext.log(String.valueOf(message), t);
		}
		else {
			logger.error(String.valueOf(message), t);
		}
	}

	public boolean matches(ServiceReference<?> serviceReference) {
		String target = (String)serviceReference.getProperty(HTTP_WHITEBOARD_TARGET);

		if (target == null) {
			return true;
		}

		org.osgi.framework.Filter whiteboardTargetFilter;

		try {
			whiteboardTargetFilter = FrameworkUtil.createFilter(target);
		}
		catch (InvalidSyntaxException ise) {
			throw new IllegalArgumentException(ise);
		}

		if (whiteboardTargetFilter.matches(attributes)) {
			return true;
		}

		return false;
	}

	public boolean matchesAnyContext(ServiceReference<?> serviceReference) {
		for (ContextController contextController : controllerMap.values()) {
			if (contextController.matches(serviceReference)) {
				return true;
			}
		}
		return false;
	}

	@Override
	public synchronized void modifiedService(
		ServiceReference<ServletContextHelper> serviceReference,
		AtomicReference<ContextController> contextController) {

		removedService(serviceReference, contextController);
		AtomicReference<ContextController> added = addingService(serviceReference);
		contextController.set(added.get());
	}

	@Override
	public synchronized void removedService(
		ServiceReference<ServletContextHelper> serviceReference,
		AtomicReference<ContextController> contextControllerRef) {

		try {
			ContextController contextController = contextControllerRef.get();
			if (contextController != null) {
				Iterator<Entry<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO>> iterator = failedServletContextDTOs.entrySet().iterator();
				while (iterator.hasNext()) {
					if (iterator.next().getValue().shadowingServiceId == contextController.getServiceId()) {
						iterator.remove();
					}
				}
				contextController.destroy();
			}
			failedServletContextDTOs.remove(serviceReference);
			controllerMap.remove(serviceReference);
			trackingContext.ungetService(serviceReference);
		}
		finally {
			incrementServiceChangecount();
		}
	}

	Collection<ContextController> getContextControllers(String requestURI) {
		int pos = requestURI.lastIndexOf('/');

		do {
			List<ContextController> contextControllers = new ArrayList<ContextController>();

			for (ContextController contextController : controllerMap.values()) {
				if (contextController.getContextPath().equals(requestURI)) {
					contextControllers.add(contextController);
				}
			}

			if (!contextControllers.isEmpty()) {
				return contextControllers;
			}

			if (pos > -1) {
				requestURI = requestURI.substring(0, pos);
				pos = requestURI.lastIndexOf('/');

				continue;
			}

			break;
		}
		while (true);

		return null;
	}

	public Collection<ContextController> getContextControllers() {
		return controllerMap.values();
	}

	public DispatchTargets getDispatchTargets(
		String requestURI, String extension, String queryString, Match match,
		RequestInfoDTO requestInfoDTO) {

		Collection<ContextController> contextControllers = getContextControllers(
			requestURI);

		if ((contextControllers == null) || contextControllers.isEmpty()) {
			return null;
		}

		String contextPath =
			contextControllers.iterator().next().getContextPath();

		requestURI = requestURI.substring(contextPath.length());

		int pos = requestURI.lastIndexOf('/');

		String servletPath = requestURI;
		String pathInfo = null;

		if (match == Match.CONTEXT_ROOT) {
			pathInfo = Const.SLASH;
			servletPath = Const.BLANK;
		}

		do {
			for (ContextController contextController : contextControllers) {
				DispatchTargets dispatchTargets =
					contextController.getDispatchTargets(
						null, requestURI, servletPath, pathInfo,
						extension, queryString, match, requestInfoDTO);

				if (dispatchTargets != null) {
					return dispatchTargets;
				}
			}

			if ((match == Match.EXACT) || (match == Match.CONTEXT_ROOT) || (match == Match.DEFAULT_SERVLET)) {
				break;
			}

			if (pos > -1) {
				String newServletPath = requestURI.substring(0, pos);
				pathInfo = requestURI.substring(pos);
				servletPath = newServletPath;
				pos = servletPath.lastIndexOf('/');

				continue;
			}

			break;
		}
		while (true);

		return null;
	}

	private FailedFilterDTO[] getFailedFilterDTOs() {
		Collection<FailedFilterDTO> ffDTOs = failedFilterDTOs.values();

		List<FailedFilterDTO> copies = new ArrayList<FailedFilterDTO>();

		for (FailedFilterDTO failedFilterDTO : ffDTOs) {
			copies.add(DTOUtil.clone(failedFilterDTO));
		}

		return copies.toArray(new FailedFilterDTO[0]);
	}

	private FailedListenerDTO[] getFailedListenerDTOs() {
		Collection<FailedListenerDTO> flDTOs = failedListenerDTOs.values();

		List<FailedListenerDTO> copies = new ArrayList<FailedListenerDTO>();

		for (FailedListenerDTO failedListenerDTO : flDTOs) {
			copies.add(DTOUtil.clone(failedListenerDTO));
		}

		return copies.toArray(new FailedListenerDTO[0]);
	}

	private FailedResourceDTO[] getFailedResourceDTOs() {
		Collection<FailedResourceDTO> frDTOs = failedResourceDTOs.values();

		List<FailedResourceDTO> copies = new ArrayList<FailedResourceDTO>();

		for (FailedResourceDTO failedResourceDTO : frDTOs) {
			copies.add(DTOUtil.clone(failedResourceDTO));
		}

		return copies.toArray(new FailedResourceDTO[0]);
	}

	private FailedServletContextDTO[] getFailedServletContextDTO() {
		Collection<ExtendedFailedServletContextDTO> fscDTOs = failedServletContextDTOs.values();

		List<FailedServletContextDTO> copies = new ArrayList<FailedServletContextDTO>();

		for (FailedServletContextDTO failedServletContextDTO : fscDTOs) {
			copies.add(DTOUtil.clone(failedServletContextDTO));
		}

		return copies.toArray(new FailedServletContextDTO[0]);
	}

	private FailedServletDTO[] getFailedServletDTOs() {
		Collection<FailedServletDTO> fsDTOs = failedServletDTOs.values();

		List<FailedServletDTO> copies = new ArrayList<FailedServletDTO>();

		for (FailedServletDTO failedServletDTO : fsDTOs) {
			copies.add(DTOUtil.clone(failedServletDTO));
		}

		return copies.toArray(new FailedServletDTO[0]);
	}

	private FailedPreprocessorDTO[] getFailedPreprocessorDTOs() {
		Collection<FailedPreprocessorDTO> fpDTOs = failedPreprocessorDTOs.values();

		List<FailedPreprocessorDTO> copies = new ArrayList<FailedPreprocessorDTO>();

		for (FailedPreprocessorDTO failedPreprocessorDTO : fpDTOs) {
			copies.add(DTOUtil.clone(failedPreprocessorDTO));
		}

		return copies.toArray(new FailedPreprocessorDTO[0]);
	}

	public ServletContextDTO[] getServletContextDTOs() {
		List<ServletContextDTO> servletContextDTOs = new ArrayList<ServletContextDTO>();

		for (ContextController contextController : controllerMap.values()) {
			servletContextDTOs.add(contextController.getServletContextDTO());
		}

		return servletContextDTOs.toArray(new ServletContextDTO[0]);
	}

	public PreprocessorDTO[] getPreprocessorDTOs() {
		List<PreprocessorDTO> pDTOs = new ArrayList<PreprocessorDTO>();

		for (PreprocessorRegistration registration : preprocessorMap.values()) {
			pDTOs.add(registration.getD());
		}

		return pDTOs.toArray(new PreprocessorDTO[0]);
	}

	public Map<ServiceReference<Preprocessor>, PreprocessorRegistration> getPreprocessorRegistrations() {
		return preprocessorMap;
	}

	public void registerHttpServiceFilter(
		Bundle bundle, String alias, Filter filter, Dictionary<String, String> initparams, HttpContextHolder httpContextHolder) {

		if (alias == null) {
			throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$
		}
		if (filter == null) {
			throw new IllegalArgumentException("Filter cannot be null"); //$NON-NLS-1$
		}

		ContextController.checkPattern(alias);

		// need to make sure exact matching aliases are converted to wildcard pattern matches
		if (!alias.endsWith(Const.SLASH_STAR) && !alias.startsWith(Const.STAR_DOT) && !alias.contains(Const.SLASH_STAR_DOT)) {
			if (alias.endsWith(Const.SLASH)) {
				alias = alias + '*';
			} else {
				alias = alias + Const.SLASH_STAR;
			}
		}

		synchronized (legacyMappings) {
			if (getRegisteredObjects().contains(filter)) {
				throw new RegisteredFilterException(filter);
			}
			HttpServiceObjectRegistration existing = legacyMappings.get(filter);
			if (existing != null) {
				throw new RegisteredFilterException(filter);
			}
			String filterName = filter.getClass().getName();
			if ((initparams != null) && (initparams.get(Const.FILTER_NAME) != null)) {
				filterName = initparams.get(Const.FILTER_NAME);
			}

			HttpServiceObjectRegistration objectRegistration = null;
			ServiceRegistration<Filter> registration = null;
			try {
				Dictionary<String, Object> props = new Hashtable<String, Object>();
				props.put(HTTP_WHITEBOARD_TARGET, targetFilter);
				props.put(HTTP_WHITEBOARD_FILTER_PATTERN, alias);
				props.put(HTTP_WHITEBOARD_FILTER_NAME, filterName);
				props.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(httpContextHolder.getServiceReference()));
				props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader());
				props.put(Constants.SERVICE_RANKING, findFilterPriority(initparams));
				fillInitParams(props, initparams, HTTP_WHITEBOARD_FILTER_INIT_PARAM_PREFIX);

				LegacyFilterFactory filterFactory = new LegacyFilterFactory(filter);

				registration = bundle.getBundleContext().registerService(Filter.class, filterFactory, props);

				// check that init got called and did not throw an exception
				filterFactory.checkForError();
				httpContextHolder.incrementUseCount();

				objectRegistration = new HttpServiceObjectRegistration(filter, registration, httpContextHolder, bundle);
				Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle);
				if (objectRegistrations == null) {
					objectRegistrations = new HashSet<HttpServiceObjectRegistration>();
					bundleRegistrations.put(bundle, objectRegistrations);
				}
				objectRegistrations.add(objectRegistration);
				legacyMappings.put(objectRegistration.serviceKey, objectRegistration);
			} finally {
				if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) {
					// something bad happened above (likely going to throw a runtime exception)
					decrementFactoryUseCount(httpContextHolder);
					if (registration != null) {
						registration.unregister();
					}
				}
			}
		}
	}

	private void fillInitParams(
		Dictionary<String, Object> props,
		Dictionary<?, ?> initparams, String prefix) {
		if (initparams != null) {
			for (Enumeration<?> eKeys = initparams.keys(); eKeys.hasMoreElements();) {
				String key = String.valueOf(eKeys.nextElement());
				String value = String.valueOf(initparams.get(key));
				if (value != null) {
					props.put(prefix + key, value);
				}
			}
		}
	}

	private static int findFilterPriority(Dictionary<String, String> initparams) {
		if (initparams == null) {
			return 0;
		}

		String filterPriority = initparams.get(Const.FILTER_PRIORITY);

		if (filterPriority == null) {
			return 0;
		}

		try {
			int result = Integer.parseInt(filterPriority);
			if (result >= -1000 && result <= 1000) {
				return result;
			}
		}
		catch (NumberFormatException e) {
			// fall through
		}

		throw new IllegalArgumentException(
			"filter-priority must be an integer between -1000 and 1000 but " + //$NON-NLS-1$
				"was: " + filterPriority); //$NON-NLS-1$
	}

	public void registerHttpServiceResources(
		Bundle bundle, String alias, String name, HttpContextHolder httpContextHolder) throws NamespaceException {
		if (alias == null) {
			throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$
		}
		if (name == null) {
			throw new IllegalArgumentException("Name cannot be null"); //$NON-NLS-1$
		}
		String pattern = alias;
		if (pattern.startsWith(Const.SLASH_STAR_DOT)) {
			pattern = pattern.substring(1);
		}
		// need to make sure exact matching aliases are converted to wildcard pattern matches
		if (!pattern.endsWith(Const.SLASH_STAR) && !pattern.startsWith(Const.STAR_DOT) && !pattern.contains(Const.SLASH_STAR_DOT)) {
			if (pattern.endsWith(Const.SLASH)) {
				pattern = pattern + '*';
			} else {
				pattern = pattern + Const.SLASH_STAR;
			}
		}
		// check the pattern against the original input
		ContextController.checkPattern(alias);

		synchronized (legacyMappings) {
			HttpServiceObjectRegistration objectRegistration = null;
			ServiceRegistration<?> registration = null;
			try {
				String fullAlias = getFullAlias(alias, httpContextHolder);
				HttpServiceObjectRegistration existing = legacyMappings.get(fullAlias);
				if (existing != null) {
					throw new PatternInUseException(alias);
				}
				Dictionary<String, Object> props = new Hashtable<String, Object>();
				props.put(HTTP_WHITEBOARD_TARGET, targetFilter);
				props.put(HTTP_WHITEBOARD_RESOURCE_PATTERN, pattern);
				props.put(HTTP_WHITEBOARD_RESOURCE_PREFIX, name);
				props.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(httpContextHolder.getServiceReference()));
				props.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
				props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader());
				registration = bundle.getBundleContext().registerService(String.class, "resource", props); //$NON-NLS-1$
				httpContextHolder.incrementUseCount();

				objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, httpContextHolder, bundle);

				Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle);
				if (objectRegistrations == null) {
					objectRegistrations = new HashSet<HttpServiceObjectRegistration>();
					bundleRegistrations.put(bundle, objectRegistrations);
				}
				objectRegistrations.add(objectRegistration);

				Map<String, String> aliasCustomizations = bundleAliasCustomizations.get(bundle);
				if (aliasCustomizations == null) {
					aliasCustomizations = new HashMap<String, String>();
					bundleAliasCustomizations.put(bundle, aliasCustomizations);
				}
				aliasCustomizations.put(alias, fullAlias);
				legacyMappings.put(objectRegistration.serviceKey, objectRegistration);
			} finally {
				if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) {
					// something bad happened above (likely going to throw a runtime exception)
					// need to clean up the factory reference
					decrementFactoryUseCount(httpContextHolder);
					if (registration != null) {
						registration.unregister();
					}
				}
			}
		}
	}

	private Object getFilter(ServiceReference<? extends ServletContextHelper> serviceReference) {
		String ctxName = (String)serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_NAME);
		return String.format("(&(%s=%s)(%s=%s))", HTTP_SERVICE_CONTEXT_PROPERTY, ctxName, HTTP_WHITEBOARD_CONTEXT_NAME, ctxName); //$NON-NLS-1$
	}

	public void registerHttpServiceServlet(
		Bundle bundle, String alias, Servlet servlet, Dictionary<?, ?> initparams, HttpContextHolder httpContextHolder) throws NamespaceException, ServletException{
		if (alias == null) {
			throw new IllegalArgumentException("Alias cannot be null"); //$NON-NLS-1$
		}
		if (servlet == null) {
			throw new IllegalArgumentException("Servlet cannot be null"); //$NON-NLS-1$
		}

		// check the pattern against the original input
		ContextController.checkPattern(alias);

		Object pattern = alias;
		// need to make sure exact matching aliases are converted to exact matching + wildcard pattern matching
		if (!alias.endsWith(Const.SLASH_STAR) && !alias.startsWith(Const.STAR_DOT) && !alias.contains(Const.SLASH_STAR_DOT)) {
			if (alias.endsWith(Const.SLASH)) {
				pattern = new String[] {alias, alias + '*'};
			} else {
				pattern = new String[] {alias, alias + Const.SLASH_STAR};
			}
		}

		synchronized (legacyMappings) {
			LegacyServlet legacyServlet = new LegacyServlet(servlet);
			if (getRegisteredObjects().contains(legacyServlet)) {
				throw new ServletAlreadyRegisteredException(servlet);
			}
			HttpServiceObjectRegistration objectRegistration = null;
			ServiceRegistration<Servlet> registration = null;
			try {
				String fullAlias = getFullAlias(alias, httpContextHolder);
				HttpServiceObjectRegistration existing = legacyMappings.get(fullAlias);
				if (existing != null) {
					throw new PatternInUseException(alias);
				}
				String servletName = servlet.getClass().getName();
				if ((initparams != null) && (initparams.get(Const.SERVLET_NAME) != null)) {
					servletName = String.valueOf(initparams.get(Const.SERVLET_NAME));
				}

				Dictionary<String, Object> props = new Hashtable<String, Object>();
				props.put(HTTP_WHITEBOARD_TARGET, targetFilter);
				props.put(HTTP_WHITEBOARD_SERVLET_PATTERN, pattern);
				props.put(HTTP_WHITEBOARD_SERVLET_NAME, servletName);
				props.put(HTTP_WHITEBOARD_CONTEXT_SELECT, getFilter(httpContextHolder.getServiceReference()));
				props.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
				props.put(Const.EQUINOX_LEGACY_TCCL_PROP, Thread.currentThread().getContextClassLoader());
				fillInitParams(props, initparams, HTTP_WHITEBOARD_SERVLET_INIT_PARAM_PREFIX);

				registration = bundle.getBundleContext().registerService(Servlet.class, legacyServlet, props);

				// check that init got called and did not throw an exception
				legacyServlet.checkForError();
				httpContextHolder.incrementUseCount();

				objectRegistration = new HttpServiceObjectRegistration(fullAlias, registration, httpContextHolder, bundle);

				Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle);
				if (objectRegistrations == null) {
					objectRegistrations = new HashSet<HttpServiceObjectRegistration>();
					bundleRegistrations.put(bundle, objectRegistrations);
				}
				objectRegistrations.add(objectRegistration);

				Map<String, String> aliasCustomizations = bundleAliasCustomizations.get(bundle);
				if (aliasCustomizations == null) {
					aliasCustomizations = new HashMap<String, String>();
					bundleAliasCustomizations.put(bundle, aliasCustomizations);
				}
				aliasCustomizations.put(alias, fullAlias);

				legacyMappings.put(objectRegistration.serviceKey, objectRegistration);
			} finally {
				if (objectRegistration == null || !legacyMappings.containsKey(objectRegistration.serviceKey)) {
					// something bad happened above (likely going to throw a runtime exception)
					// need to clean up the factory reference
					decrementFactoryUseCount(httpContextHolder);
					if (registration != null) {
						registration.unregister();
					}
				}
			}
		}
	}

	private String getFullAlias(String alias, HttpContextHolder httpContextHolder) {
		@SuppressWarnings("unchecked")
		AtomicReference<ContextController> controllerRef = contextServiceTracker.getService((ServiceReference<ServletContextHelper>)httpContextHolder.getServiceReference());
		if (controllerRef != null) {
			ContextController controller = controllerRef.get();
			if (controller != null) {
				return controller.getContextPath() + alias;
			}
		}
		return alias;
	}

	public void unregisterHttpServiceAlias(Bundle bundle, String alias) {
		synchronized (legacyMappings) {
			Map<String, String> aliasCustomizations = bundleAliasCustomizations.get(bundle);
			String aliasCustomization = aliasCustomizations == null ? null : aliasCustomizations.remove(alias);
			if (aliasCustomization == null) {
				throw new IllegalArgumentException("The bundle did not register the alias: " + alias); //$NON-NLS-1$
			}
			HttpServiceObjectRegistration objectRegistration = legacyMappings.get(aliasCustomization);
			if (objectRegistration == null) {
				throw new IllegalArgumentException("No registration found for alias: " + alias); //$NON-NLS-1$
			}
			Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle);
			if (objectRegistrations == null || !objectRegistrations.remove(objectRegistration))
			{
				throw new IllegalArgumentException("The bundle did not register the alias: " + alias); //$NON-NLS-1$
			}

			try {
				objectRegistration.registration.unregister();
			} catch (IllegalStateException e) {
				// ignore; already unregistered
			}
			decrementFactoryUseCount(objectRegistration.httpContextHolder);
			legacyMappings.remove(aliasCustomization);

		}
	}

	public void unregisterHttpServiceFilter(Bundle bundle, Filter filter) {
		synchronized (legacyMappings) {
			HttpServiceObjectRegistration objectRegistration = legacyMappings.get(filter);
			if (objectRegistration == null) {
				throw new IllegalArgumentException("No registration found for filter: " + filter); //$NON-NLS-1$
			}
			Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.get(bundle);
			if (objectRegistrations == null || !objectRegistrations.remove(objectRegistration))
			{
				throw new IllegalArgumentException("The bundle did not register the filter: " + filter); //$NON-NLS-1$
			}
			try {
				objectRegistration.registration.unregister();
			} catch (IllegalStateException e) {
				// ignore; already unregistered
			}
			decrementFactoryUseCount(objectRegistration.httpContextHolder);
			legacyMappings.remove(filter);
		}
	}

	public void unregisterHttpServiceObjects(Bundle bundle) {
		synchronized (legacyMappings) {
			bundleAliasCustomizations.remove(bundle);
			Set<HttpServiceObjectRegistration> objectRegistrations = bundleRegistrations.remove(bundle);
			if (objectRegistrations != null) {
				for (HttpServiceObjectRegistration objectRegistration : objectRegistrations) {
					try {
						objectRegistration.registration.unregister();
					} catch (IllegalStateException e) {
						// ignore; already unregistered
					}
					decrementFactoryUseCount(objectRegistration.httpContextHolder);
					legacyMappings.remove(objectRegistration.serviceKey);
				}
			}
		}
	}

	private void decrementFactoryUseCount(HttpContextHolder holder) {
		synchronized (legacyContextMap) {
			if (holder.decrementUseCount() == 0) {
				legacyContextMap.remove(holder.getHttpContext());
			}
		}
	}

	private static org.osgi.framework.Filter createErrorPageFilter(BundleContext context) {
		StringBuilder sb = new StringBuilder();

		sb.append("("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_SERVLET_ERROR_PAGE);
		sb.append("=*)"); //$NON-NLS-1$

		try {
			return context.createFilter(sb.toString());
		}
		catch (InvalidSyntaxException ise) {
			throw new IllegalArgumentException(ise);
		}
	}

	private static org.osgi.framework.Filter createResourceFilter(BundleContext context) {
		StringBuilder sb = new StringBuilder();

		sb.append("(&("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_RESOURCE_PREFIX);
		sb.append("=*)("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_RESOURCE_PATTERN);
		sb.append("=*))"); //$NON-NLS-1$

		try {
			return context.createFilter(sb.toString());
		}
		catch (InvalidSyntaxException ise) {
			throw new IllegalArgumentException(ise);
		}
	}

	private static org.osgi.framework.Filter createServletFilter(BundleContext context) {
		StringBuilder sb = new StringBuilder();

		sb.append("(&(objectClass="); //$NON-NLS-1$
		sb.append(Servlet.class.getName());
		sb.append(")(|("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_SERVLET_NAME);
		sb.append("=*)("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_SERVLET_PATTERN);
		sb.append("=*)))"); //$NON-NLS-1$

		try {
			return context.createFilter(sb.toString());
		}
		catch (InvalidSyntaxException ise) {
			throw new IllegalArgumentException(ise);
		}
	}

	private static org.osgi.framework.Filter createFilterFilter(BundleContext context) {
		StringBuilder sb = new StringBuilder();

		sb.append("(&(objectClass="); //$NON-NLS-1$
		sb.append(Filter.class.getName());
		sb.append(")(|("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_FILTER_PATTERN);
		sb.append("=*)("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_FILTER_REGEX);
		sb.append("=*)("); //$NON-NLS-1$
		sb.append(HTTP_WHITEBOARD_FILTER_SERVLET);
		sb.append("=*)))"); //$NON-NLS-1$

		try {
			return context.createFilter(sb.toString());
		}
		catch (InvalidSyntaxException ise) {
			throw new IllegalArgumentException(ise);
		}
	}

	private static org.osgi.framework.Filter createListenerFilter(BundleContext context) {
		StringBuilder sb = new StringBuilder();

		sb.append("(&"); //$NON-NLS-1$
		sb.append("(").append(HTTP_WHITEBOARD_LISTENER).append("=*)"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(|"); //$NON-NLS-1$
		sb.append("(objectClass=").append(ServletContextListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(objectClass=").append(ServletContextAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(objectClass=").append(ServletRequestListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(objectClass=").append(ServletRequestAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(objectClass=").append(HttpSessionListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(objectClass=").append(HttpSessionAttributeListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append("(objectClass=").append(HttpSessionIdListener.class.getName()).append(")"); //$NON-NLS-1$ //$NON-NLS-2$
		sb.append(")"); //$NON-NLS-1$
		sb.append(")"); //$NON-NLS-1$

		try {
			return context.createFilter(sb.toString());
		}
		catch (InvalidSyntaxException ise) {
			throw new IllegalArgumentException(ise);
		}
	}

	public org.osgi.framework.Filter getListenerFilter() {
		return listenerServiceFilter;
	}

	public org.osgi.framework.Filter getErrorPageFilter() {
		return errorPageServiceFilter;
	}

	public org.osgi.framework.Filter getFilterFilter() {
		return filterServiceFilter;
	}

	public org.osgi.framework.Filter getServletFilter() {
		return servletServiceFilter;
	}

	public org.osgi.framework.Filter getResourceFilter() {
		return resourceServiceFilter;
	}

	public void recordFailedErrorPageDTO(
		ServiceReference<?> serviceReference,
		FailedErrorPageDTO failedErrorPageDTO) {

		if (failedErrorPageDTOs.containsKey(serviceReference)) {
			return;
		}

		failedErrorPageDTOs.put(serviceReference, failedErrorPageDTO);
	}

	public void recordFailedFilterDTO(
		ServiceReference<Filter> serviceReference,
		FailedFilterDTO failedFilterDTO) {

		if (failedFilterDTOs.containsKey(serviceReference)) {
			return;
		}

		failedFilterDTOs.put(serviceReference, failedFilterDTO);
	}

	public void recordFailedListenerDTO(
		ServiceReference<EventListener> serviceReference,
		FailedListenerDTO failedListenerDTO) {

		if (failedListenerDTOs.containsKey(serviceReference)) {
			return;
		}

		failedListenerDTOs.put(serviceReference, failedListenerDTO);
	}

	public void recordFailedResourceDTO(
		ServiceReference<?> serviceReference, FailedResourceDTO failedResourceDTO) {

		if (failedResourceDTOs.containsKey(serviceReference)) {
			return;
		}

		failedResourceDTOs.put(serviceReference, failedResourceDTO);
	}

	public void recordFailedServletContextDTO(
		ServiceReference<ServletContextHelper> serviceReference, long shadowingServiceId, int failureReason) {

		ExtendedFailedServletContextDTO failedServletContextDTO = new ExtendedFailedServletContextDTO();

		failedServletContextDTO.attributes = Collections.emptyMap();
		failedServletContextDTO.contextPath = String.valueOf(serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_PATH));
		failedServletContextDTO.errorPageDTOs = new ExtendedErrorPageDTO[0];
		failedServletContextDTO.failureReason = failureReason;
		failedServletContextDTO.filterDTOs = new FilterDTO[0];
		failedServletContextDTO.initParams = ServiceProperties.parseInitParams(
			serviceReference, HTTP_WHITEBOARD_CONTEXT_INIT_PARAM_PREFIX);
		failedServletContextDTO.listenerDTOs = new ListenerDTO[0];
		failedServletContextDTO.name = String.valueOf(serviceReference.getProperty(HTTP_WHITEBOARD_CONTEXT_NAME));
		failedServletContextDTO.resourceDTOs = new ResourceDTO[0];
		failedServletContextDTO.serviceId = (Long)serviceReference.getProperty(Constants.SERVICE_ID);
		failedServletContextDTO.servletDTOs = new ServletDTO[0];
		failedServletContextDTO.shadowingServiceId = shadowingServiceId;

		failedServletContextDTOs.put(serviceReference, failedServletContextDTO);
	}

	public void recordFailedServletDTO(
		ServiceReference<?> serviceReference,
		FailedServletDTO failedServletDTO) {

		if (failedServletDTOs.containsKey(serviceReference)) {
			return;
		}

		failedServletDTOs.put(serviceReference, failedServletDTO);
	}

	public void recordFailedPreprocessorDTO(
		ServiceReference<Preprocessor> serviceReference,
		FailedPreprocessorDTO failedPreprocessorDTO) {

		if (failedPreprocessorDTOs.containsKey(serviceReference)) {
			return;
		}

		failedPreprocessorDTOs.put(serviceReference, failedPreprocessorDTO);
	}

	public void removeFailedErrorPageDTO(
		ServiceReference<Servlet> serviceReference) {

		failedErrorPageDTOs.remove(serviceReference);
	}

	public void removeFailedFilterDTO(
		ServiceReference<Filter> serviceReference) {

		failedFilterDTOs.remove(serviceReference);
	}

	public void removeFailedListenerDTO(
		ServiceReference<EventListener> serviceReference) {

		failedListenerDTOs.remove(serviceReference);
	}

	public void removeFailedResourceDTO(
		ServiceReference<Object> serviceReference) {

		failedResourceDTOs.remove(serviceReference);
	}

	public void removeFailedServletDTO(
		ServiceReference<Servlet> serviceReference) {

		failedServletDTOs.remove(serviceReference);
	}

	public void removeFailedPreprocessorDTO(
		ServiceReference<Preprocessor> serviceReference) {

		failedPreprocessorDTOs.remove(serviceReference);
	}

	public synchronized void fireSessionIdChanged(String oldSessionId) {
		for (ContextController contextController : controllerMap.values()) {
			contextController.fireSessionIdChanged(oldSessionId);
		}
	}

	public void sessionDestroyed(String sessionId) {
		httpSessionTracker.invalidate(sessionId, false);
	}

	public void setHsrRegistration(ServiceRegistration<HttpServiceRuntime> hsrRegistration) {
		this.hsrRegistration.set(hsrRegistration);
	}

	ServiceRegistration<HttpServiceRuntime> getHsrRegistration() {
		return hsrRegistration.get();
	}

	long getServiceChangecount() {
		return serviceChangecount.get();
	}

	public void incrementServiceChangecount() {
		serviceChangecount.incrementAndGet();
		if (hsrRegistration.get() != null && !scheduledExecutor.isShutdown() && semaphore.tryAcquire()) {
			scheduledExecutor.schedule(new ChangeCountTimer(), 100, TimeUnit.MILLISECONDS);
		}
	}

	Semaphore getSemaphore() {
		return semaphore;
	}

	private final Map<String, Object> attributes;
	private final String targetFilter;
	final ServiceRegistration<DefaultServletContextHelper> defaultContextReg;
	private final ServletContext parentServletContext;
	private final BundleContext trackingContext;
	private final BundleContext consumingContext;
	private final org.osgi.framework.Filter errorPageServiceFilter;
	private final org.osgi.framework.Filter servletServiceFilter;
	private final org.osgi.framework.Filter resourceServiceFilter;
	private final org.osgi.framework.Filter filterServiceFilter;
	private final org.osgi.framework.Filter listenerServiceFilter;

	// BEGIN of old HttpService support
	final ConcurrentMap<HttpContext, HttpContextHolder> legacyContextMap =
		new ConcurrentHashMap<HttpContext, HttpContextHolder>();
	private final Map<Object, HttpServiceObjectRegistration> legacyMappings =
		Collections.synchronizedMap(new HashMap<Object, HttpServiceObjectRegistration>());
	private final Map<Bundle, Set<HttpServiceObjectRegistration>> bundleRegistrations =
		new HashMap<Bundle, Set<HttpServiceObjectRegistration>>();
	private final Map<Bundle, Map<String, String>> bundleAliasCustomizations = new HashMap<Bundle, Map<String,String>>();
	// END of old HttpService support

	private final ConcurrentMap<ServiceReference<ServletContextHelper>, ContextController> controllerMap =
		new ConcurrentSkipListMap<ServiceReference<ServletContextHelper>, ContextController>(Collections.reverseOrder());
	private final ConcurrentMap<ServiceReference<Preprocessor>, PreprocessorRegistration> preprocessorMap =
		new ConcurrentSkipListMap<ServiceReference<Preprocessor>, PreprocessorRegistration>(Collections.reverseOrder());

	final ConcurrentMap<ServiceReference<?>, FailedErrorPageDTO> failedErrorPageDTOs =
		new ConcurrentHashMap<ServiceReference<?>, FailedErrorPageDTO>();
	final ConcurrentMap<ServiceReference<Filter>, FailedFilterDTO> failedFilterDTOs =
		new ConcurrentHashMap<ServiceReference<Filter>, FailedFilterDTO>();
	final ConcurrentMap<ServiceReference<EventListener>, FailedListenerDTO> failedListenerDTOs =
		new ConcurrentHashMap<ServiceReference<EventListener>, FailedListenerDTO>();
	final ConcurrentMap<ServiceReference<?>, FailedResourceDTO> failedResourceDTOs =
		new ConcurrentHashMap<ServiceReference<?>, FailedResourceDTO>();
	final ConcurrentMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO> failedServletContextDTOs =
		new ConcurrentHashMap<ServiceReference<ServletContextHelper>, ExtendedFailedServletContextDTO>();
	final ConcurrentMap<ServiceReference<?>, FailedServletDTO> failedServletDTOs =
		new ConcurrentHashMap<ServiceReference<?>, FailedServletDTO>();
	final ConcurrentMap<ServiceReference<?>, FailedPreprocessorDTO> failedPreprocessorDTOs =
		new ConcurrentHashMap<ServiceReference<?>, FailedPreprocessorDTO>();

	private final Set<Object> registeredObjects = Collections.newSetFromMap(new ConcurrentHashMap<Object, Boolean>());
	private final ServiceTracker<LoggerFactory, Logger> loggerFactoryTracker;
	private final ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker;
	private final ServiceTracker<Preprocessor, AtomicReference<PreprocessorRegistration>> preprocessorServiceTracker;
	private final ServiceTracker<ContextPathCustomizer, ContextPathCustomizer> contextPathAdaptorTracker;
	private final ContextPathCustomizerHolder contextPathCustomizerHolder;
	private final HttpSessionTracker httpSessionTracker;
	private final ServiceRegistration<HttpSessionInvalidator> invalidatorReg;
	private final AtomicReference<ServiceRegistration<HttpServiceRuntime>> hsrRegistration = new AtomicReference<>();

	private final AtomicLong serviceChangecount = new AtomicLong();
	private final ScheduledExecutorService scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
	private final Semaphore semaphore = new Semaphore(1);

	class ChangeCountTimer implements Callable<Void> {
		@Override
		public Void call() {
			try {
				Dictionary<String,Object> properties = getHsrRegistration().getReference().getProperties();
				properties.put(Constants.SERVICE_CHANGECOUNT, getServiceChangecount());
				getHsrRegistration().setProperties(properties);
				return null;
			}
			finally {
				getSemaphore().release();
			}
		}
	}

	static class LegacyServiceObject {
		final AtomicReference<Exception> error = new AtomicReference<Exception>(new ServletException("The init() method was never called.")); //$NON-NLS-1$
		public void checkForError() {
			Exception result = error.get();
			if (result != null) {
				Throw.unchecked(result);
			}
		}
	}

	public static class LegacyFilterFactory extends LegacyServiceObject implements PrototypeServiceFactory<Filter> {
		final Filter filter;

		public LegacyFilterFactory(Filter filter) {
			this.filter = filter;
		}

		@Override
		public Filter getService(Bundle bundle, ServiceRegistration<Filter> registration) {
			return new LegacyFilter();
		}

		@Override
		public void ungetService(
			Bundle bundle, ServiceRegistration<Filter> registration, Filter service) {
			// do nothing
		}

		// NOTE we do not do the same equals check here for filter that we do for servlet
		// this is because we must allow filter to be applied to all context helpers
		// TODO this means it is still possible that init() will get called if the same filter
		// is registered multiple times.  This is unfortunate but is an error case on the client anyway.
		class LegacyFilter implements Filter {
			/**
			 * @throws ServletException
			 */
			@Override
			public void init(FilterConfig filterConfig) throws ServletException {
				try {
					filter.init(filterConfig);
					error.set(null);
				} catch (Exception e){
					error.set(e);
					Throw.unchecked(e);
				}
			}

			@Override
			public void doFilter(
				ServletRequest request, ServletResponse response, FilterChain chain)
				throws IOException, ServletException {
				filter.doFilter(request, response, chain);
			}

			@Override
			public void destroy() {
				filter.destroy();
			}
		}
	}

	static class LegacyServlet extends LegacyServiceObject implements Servlet {
		final Servlet servlet;

		public LegacyServlet(Servlet servlet) {
			this.servlet = servlet;
		}

		/**
		 * @throws ServletException
		 */
		@Override
		public void init(ServletConfig config)
			throws ServletException {
			try {
				servlet.init(config);
				error.set(null);
			} catch (Exception e){
				error.set(e);
				Throw.unchecked(e);
			}
		}

		@Override
		public ServletConfig getServletConfig() {
			return servlet.getServletConfig();
		}

		@Override
		public void
			service(ServletRequest req, ServletResponse res)
				throws ServletException, IOException {
			servlet.service(req, res);
		}

		@Override
		public String getServletInfo() {
			return servlet.getServletInfo();
		}

		@Override
		public void destroy() {
			servlet.destroy();
		}

		@Override
		public int hashCode() {
			return servlet.hashCode();
		}

		@Override
		public boolean equals(Object other) {
			if (other instanceof LegacyServlet) {
				other = ((LegacyServlet) other).servlet;
			}
			return servlet.equals(other);
		}
	}

	static class ContextPathCustomizerHolder implements ServiceTrackerCustomizer<ContextPathCustomizer, ContextPathCustomizer> {
		private final BundleContext context;
		private final ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker;
		private final NavigableMap<ServiceReference<ContextPathCustomizer>, ContextPathCustomizer> pathCustomizers =
			new TreeMap<ServiceReference<ContextPathCustomizer>, ContextPathCustomizer>(Collections.reverseOrder());

		public ContextPathCustomizerHolder(
			BundleContext context,
			ServiceTracker<ServletContextHelper, AtomicReference<ContextController>> contextServiceTracker) {
			super();
			this.context = context;
			this.contextServiceTracker = contextServiceTracker;
		}

		@Override
		public ContextPathCustomizer addingService(
			ServiceReference<ContextPathCustomizer> reference) {
			ContextPathCustomizer service = context.getService(reference);
			boolean reset = false;
			synchronized (pathCustomizers) {
				pathCustomizers.put(reference, service);
				reset = pathCustomizers.firstKey().equals(reference);
			}
			if (reset) {
				contextServiceTracker.close();
				contextServiceTracker.open();
			}
			return service;
		}

		@Override
		public void modifiedService(
			ServiceReference<ContextPathCustomizer> reference,
			ContextPathCustomizer service) {
			removedService(reference, service);
			addingService(reference);
		}
		@Override
		public void removedService(
			ServiceReference<ContextPathCustomizer> reference,
			ContextPathCustomizer service) {
			boolean reset = false;
			synchronized (pathCustomizers) {
				ServiceReference<ContextPathCustomizer> currentFirst = pathCustomizers.firstKey();
				pathCustomizers.remove(reference);
				reset = currentFirst.equals(reference);
			}

			// only reset if the tracker is still open
			if (reset && contextServiceTracker.getTrackingCount() >= 0) {

				contextServiceTracker.close();
				contextServiceTracker.open();
			}
			context.ungetService(reference);
		}

		ContextPathCustomizer getHighestRanked() {
			synchronized (pathCustomizers) {
				Map.Entry<ServiceReference<ContextPathCustomizer>, ContextPathCustomizer> firstEntry = pathCustomizers.firstEntry();
				return firstEntry == null ? null : firstEntry.getValue();
			}
		}
	}

}
