blob: e872de14ae74cf6ffb94d717e835c7f7377f4097 [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.handler;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.annotation.Nonnull;
import javax.servlet.DispatcherType;
import org.apache.felix.http.base.internal.runtime.ServletContextHelperInfo;
import org.apache.felix.http.base.internal.runtime.dto.ContextRuntime;
import org.apache.felix.http.base.internal.runtime.dto.FailureRuntime;
import org.osgi.framework.BundleContext;
/**
* 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];
private final BundleContext bundleContext;
/** Current list of context registrations. */
private volatile List<PerContextHandlerRegistry> registrations = Collections.emptyList();
public HandlerRegistry(BundleContext bundleContext)
{
this.bundleContext = bundleContext;
}
/**
* Register default context registry for Http Service
*/
public void init()
{
this.add(new PerContextHandlerRegistry(this.bundleContext));
}
/**
* 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();
}
}
/**
* Add a context registration.
* @param info The servlet context helper info
*/
public void add(@Nonnull ServletContextHelperInfo info)
{
this.add(new PerContextHandlerRegistry(info, this.bundleContext));
}
/**
* 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.
*/
private 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;
}
}
/**
* Get the per context registry.
* @param info The servlet context helper info or {@code null} for the Http Service context.
* @return A per context registry or {@code null}
*/
public PerContextHandlerRegistry getRegistry(final ServletContextHelperInfo info)
{
final long key = (info == null ? 0 : info.getServiceId());
synchronized ( this )
{
for(final PerContextHandlerRegistry r : this.registrations)
{
if ( key == r.getContextServiceId())
{
return r;
}
}
}
return null;
}
public ErrorsMapping getErrorsMapping(final String requestURI, final Long serviceId)
{
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
if ( serviceId != null && serviceId == r.getContextServiceId() )
{
return r.getErrorsMapping();
}
else if ( serviceId == null && r.isMatching(requestURI) != null )
{
return r.getErrorsMapping();
}
}
return null;
}
public FilterHandler[] getFilterHandlers(@Nonnull final ServletHandler servletHandler,
final DispatcherType dispatcherType,
@Nonnull final String requestURI)
{
final long key = servletHandler.getContextServiceId();
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
if ( key == r.getContextServiceId() )
{
return r.getFilterHandlers(servletHandler, dispatcherType, requestURI);
}
}
return EMPTY_FILTER_HANDLER;
}
/**
* Get the servlet handler for a servlet by name
* @param contextId The context id or {@code null}
* @param name The servlet name
* @return The servlet handler or {@code null}
*/
public ServletHandler getServletHandlerByName(final Long contextId, @Nonnull final String name)
{
final long key = (contextId == null ? 0 : contextId);
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
if ( key == r.getContextServiceId() )
{
return r.getServletHandlerByName(name);
}
}
return null;
}
/**
* Search the servlet handler for the request uri
* @param requestURI The request uri
* @return
*/
public ServletHandler getServletHander(@Nonnull final String requestURI)
{
// search the first matching context registry
final List<PerContextHandlerRegistry> regs = this.registrations;
for(final PerContextHandlerRegistry r : regs)
{
final String pathInContext = r.isMatching(requestURI);
if ( pathInContext != null )
{
final ServletHandler handler = r.getServletHander(pathInContext);
if ( handler != null )
{
return handler;
}
}
}
return null;
}
public synchronized List<ContextRuntime> getRuntime(FailureRuntime.Builder failureRuntimeBuilder)
{
List<ContextRuntime> handlerRuntimes = new ArrayList<ContextRuntime>();
for (PerContextHandlerRegistry contextRegistry : this.registrations)
{
handlerRuntimes.add(contextRegistry.getRuntime(failureRuntimeBuilder));
}
return handlerRuntimes;
}
}