| /* |
| * 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; |
| } |
| } |