blob: 90c8b5cc67c83283688a22005f7da17940a737c0 [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.servlet.DispatcherType;
import org.apache.felix.http.base.internal.HttpConfig;
import org.apache.felix.http.base.internal.handler.FilterHandler;
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.runtime.FilterInfo;
import org.apache.felix.http.base.internal.runtime.ListenerInfo;
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.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
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();
private final HttpConfig config;
/**
* Default http service registry
*/
public PerContextHandlerRegistry(@NotNull final HttpConfig config)
{
this.config = config;
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(@NotNull final ServletContextHelperInfo info, @NotNull final HttpConfig config)
{
this.config = config;
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 HttpConfig getConfig()
{
return this.config;
}
public void removeAll()
{
this.errorPageRegistry.cleanup();
this.eventListenerRegistry.cleanup();
this.filterRegistry.cleanup();
this.servletRegistry.cleanup();
}
@Override
public int compareTo(@NotNull final PerContextHandlerRegistry other)
{
final int result = new Integer(other.path.length()).compareTo(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 * new Long(this.serviceId).compareTo(other.serviceId);
}
return new Integer(other.ranking).compareTo(this.ranking);
}
return result;
}
public String isMatching(@NotNull 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(@NotNull final String relativeRequestURI)
{
return this.servletRegistry.resolve(relativeRequestURI);
}
public ServletHandler resolveServletByName(final String name)
{
return this.servletRegistry.resolveByName(name);
}
/**
* Get filter handlers for the request uri
* @param servletHandler The servlet handler (might be null)
* @param dispatcherType The dispatcher type
* @param requestURI The request uri
* @return The array of filter handlers, the array might be empty.
*/
public @NotNull FilterHandler[] getFilterHandlers(@Nullable final ServletHandler servletHandler,
@NotNull final DispatcherType dispatcherType,
@NotNull final String requestURI)
{
return this.filterRegistry.getFilterHandlers(servletHandler, dispatcherType, requestURI);
}
/**
* Get the servlet handling the error.
* @param code The error code
* @param exception The optional exception
* @return The servlet handler or {@code null}.
*/
public @Nullable ServletHandler getErrorHandler(final int code, @Nullable final 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 servlet
* @param handler The servlet handler
*/
public void registerServlet(@NotNull final ServletHandler handler)
{
this.servletRegistry.addServlet(handler);
this.errorPageRegistry.addServlet(handler);
}
/**
* Remove a servlet
* @param servletInfo The servlet info
* @param destroy Destroy the servlet
*/
public void unregisterServlet(@NotNull final ServletInfo servletInfo, final boolean destroy)
{
this.servletRegistry.removeServlet(servletInfo, destroy);
this.errorPageRegistry.removeServlet(servletInfo, destroy);
}
/**
* Add a filter
* @param handler The filter handler
*/
public void registerFilter(@NotNull final FilterHandler handler)
{
this.filterRegistry.addFilter(handler);
}
/**
* Remove a filter
* @param info The filter info
* @param destroy Destroy the filter
*/
public void unregisterFilter(@NotNull final FilterInfo info, final boolean destroy)
{
this.filterRegistry.removeFilter(info, destroy);
}
/**
* Register listeners
* @param listenerHandler
*/
public void registerListeners(@NotNull final ListenerHandler listenerHandler)
{
this.eventListenerRegistry.addListeners(listenerHandler);
}
/**
* Unregister listeners
*
* @param info The listener info
*/
public void unregisterListeners(@NotNull final ListenerInfo info)
{
this.eventListenerRegistry.removeListeners(info);
}
}