blob: 8e25b6e3fc1e6400bd097e226e16de121382773c [file] [log] [blame]
/*
* Licensed to the Apaanche 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 java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.servlet.DispatcherType;
import org.apache.felix.http.base.internal.handler.FilterHandler;
import org.apache.felix.http.base.internal.handler.ServletHandler;
import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
import org.apache.felix.http.base.internal.runtime.dto.FailedDTOHolder;
import org.osgi.service.http.runtime.dto.ServletContextDTO;
/**
* Registry for all services.
*
* The registry is organized per servlet context and is dispatching to one
* of the {@link PerContextHandlerRegistry} registries.
*/
public final class HandlerRegistry
{
private static FilterHandler[] EMPTY_FILTER_HANDLER = new FilterHandler[0];
/** Current list of context registrations. */
private volatile List<PerContextHandlerRegistry> registrations = Collections.emptyList();
/**
* Register default context registry for Http Service
*/
public void init()
{
this.add(new PerContextHandlerRegistry());
}
/**
* Reset to initial state
*/
public void reset()
{
this.registrations.clear();
this.init();
}
/**
* Shutdown
*/
public void shutdown()
{
final List<PerContextHandlerRegistry> list;
synchronized ( this )
{
list = new ArrayList<PerContextHandlerRegistry>(this.registrations);
this.registrations = Collections.emptyList();
}
for(final PerContextHandlerRegistry r : list)
{
r.removeAll();
}
}
/**
* Remove a context registration.
* @param info The servlet context helper info
*/
public void remove(@Nonnull ServletContextHelperInfo info)
{
synchronized ( this )
{
final List<PerContextHandlerRegistry> updatedList = new ArrayList<PerContextHandlerRegistry>(this.registrations);
final Iterator<PerContextHandlerRegistry> i = updatedList.iterator();
while ( i.hasNext() )
{
final PerContextHandlerRegistry reg = i.next();
if ( reg.getContextServiceId() == info.getServiceId() )
{
i.remove();
this.registrations = updatedList;
break;
}
}
}
}
/**
* Add a new context registration.
*/
public void add(@Nonnull PerContextHandlerRegistry registry)
{
synchronized ( this )
{
final List<PerContextHandlerRegistry> updatedList = new ArrayList<PerContextHandlerRegistry>(this.registrations);
updatedList.add(registry);
Collections.sort(updatedList);
this.registrations = updatedList;
}
}
public PerContextHandlerRegistry getRegistry(final long key)
{
final List<PerContextHandlerRegistry> list = this.registrations;
for(final PerContextHandlerRegistry r : list)
{
if ( key == r.getContextServiceId())
{
return r;
}
}
return null;
}
public @CheckForNull ServletResolution getErrorHandler(@Nonnull final String requestURI,
final Long serviceId,
final int code,
final Throwable exception)
{
final PerContextHandlerRegistry reg;
if ( serviceId == null )
{
// if the context is unknown, we use the first matching one!
PerContextHandlerRegistry found = null;
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
final String path = r.isMatching(requestURI);
if ( path != null )
{
found = r;
break;
}
}
reg = found;
}
else
{
reg = this.getRegistry(serviceId);
}
if ( reg != null )
{
final ServletHandler handler = reg.getErrorHandler(code, exception);
if ( handler != null )
{
final ServletResolution res = new ServletResolution();
res.handler = handler;
res.handlerRegistry = reg;
return res;
}
}
return null;
}
public FilterHandler[] getFilters(@Nonnull final ServletResolution pr,
@Nonnull final DispatcherType dispatcherType,
@Nonnull String requestURI)
{
if ( pr != null && pr.handlerRegistry != null )
{
return pr.handlerRegistry.getFilterHandlers(pr.handler, dispatcherType, requestURI);
}
return EMPTY_FILTER_HANDLER;
}
public PathResolution resolveServlet(@Nonnull final String requestURI)
{
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
final String path = r.isMatching(requestURI);
if ( path != null )
{
final PathResolution ps = r.resolve(path);
if ( ps != null )
{
// remove context path from request URI and add registry object
ps.requestURI = path;
ps.handlerRegistry = r;
return ps;
}
}
}
return null;
}
/**
* Get the servlet handler for a servlet by name
* @param contextId The context id
* @param name The servlet name
* @return The servlet handler or {@code null}
*/
public ServletResolution resolveServletByName(final long contextId, @Nonnull final String name)
{
final PerContextHandlerRegistry reg = this.getRegistry(contextId);
if ( reg != null )
{
final ServletHandler handler = reg.resolveServletByName(name);
if ( handler != null )
{
final ServletResolution resolution = new ServletResolution();
resolution.handler = handler;
resolution.handlerRegistry = reg;
return resolution;
}
}
return null;
}
public boolean getRuntimeInfo(@Nonnull final ServletContextDTO dto,
@Nonnull final FailedDTOHolder failedDTOHolder)
{
final PerContextHandlerRegistry reg = this.getRegistry(dto.serviceId);
if ( reg != null )
{
reg.getRuntime(dto, failedDTOHolder);
return true;
}
return false;
}
public PerContextHandlerRegistry getBestMatchingRegistry(String requestURI)
{
// if the context is unknown, we use the first matching one!
PerContextHandlerRegistry found = null;
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
final String path = r.isMatching(requestURI);
if ( path != null )
{
found = r;
break;
}
}
return found;
}
}