Commit f185f5a6 authored by Matija Obreza's avatar Matija Obreza
Browse files

NewGUIViewResolver checks for versioned .jsp files in /WEB-INF/jsp/1/ folder

parent 9b485529
/**
* Copyright 2014 Global Crop Diversity Trust
* 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.
......@@ -33,7 +33,16 @@ import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.genesys2.spring.config.NewGUIViewResolver;
/**
* 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 = Logger.getLogger(NewGUIFilter.class);
public static final String REQUEST_GUIVERSION_ATTR = LocaleURLFilter.class.getName() + ".GUIVERSION";
......@@ -75,14 +84,6 @@ public class NewGUIFilter implements Filter {
if (matcher.matches()) {
final String guiPrefix = "/" + matcher.group(1);
final String remainingUrl = matcher.group(2);
try {
final int guiVersion = Integer.parseInt(matcher.group(1));
httpRequest.setAttribute(REQUEST_GUIVERSION_ATTR, guiVersion);
} catch (NumberFormatException e) {
LOG.info("Invalid GUI version in " + matcher.group(1) + ": " + e.getMessage());
}
if (LOG.isDebugEnabled()) {
LOG.trace("URL matches! prefix=" + guiPrefix + " remaining=" + remainingUrl);
......@@ -167,7 +168,18 @@ public class NewGUIFilter implements Filter {
}
};
filterChain.doFilter(guiRequest, guiResponse);
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);
......@@ -175,4 +187,32 @@ public class NewGUIFilter implements Filter {
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 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.spring.config;
import java.io.File;
import java.util.Locale;
import org.apache.log4j.Logger;
import org.genesys2.server.servlet.filter.NewGUIFilter;
import org.genesys2.server.servlet.filter.NewGUIFilter.LocalGUIVersion;
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 = Logger.getLogger(NewGUIViewResolver.class);
@Override
protected Object getCacheKey(String viewName, Locale locale) {
if (LocalGUIVersion.get() == 0) {
return super.getCacheKey(viewName, locale);
}
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(String viewName, 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
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);
}
}
......@@ -45,6 +45,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import org.springframework.web.servlet.theme.CookieThemeResolver;
import org.springframework.web.servlet.theme.ThemeChangeInterceptor;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Import({ SpringProperties.class })
@EnableWebMvc
......@@ -73,7 +74,7 @@ public class SpringServletConfig extends WebMvcConfigurerAdapter {
@Bean
public ViewResolver viewResolver() {
final org.springframework.web.servlet.view.InternalResourceViewResolver resolver = new org.springframework.web.servlet.view.InternalResourceViewResolver();
final InternalResourceViewResolver resolver = new NewGUIViewResolver();
resolver.setPrefix("/WEB-INF/jsp");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
......
......@@ -41,4 +41,5 @@ log4j.category.com.hazelcast=info
#log4j.category.org.eclipse.jetty.servlets=trace
#LocaleURLFilter
#log4j.category.org.genesys2.server.servlet.filter=debug
log4j.category.org.genesys2.server.servlet.filter.NewGUIFilter=debug
#log4j.category.org.genesys2.server.servlet.filter.NewGUIFilter=debug
#log4j.category.org.genesys2.spring.config.NewGUIViewResolver=trace
<!DOCTYPE html>
<%@include file="/WEB-INF/jsp/init.jsp"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<html>
<head>
<title><spring:message code="admin.cache.page.title" />1</title>
</head>
<body>
<h1>
<spring:message code="admin.cache.page.title" />
</h1>
<%@ include file="/WEB-INF/jsp/admin/menu.jsp"%>
<form method="post" action="<c:url value="/admin/cache/clearTilesCache" />">
<input type="submit" class="btn btn-default" value="Clear Tiles cache" />
<!-- CSRF protection -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<form method="post" action="<c:url value="/admin/cache/clearCaches" />">
<input type="submit" class="btn btn-default" value="Clear all caches" />
<!-- CSRF protection -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:forEach items="${cacheMaps}" var="cacheMap">
<h3>
<c:out value="${cacheMap.serviceName}" />
<c:out value="${cacheMap.name}" />
</h3>
<form method="post" action="<c:url value="/admin/cache/clearCache" />">
<input type="hidden" name="name" value="${cacheMap.name}" />
<input type="submit" class="btn btn-default" value="Clear" />
<!-- CSRF protection -->
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
<c:set value="${cacheMap.mapStats}" var="mapStat" />
<div class="row">
<div class="col-xs-6 col-sm-4">
<spring:message code="cache.stat.map.ownedEntryCount" />
</div>
<div class="col-xs-6 col-sm-8">
<c:out value="${mapStat.ownedEntryCount}" />
</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-4">
<spring:message code="cache.stat.map.lockedEntryCount" />
</div>
<div class="col-xs-6 col-sm-8">
<c:out value="${mapStat.lockedEntryCount}" />
</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-4">
<spring:message code="cache.stat.map.puts" />
</div>
<div class="col-xs-6 col-sm-8">
<c:out value="${mapStat.putOperationCount}" />
</div>
</div>
<div class="row">
<div class="col-xs-6 col-sm-4">
<spring:message code="cache.stat.map.hits" />
</div>
<div class="col-xs-6 col-sm-8">
<c:out value="${mapStat.hits}" />
</div>
</div>
</c:forEach>
<c:forEach items="${cacheOthers}" var="cacheOther">
<h3>
<c:out value="${cacheOther}" />
<c:out value="${cacheOther}" />
</h3>
</c:forEach>
</body>
</html>
\ No newline at end of file
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