blob: cf9d6241ac30c63364ba5ce9168658d8333c5970 [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.felix.http.base.internal.registry;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.servlet.DispatcherType;
import org.apache.felix.http.base.internal.context.ExtServletContext;
import org.apache.felix.http.base.internal.handler.FilterHandler;
import org.apache.felix.http.base.internal.handler.HttpServiceServletHandler;
import org.apache.felix.http.base.internal.handler.ListenerHandler;
import org.apache.felix.http.base.internal.handler.ServletHandler;
import org.apache.felix.http.base.internal.handler.WhiteboardFilterHandler;
import org.apache.felix.http.base.internal.handler.WhiteboardListenerHandler;
import org.apache.felix.http.base.internal.handler.WhiteboardServletHandler;
import org.apache.felix.http.base.internal.runtime.FilterInfo;
import org.apache.felix.http.base.internal.runtime.ListenerInfo;
import org.apache.felix.http.base.internal.runtime.ResourceInfo;
import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
import org.apache.felix.http.base.internal.runtime.ServletInfo;
import org.apache.felix.http.base.internal.runtime.dto.FailedDTOHolder;
import org.apache.felix.http.base.internal.service.HttpServiceFactory;
import org.apache.felix.http.base.internal.service.ResourceServlet;
import org.apache.felix.http.base.internal.whiteboard.ContextHandler;
import org.osgi.service.http.runtime.dto.DTOConstants;
import org.osgi.service.http.runtime.dto.ServletContextDTO;
/**
* This registry keeps track of all processing components per context:
* - servlets
* - filters
* - error pages
*/
public final class PerContextHandlerRegistry implements Comparable<PerContextHandlerRegistry>
{
/** Service id of the context. */
private final long serviceId;
/** Ranking of the context. */
private final int ranking;
/** The context path. */
private final String path;
/** The context prefix. */
private final String prefix;
private final ServletRegistry servletRegistry = new ServletRegistry();
private final FilterRegistry filterRegistry = new FilterRegistry();
private final ErrorPageRegistry errorPageRegistry = new ErrorPageRegistry();
private final EventListenerRegistry eventListenerRegistry = new EventListenerRegistry();
/**
* Default http service registry
*/
public PerContextHandlerRegistry()
{
this.serviceId = HttpServiceFactory.HTTP_SERVICE_CONTEXT_SERVICE_ID;
this.ranking = Integer.MAX_VALUE;
this.path = "/";
this.prefix = null;
}
/**
* Registry for a servlet context helper (whiteboard support)
* @param info The servlet context helper info
*/
public PerContextHandlerRegistry(@Nonnull final ServletContextHelperInfo info)
{
this.serviceId = info.getServiceId();
this.ranking = info.getRanking();
this.path = info.getPath();
if ( this.path.equals("/") )
{
this.prefix = null;
}
else
{
this.prefix = this.path + "/";
}
}
public long getContextServiceId()
{
return this.serviceId;
}
public void removeAll()
{
this.errorPageRegistry.cleanup();
this.eventListenerRegistry.cleanup();
this.filterRegistry.cleanup();
this.servletRegistry.cleanup();
}
@Override
public int compareTo(@Nonnull final PerContextHandlerRegistry other)
{
final int result = Integer.compare(other.path.length(), this.path.length());
if ( result == 0 ) {
if (this.ranking == other.ranking)
{
// Service id's can be negative. Negative id's follow the reverse natural ordering of integers.
int reverseOrder = ( this.serviceId <= 0 && other.serviceId <= 0 ) ? -1 : 1;
return reverseOrder * Long.compare(this.serviceId, other.serviceId);
}
return Integer.compare(other.ranking, this.ranking);
}
return result;
}
public String isMatching(@Nonnull final String requestURI)
{
if (requestURI.equals(this.path))
{
return "";
}
if (this.prefix == null)
{
return requestURI;
}
if (requestURI.startsWith(this.prefix))
{
return requestURI.substring(this.prefix.length() - 1);
}
return null;
}
public PathResolution resolve(@Nonnull final String relativeRequestURI)
{
return this.servletRegistry.resolve(relativeRequestURI);
}
public ServletHandler resolveServletByName(final String name)
{
return this.servletRegistry.resolveByName(name);
}
/**
* Register a servlet.
* @param contextInfo The servlet context helper info
* @param servletInfo The servlet info
*/
public int registerServlet(@Nonnull final ContextHandler contextHandler,
@Nonnull final ServletInfo servletInfo)
{
final ExtServletContext context = contextHandler.getServletContext(servletInfo.getServiceReference().getBundle());
if ( context == null )
{
return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
}
final ServletHandler handler = new WhiteboardServletHandler(
contextHandler.getContextInfo().getServiceId(),
context,
servletInfo, contextHandler.getBundleContext());
this.servletRegistry.addServlet(handler);
this.errorPageRegistry.addServlet(handler);
return -1;
}
/**
* Unregister a servlet
* @param contextInfo The servlet context helper info
* @param servletInfo The servlet info
*/
public void unregisterServlet(@Nonnull final ContextHandler contextHandler, @Nonnull final ServletInfo servletInfo)
{
this.servletRegistry.removeServlet(servletInfo, true);
this.errorPageRegistry.removeServlet(servletInfo, true);
contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
}
/**
* Register a filter
* @param contextInfo The servlet context helper info
* @param filterInfo The filter info
*/
public int registerFilter(@Nonnull final ContextHandler contextHandler,
@Nonnull final FilterInfo filterInfo)
{
final ExtServletContext context = contextHandler.getServletContext(filterInfo.getServiceReference().getBundle());
if ( context == null )
{
return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
}
final FilterHandler handler = new WhiteboardFilterHandler(
contextHandler.getContextInfo().getServiceId(),
context,
filterInfo, contextHandler.getBundleContext());
this.filterRegistry.addFilter(handler);
return -1;
}
/**
* Unregister a filter
* @param contextInfo The servlet context helper info
* @param filterInfo The filter info
*/
public void unregisterFilter(@Nonnull final ContextHandler contextHandler, @Nonnull final FilterInfo filterInfo)
{
this.filterRegistry.removeFilter(filterInfo, true);
contextHandler.ungetServletContext(filterInfo.getServiceReference().getBundle());
}
/**
* Register listeners
*
* @param contextHandler The context handler
* @param info The listener info
* @return {@code -1} on successful registration, failure code otherwise
*/
public int registerListeners(@Nonnull final ContextHandler contextHandler,
@Nonnull final ListenerInfo info)
{
final ExtServletContext context = contextHandler.getServletContext(info.getServiceReference().getBundle());
if ( context == null )
{
return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
}
final ListenerHandler handler = new WhiteboardListenerHandler(
contextHandler.getContextInfo().getServiceId(),
context,
info,
contextHandler.getBundleContext());
this.eventListenerRegistry.addListeners(handler);
return -1;
}
/**
* Unregister listeners
*
* @param contextHandler The context handler
* @param info The listener info
*/
public void unregisterListeners(@Nonnull final ContextHandler contextHandler, @Nonnull final ListenerInfo info)
{
this.eventListenerRegistry.removeListeners(info);
contextHandler.ungetServletContext(info.getServiceReference().getBundle());
}
/**
* Register a resource.
* @param contextInfo The servlet context helper info
* @param resourceInfo The resource info
*/
public int registerResource(@Nonnull final ContextHandler contextHandler,
@Nonnull final ResourceInfo resourceInfo)
{
final ServletInfo servletInfo = new ServletInfo(resourceInfo);
final ExtServletContext context = contextHandler.getServletContext(servletInfo.getServiceReference().getBundle());
if ( context == null )
{
return DTOConstants.FAILURE_REASON_SERVLET_CONTEXT_FAILURE;
}
final ServletHandler handler = new HttpServiceServletHandler(
contextHandler.getContextInfo().getServiceId(),
context,
servletInfo, new ResourceServlet(resourceInfo.getPrefix()));
this.servletRegistry.addServlet(handler);
return -1;
}
/**
* Unregister a resource.
* @param contextInfo The servlet context helper info
* @param resourceInfo The resource info
*/
public void unregisterResource(@Nonnull final ContextHandler contextHandler, @Nonnull final ResourceInfo resourceInfo)
{
final ServletInfo servletInfo = new ServletInfo(resourceInfo);
this.servletRegistry.removeServlet(servletInfo, true);
contextHandler.ungetServletContext(servletInfo.getServiceReference().getBundle());
}
public FilterHandler[] getFilterHandlers(@CheckForNull final ServletHandler servletHandler,
@Nonnull final DispatcherType dispatcherType,
@Nonnull final String requestURI)
{
return this.filterRegistry.getFilterHandlers(servletHandler, dispatcherType, requestURI);
}
public ServletHandler getErrorHandler(int code, Throwable exception)
{
return this.errorPageRegistry.get(exception, code);
}
public EventListenerRegistry getEventListenerRegistry()
{
return this.eventListenerRegistry;
}
/**
* Create all DTOs for servlets, filters, resources and error pages
* @param dto The servlet context DTO
* @param failedDTOHolder The container for all failed DTOs
*/
public void getRuntime(final ServletContextDTO dto,
final FailedDTOHolder failedDTOHolder)
{
// collect filters
this.filterRegistry.getRuntimeInfo(dto, failedDTOHolder.failedFilterDTOs);
// collect error pages
this.errorPageRegistry.getRuntimeInfo(dto, failedDTOHolder.failedErrorPageDTOs);
// collect servlets and resources
this.servletRegistry.getRuntimeInfo(dto, failedDTOHolder.failedServletDTOs, failedDTOHolder.failedResourceDTOs);
// collect listeners
this.eventListenerRegistry.getRuntimeInfo(dto, failedDTOHolder.failedListenerDTOs);
}
/**
* Add a filter for the http service.
* @param handler The filter handler
*/
public void registerFilter(@Nonnull final FilterHandler handler) {
this.filterRegistry.addFilter(handler);
}
/**
* Add a servlet for the http service.
* @param handler The servlet handler
*/
public void registerServlet(@Nonnull final ServletHandler handler) {
this.servletRegistry.addServlet(handler);
this.errorPageRegistry.addServlet(handler);
}
/**
* Remove a servlet for the http service.
* @param servletInfo The servlet info
* @param destroy Destroy the servlet
*/
public void unregisterServlet(@Nonnull final ServletInfo servletInfo, final boolean destroy) {
this.servletRegistry.removeServlet(servletInfo, destroy);
this.errorPageRegistry.removeServlet(servletInfo, destroy);
}
/**
* Remove a filter for the http service.
* @param info The filter info
* @param destroy Destroy the filter
*/
public void unregisterFilter(@Nonnull final FilterInfo info, final boolean destroy) {
this.filterRegistry.removeFilter(info, destroy);
}
}