blob: edbbfc8a05982da16bd20b6e453b550cd2e8daef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* VMware Inc. - initial contribution
*******************************************************************************/
package org.eclipse.virgo.snaps.core.internal.webapp.container;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import org.eclipse.virgo.snaps.core.internal.SnapException;
import org.eclipse.virgo.snaps.core.internal.webapp.ImmutableFilterConfig;
import org.eclipse.virgo.snaps.core.internal.webapp.SnapServletContext;
import org.eclipse.virgo.snaps.core.internal.webapp.config.FilterDefinition;
import org.eclipse.virgo.snaps.core.internal.webapp.config.FilterDispatcherType;
import org.eclipse.virgo.snaps.core.internal.webapp.config.ServletNameFilterMappingDefinition;
import org.eclipse.virgo.snaps.core.internal.webapp.config.UrlPatternFilterMappingDefinition;
import org.eclipse.virgo.snaps.core.internal.webapp.config.WebXml;
import org.eclipse.virgo.snaps.core.internal.webapp.container.ManagerUtils.ClassLoaderCallback;
import org.eclipse.virgo.snaps.core.internal.webapp.url.FilterUrlPatternMatcher;
class FilterManager {
private final List<SnapServletContext> snapServletContexts = new ArrayList<>();
private final ClassLoader classLoader;
private final List<FilterHolder> filters = Collections.synchronizedList(new ArrayList<FilterHolder>());
private final List<UrlPatternFilterMapping> urlPatternFilterMappings = Collections.synchronizedList(new ArrayList<UrlPatternFilterMapping>());
private final List<ServletNameFilterMapping> servletNameFilterMappings = Collections.synchronizedList(new ArrayList<ServletNameFilterMapping>());
private WebXml webXml;
private Map<String, FilterHolder> filtersMap;
public FilterManager(WebXml webXml, SnapServletContext snapServletContext, ClassLoader classLoader) {
this.webXml = webXml;
this.snapServletContexts.add(snapServletContext);
this.classLoader = classLoader;
this.filtersMap = processFilters();
reifyWebXml(snapServletContext);
}
private void reifyWebXml(SnapServletContext snapServletContext) {
processUrlPatternFilterMappings(snapServletContext);
processServletNameFilterMappings();
}
private Map<String, FilterHolder> processFilters() throws SnapException {
Map<String, FilterHolder> filtersMap = new HashMap<String, FilterHolder>();
for (FilterDefinition filterDefinition : this.webXml.getFilterDefinitions()) {
try {
Class<?> filterClass = ManagerUtils.loadComponentClass(filterDefinition.getFilterClassName(), this.classLoader);
if (Filter.class.isAssignableFrom(filterClass)) {
Filter filter = (Filter) filterClass.newInstance();
FilterHolder filterHolder = new FilterHolder(filterDefinition, filter);
filtersMap.put(filterDefinition.getFilterName(), filterHolder);
this.filters.add(filterHolder);
} else {
throw new SnapException("The class '" + filterClass.getName() + "' does not implement '" + Filter.class.getName() + "'");
}
} catch (ClassNotFoundException e) {
throw new SnapException("The filter class '" + filterDefinition.getFilterClassName() + "' could not be loaded by "
+ this.classLoader, e);
} catch (InstantiationException e) {
throw new SnapException("The filter class '" + filterDefinition.getFilterClassName() + "' could not be instantiated", e);
} catch (IllegalAccessException e) {
throw new SnapException("The filter class '" + filterDefinition.getFilterClassName()
+ "' could not be instantiated due to access restrictions", e);
}
}
return filtersMap;
}
private void processUrlPatternFilterMappings(SnapServletContext snapServletContext) throws SnapException {
for (UrlPatternFilterMappingDefinition definition : this.webXml.getUrlPatternFilterMappingDefinitions()) {
Filter filter = this.filtersMap.get(definition.getFilterName()).getInstance();
this.urlPatternFilterMappings.add(new UrlPatternFilterMapping(filter, ManagerUtils.expandMapping(definition.getUrlPattern(), snapServletContext), definition.getFilterDispatcherTypes()));
}
}
private void processServletNameFilterMappings() {
for (ServletNameFilterMappingDefinition definition : this.webXml.getServletNameFilterMappingDefinitions()) {
Filter filter = this.filtersMap.get(definition.getFilterName()).getInstance();
this.servletNameFilterMappings.add(new ServletNameFilterMapping(filter, definition.getServletName(), definition.getFilterDispatcherTypes()));
}
}
void init() throws ServletException {
try {
ManagerUtils.doWithThreadContextClassLoader(this.classLoader, new ClassLoaderCallback<Void>() {
public Void doWithClassLoader() throws ServletException {
for (FilterHolder filterHolder : filters) {
FilterConfig config = new ImmutableFilterConfig(filterHolder.getDefinition(), snapServletContexts.get(0));
try {
filterHolder.getInstance().init(config);
} catch (ServletException se) {
// TODO Log which filter failed
throw se;
}
}
return null;
}
});
} catch (IOException e) {
throw new ServletException("Unexpected IOException from filter init", e);
}
}
void destroy() {
for (FilterHolder holder : this.filters) {
holder.getInstance().destroy();
}
this.filters.clear();
}
Filter[] findMatches(String path, String servletName, FilterDispatcherType dispatcherType) {
List<Filter> filters = new ArrayList<Filter>();
for (UrlPatternFilterMapping filterMapping : this.urlPatternFilterMappings) {
if (filterMapping.matches(path, dispatcherType)) {
filters.add(filterMapping.getFilter());
}
}
for (ServletNameFilterMapping filterMapping : this.servletNameFilterMappings) {
if (filterMapping.matches(servletName, dispatcherType)) {
filters.add(filterMapping.getFilter());
}
}
return filters.toArray(new Filter[filters.size()]);
}
private static abstract class FilterMapping {
private final Filter filter;
protected final Set<FilterDispatcherType> dispatcherTypes;
private FilterMapping(Filter filter, Set<FilterDispatcherType> dispatcherTypes) {
this.filter = filter;
this.dispatcherTypes = dispatcherTypes;
}
Filter getFilter() {
return this.filter;
}
}
private static class UrlPatternFilterMapping extends FilterMapping {
private final FilterUrlPatternMatcher patternMatcher;
private UrlPatternFilterMapping(Filter filter, String pattern, Set<FilterDispatcherType> dispatcherTypes) {
super(filter, dispatcherTypes);
this.patternMatcher = new FilterUrlPatternMatcher(pattern);
}
private boolean matches(String path, FilterDispatcherType dispatcherType) {
return this.dispatcherTypes.contains(dispatcherType) && this.patternMatcher.matches(path);
}
}
private static class ServletNameFilterMapping extends FilterMapping {
private final String servletName;
private ServletNameFilterMapping(Filter filter, String servletName, Set<FilterDispatcherType> dispatcherTypes) {
super(filter, dispatcherTypes);
this.servletName = servletName;
}
private boolean matches(String servletName, FilterDispatcherType dispatcherType) {
return this.dispatcherTypes.contains(dispatcherType) && this.servletName.equals(servletName);
}
}
public void addSnapServletContext(SnapServletContext snapServletContext) {
this.snapServletContexts.add(snapServletContext);
processUrlPatternFilterMappings(snapServletContext);
}
}