Commit 0f6323d3 authored by Matija Obreza's avatar Matija Obreza
Browse files

Removed NewGUIFilter and view resolver

parent f595c3c5
/**
* Copyright 2016 Global Crop Diversity Trust
*
* 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.
**/
package org.genesys2.server.servlet.filter;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.lang.StringUtils;
import org.genesys2.spring.config.NewGUIViewResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.util.UriUtils;
/**
* The {@code NewGUIFilter} allows for having URL-based versioned user
* interfaces. Any URL prefixed with {@code /version/} is stripped of the
* version information and the version data stored. The decorators are loaded
* before this filter and will appropriately render appropriately.
*
* @author Matija Obreza
*/
public class NewGUIFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(NewGUIFilter.class);
public static final String REQUEST_GUIVERSION_ATTR = LocaleURLFilter.class.getName() + ".GUIVERSION";
private static final Pattern newGuiPattern = Pattern.compile("/(\\d+)(/.+)");
private String[] excludedPaths;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String excludePaths = filterConfig.getInitParameter("exclude-paths");
if (StringUtils.isNotBlank(excludePaths)) {
String[] ex = excludePaths.split("\\s+");
for (String e : ex) {
LOG.info("Excluding path: {}", e);
}
this.excludedPaths = ex;
}
}
@Override
public void destroy() {
if (LOG.isDebugEnabled()) {
LOG.debug("Destroying NewGUIFilter");
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
final String originalUrl = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
final String origianlUrlDecoded = UriUtils.decode(originalUrl, "UTF-8");
if (LOG.isTraceEnabled()) {
LOG.trace("Incoming URL: {}", originalUrl);
}
final Matcher matcher = newGuiPattern.matcher(originalUrl);
if (matcher.matches()) {
final String guiPrefix = "/" + matcher.group(1);
final String remainingUrl = matcher.group(2);
if (LOG.isDebugEnabled()) {
LOG.trace("URL matches! prefix={} remaining={}", guiPrefix, remainingUrl);
LOG.debug("Proxying request to remaining URL {}", remainingUrl);
}
HttpServletRequestWrapper guiRequest = new HttpServletRequestWrapper(httpRequest) {
@Override
public String getServletPath() {
String servletPath = super.getServletPath();
// servletPath is URL decoded, must use origianlUrlDecoded.
if (origianlUrlDecoded.equals(servletPath)) {
if (LOG.isDebugEnabled())
LOG.debug("servletPath={} remaining={}", servletPath, remainingUrl);
return remainingUrl;
}
return servletPath;
}
@Override
public String getRequestURI() {
String requestURI = super.getRequestURI();
// requestURI is URL encoded, must use originalUrl.
if (originalUrl.equals(requestURI)) {
if (LOG.isDebugEnabled())
LOG.debug("requestURI={} remaining={}", requestURI, remainingUrl);
return remainingUrl;
}
return requestURI;
}
};
HttpServletResponseWrapper guiResponse = new HttpServletResponseWrapper(httpResponse) {
private boolean isExcluded(String url) {
for (String excludedPath : excludedPaths) {
if (url.startsWith(excludedPath)) {
if (LOG.isTraceEnabled()) {
LOG.trace("Excluded={} matches {}", excludedPath, url);
}
return true;
}
}
return url.startsWith("?");
}
@Override
public String encodeURL(String url) {
if (isExcluded(url)) {
return super.encodeURL(url);
} else {
String encodedURL = super.encodeURL(guiPrefix + url);
if (LOG.isDebugEnabled()) {
LOG.debug("encodeURL {} to {}", url, encodedURL);
}
return encodedURL;
}
}
@Override
@Deprecated
public String encodeUrl(String url) {
if (isExcluded(url)) {
return super.encodeUrl(url);
} else {
String encodedURL = super.encodeUrl(guiPrefix + url);
if (LOG.isDebugEnabled()) {
LOG.debug("encodeUrl {} to {}", url, encodedURL);
}
return encodedURL;
}
}
@Override
public String encodeRedirectURL(String url) {
if (isExcluded(url)) {
return super.encodeRedirectURL(url);
} else {
String encodedURL = super.encodeRedirectURL(guiPrefix + url);
if (LOG.isDebugEnabled()) {
LOG.debug("encodeRedirectURL {} to {}", url, encodedURL);
}
return encodedURL;
}
}
};
try {
try {
final int guiVersion = Integer.parseInt(matcher.group(1));
httpRequest.setAttribute(REQUEST_GUIVERSION_ATTR, guiVersion);
LocalGUIVersion.set(guiVersion);
} catch (NumberFormatException e) {
LOG.info("Invalid GUI version in {}: {}", matcher.group(1), e.getMessage());
}
filterChain.doFilter(guiRequest, guiResponse);
} finally {
LocalGUIVersion.remove();
}
} else {
if (LOG.isTraceEnabled()) {
LOG.trace("No match on url {}", originalUrl);
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
/**
* A ThreadLocal utility to manage the GUI version information. Used by
* {@link NewGUIViewResolver}.
*/
public static class LocalGUIVersion {
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadGuiVersion = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
};
};
// Returns the current thread's unique ID, assigning it if necessary
public static void set(int version) {
threadGuiVersion.set(version);
}
public static void remove() {
threadGuiVersion.remove();
}
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadGuiVersion.get();
}
}
}
/*
* Copyright 2017 Global Crop Diversity Trust
*
* 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.
*/
package org.genesys2.spring.config;
import java.io.File;
import java.util.Locale;
import org.genesys2.server.servlet.filter.NewGUIFilter;
import org.genesys2.server.servlet.filter.NewGUIFilter.LocalGUIVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
* Using the GUI version captured in {@link NewGUIFilter}, this view resolver
* checks for view (.jsp) files in
* {@code getPrefix() + "/" + LocalGUIVersion.get() + viewName + getSuffix()}
* location. For example the /admin/index view will be resolved to
* /WEB-INF/jsp/admin/index.jsp with the standard resolver.
*
* The {@code NewGUIViewResolver} first checks if the versioned view exists at
* {@code /WEB-INF/jsp/1/admin/index.jsp} and returns /1/admin/index if the
* relevant .jsp file exists.
*
* @author Matija Obreza
*
*/
public class NewGUIViewResolver extends InternalResourceViewResolver {
private static final Logger LOG = LoggerFactory.getLogger(NewGUIViewResolver.class);
@Override
protected Object getCacheKey(final String viewName, final Locale locale) {
if (LocalGUIVersion.get() == 0) {
return super.getCacheKey(viewName, locale);
}
final File file = new File(getServletContext().getRealPath(getPrefix() + "/" + LocalGUIVersion.get() + viewName + getSuffix()));
if (LOG.isDebugEnabled()) {
LOG.debug("Checking versioned view in {}", file.getAbsolutePath());
}
if (file.exists()) {
if (LOG.isInfoEnabled()) {
LOG.info("Using versioned view at /{}", LocalGUIVersion.get() + viewName);
}
return super.getCacheKey("/" + LocalGUIVersion.get() + viewName, locale);
} else {
if (LOG.isInfoEnabled()) {
LOG.info("Versioned view not found at /{}", LocalGUIVersion.get() + viewName);
}
}
return super.getCacheKey(viewName, locale);
}
@Override
protected View createView(final String viewName, final Locale locale) throws Exception {
if (LocalGUIVersion.get() == 0) {
if (LOG.isTraceEnabled()) {
LOG.trace("LocalGUIVersion.get() returns 0");
}
return super.createView(viewName, locale);
}
// If this resolver is not supposed to handle the given view,
// return null to pass on to the next resolver in the chain.
if (!canHandle(viewName, locale)) {
return null;
}
// Check for special "redirect:" prefix.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
super.createView(viewName, locale);
}
// Check for special "forward:" prefix.
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
super.createView(viewName, locale);
}
// Check for getPrefix() + LocalGUIVersion.get() + viewName +
// getSuffix() file
final File file = new File(getServletContext().getRealPath(getPrefix() + "/" + LocalGUIVersion.get() + viewName + getSuffix()));
if (LOG.isDebugEnabled()) {
LOG.debug("Checking versioned view in {}", file.getAbsolutePath());
}
if (file.exists()) {
if (LOG.isInfoEnabled()) {
LOG.info("Using versioned view at /{}", LocalGUIVersion.get() + viewName);
}
return super.createView("/" + LocalGUIVersion.get() + viewName, locale);
} else {
if (LOG.isInfoEnabled()) {
LOG.info("Versioned view not found at /{}", LocalGUIVersion.get() + viewName);
}
}
// Else fall back to superclass implementation: calling loadView.
return super.createView(viewName, locale);
}
}
......@@ -136,7 +136,7 @@ public class WebConfiguration extends WebMvcConfigurerAdapter {
@Bean
public InternalResourceViewResolver jstlViewResolver() {
final InternalResourceViewResolver resolver = new NewGUIViewResolver();
final InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/jsp");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
......
......@@ -27,7 +27,6 @@ import javax.servlet.SessionTrackingMode;
import com.hazelcast.web.SessionListener;
import org.genesys2.server.servlet.filter.LocaleURLFilter;
import org.genesys2.server.servlet.filter.NewGUIFilter;
import org.sitemesh.builder.SiteMeshFilterBuilder;
import org.sitemesh.config.ConfigurableSiteMeshFilter;
import org.sitemesh.webapp.contentfilter.BasicSelector;
......@@ -125,12 +124,6 @@ public class WebInitializer extends AbstractAnnotationConfigDispatcherServletIni
final FilterRegistration.Dynamic sitemeshFilter = servletContext.addFilter("sitemesh", sitemeshWithErrors);
sitemeshFilter.addMappingForUrlPatterns(null, false, "/*");
// New GUI filter configuration
// TODO Upgrade to @WebFilter
final FilterRegistration.Dynamic newGUIFilter = servletContext.addFilter("newGUIFilter", NewGUIFilter.class);
newGUIFilter.setInitParameter("exclude-paths", "/html /login-attempt");
newGUIFilter.addMappingForUrlPatterns(null, false, "/*");
// GZip filter configuration
final FilterRegistration.Dynamic gZIPFilter = servletContext.addFilter("gZIPFilter", GzipFilter.class);
gZIPFilter.addMappingForUrlPatterns(null, false, "/html/*");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment