/*
* (C) Copyright 2006-2009 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed 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.
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id$
*/
package org.nuxeo.ecm.platform.web.common.requestcontroller.service;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.FilterConfig;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.runtime.model.ComponentInstance;
import org.nuxeo.runtime.model.DefaultComponent;
/**
* Runtime component that implements the {@link RequestControllerManager} interface. Contains both the Extension point
* logic and the service implementation.
*
* @author tiry
*/
public class RequestControllerService extends DefaultComponent implements RequestControllerManager {
public static final String FILTER_CONFIG_EP = "filterConfig";
public static final String CORS_CONFIG_EP = "corsConfig";
/**
* @since 6.0
*/
public static final String HEADERS_CONFIG_EP = "responseHeaders";
private static final Log log = LogFactory.getLog(RequestControllerService.class);
protected static final Map<String, FilterConfigDescriptor> grantPatterns = new LinkedHashMap<String, FilterConfigDescriptor>();
protected static final Map<String, FilterConfigDescriptor> denyPatterns = new LinkedHashMap<String, FilterConfigDescriptor>();
// @GuardedBy("itself")
protected static final Map<String, RequestFilterConfig> configCache = new LRUCachingMap<String, RequestFilterConfig>(
250);
protected static final Map<String, FilterConfig> filterConfigCache = new LRUCachingMap<>(250);
protected static final NuxeoCorsFilterDescriptorRegistry corsFilterRegistry = new NuxeoCorsFilterDescriptorRegistry();
protected static final NuxeoHeaderDescriptorRegistry headersRegistry = new NuxeoHeaderDescriptorRegistry();
protected Map<String, String> headersCache;
@Override
public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (FILTER_CONFIG_EP.equals(extensionPoint)) {
FilterConfigDescriptor desc = (FilterConfigDescriptor) contribution;
registerFilterConfig(desc);
} else if (CORS_CONFIG_EP.equals(extensionPoint)) {
corsFilterRegistry.addContribution((NuxeoCorsFilterDescriptor) contribution);
} else if (HEADERS_CONFIG_EP.equals(extensionPoint)) {
headersRegistry.addContribution((NuxeoHeaderDescriptor) contribution);
} else {
log.error("Unknown ExtensionPoint " + extensionPoint);
}
}
public void registerFilterConfig(String name, String pattern, boolean grant, boolean tx, boolean sync,
boolean cached, boolean isPrivate, String cacheTime) {
FilterConfigDescriptor desc = new FilterConfigDescriptor(name, pattern, grant, tx, sync, cached, isPrivate,
cacheTime);
registerFilterConfig(desc);
}
public void registerFilterConfig(FilterConfigDescriptor desc) {
if (desc.isGrantRule()) {
grantPatterns.put(desc.getName(), desc);
log.debug("Registered grant filter config");
} else {
denyPatterns.put(desc.getName(), desc);
log.debug("Registered deny filter config");
}
}
@Override
public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
if (CORS_CONFIG_EP.equals(extensionPoint)) {
corsFilterRegistry.removeContribution((NuxeoCorsFilterDescriptor) contribution);
}
}
/* Service interface */
@Override
public FilterConfig getCorsConfigForRequest(HttpServletRequest request) {
String uri = request.getRequestURI();
FilterConfig filterConfig = null;
synchronized (filterConfigCache) {
filterConfig = filterConfigCache.get(uri);
}
if (filterConfig == null) {
filterConfig = computeCorsFilterConfigForUri(uri);
synchronized (filterConfigCache) {
filterConfigCache.put(uri, filterConfig);
}
}
return filterConfig;
}
public FilterConfig computeCorsFilterConfigForUri(String uri) {
NuxeoCorsFilterDescriptor descriptor = corsFilterRegistry.getFirstMatchingDescriptor(uri);
return descriptor != null ? descriptor.buildFilterConfig() : null;
}
public RequestFilterConfig getConfigForRequest(HttpServletRequest request) {
String uri = request.getRequestURI();
RequestFilterConfig config = null;
synchronized (configCache) {
config = configCache.get(uri);
}
if (config == null) {
config = computeConfigForRequest(uri);
synchronized (configCache) {
configCache.put(uri, config);
}
}
return config;
}
public RequestFilterConfig computeConfigForRequest(String uri) {
// handle deny patterns
for (FilterConfigDescriptor desc : denyPatterns.values()) {
Pattern pat = desc.getCompiledPattern();
Matcher m = pat.matcher(uri);
if (m.matches()) {
return new RequestFilterConfigImpl(false, false, false, false, false, "");
}
}
// handle grant patterns
for (FilterConfigDescriptor desc : grantPatterns.values()) {
Pattern pat = desc.getCompiledPattern();
Matcher m = pat.matcher(uri);
if (m.matches()) {
return new RequestFilterConfigImpl(desc.useSync(), desc.useTx(), desc.useTxBuffered(), desc.isCached(),
desc.isPrivate(), desc.getCacheTime());
}
}
// return deny by default
return new RequestFilterConfigImpl(false, false, false, false, false, "");
}
public Map<String, String> getResponseHeaders() {
if (headersCache == null) {
headersCache = buildHeadersCache();
}
return headersCache;
}
protected static Map<String, String> buildHeadersCache() {
Map<String, String> headersCache = new HashMap<String, String>();
for (NuxeoHeaderDescriptor header : headersRegistry.descs.values()) {
headersCache.put(header.name, header.getValue());
}
return headersCache;
}
}