Merge branch 'maint-rel-1.6' of https://github.com/vivo-project/Vitro into maint-rel-1.6
This commit is contained in:
commit
b0c4ad4e4a
5 changed files with 79 additions and 22 deletions
|
@ -3,6 +3,7 @@
|
||||||
package edu.cornell.mannlib.vitro.webapp.freemarker.config;
|
package edu.cornell.mannlib.vitro.webapp.freemarker.config;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -35,28 +36,52 @@ import freemarker.template.utility.DeepUnwrap;
|
||||||
* Extend the Freemarker Configuration class to include some information that is
|
* Extend the Freemarker Configuration class to include some information that is
|
||||||
* particular to the current request.
|
* particular to the current request.
|
||||||
*
|
*
|
||||||
* Takes advantage of the fact that each servlet request runs in a separate
|
* A reference to the current request is not always available to the Freemarker
|
||||||
* thread. Stores the request-based information in a ThreadLocal. Override any
|
* Configuration, so we take advantage of the fact that each request runs in a
|
||||||
* methods that should return that information instead of (or in addition to)
|
* separate thread, and store a reference to that request in a ThreadLocal
|
||||||
* the common info.
|
* object.
|
||||||
|
*
|
||||||
|
* Then, we override any methods that should return that request-based
|
||||||
|
* information instead of (or in addition to) the common info.
|
||||||
*
|
*
|
||||||
* Only the getters are overridden, not the setters. So if you call
|
* Only the getters are overridden, not the setters. So if you call
|
||||||
* setAllSharedVariables(), for example, it will have no effect on the
|
* setAllSharedVariables(), for example, it will have no effect on the
|
||||||
* request-based information.
|
* request-based information.
|
||||||
|
*
|
||||||
|
* Notice that the reference to the current request is actually stored through a
|
||||||
|
* WeakReference. This is because the ThreadLocal will not be cleared when the
|
||||||
|
* webapp is stopped, so none of the references from that ThreadLocal are
|
||||||
|
* eligible for garbage collection. If any of those references is an instance of
|
||||||
|
* a class that is loaded by the webapp, then the webapp ClassLoader is not
|
||||||
|
* eligible for garbage collection. This would be a huge memory leak.
|
||||||
|
*
|
||||||
|
* Thanks to the WeakReference, the request is eligible for garbage collection
|
||||||
|
* if nothing else refers to it. In theory, this means that the WeakReference
|
||||||
|
* could return a null, but if the garbage collector has taken the request, then
|
||||||
|
* who is invoking this object?
|
||||||
*/
|
*/
|
||||||
public class FreemarkerConfigurationImpl extends Configuration {
|
public class FreemarkerConfigurationImpl extends Configuration {
|
||||||
private static final Log log = LogFactory
|
private static final Log log = LogFactory
|
||||||
.getLog(FreemarkerConfigurationImpl.class);
|
.getLog(FreemarkerConfigurationImpl.class);
|
||||||
|
|
||||||
private final ThreadLocal<RequestBasedInformation> rbiRef = new ThreadLocal<>();
|
private static final String ATTRIBUTE_NAME = RequestBasedInformation.class
|
||||||
|
.getName();
|
||||||
|
|
||||||
|
private final ThreadLocal<WeakReference<HttpServletRequest>> reqRef = new ThreadLocal<>();
|
||||||
|
|
||||||
void setRequestInfo(HttpServletRequest req) {
|
void setRequestInfo(HttpServletRequest req) {
|
||||||
rbiRef.set(new RequestBasedInformation(req, this));
|
reqRef.set(new WeakReference<>(req));
|
||||||
|
req.setAttribute(ATTRIBUTE_NAME, new RequestBasedInformation(req, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RequestBasedInformation getRequestInfo() {
|
||||||
|
HttpServletRequest req = reqRef.get().get();
|
||||||
|
return (RequestBasedInformation) req.getAttribute(ATTRIBUTE_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getCustomAttribute(String name) {
|
public Object getCustomAttribute(String name) {
|
||||||
Map<String, Object> attribs = rbiRef.get().getCustomAttributes();
|
Map<String, Object> attribs = getRequestInfo().getCustomAttributes();
|
||||||
if (attribs.containsKey(name)) {
|
if (attribs.containsKey(name)) {
|
||||||
return attribs.get(name);
|
return attribs.get(name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -66,13 +91,13 @@ public class FreemarkerConfigurationImpl extends Configuration {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getCustomAttributeNames() {
|
public String[] getCustomAttributeNames() {
|
||||||
Set<String> rbiNames = rbiRef.get().getCustomAttributes().keySet();
|
Set<String> rbiNames = getRequestInfo().getCustomAttributes().keySet();
|
||||||
return joinNames(rbiNames, super.getCustomAttributeNames());
|
return joinNames(rbiNames, super.getCustomAttributeNames());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateModel getSharedVariable(String name) {
|
public TemplateModel getSharedVariable(String name) {
|
||||||
Map<String, TemplateModel> vars = rbiRef.get().getSharedVariables();
|
Map<String, TemplateModel> vars = getRequestInfo().getSharedVariables();
|
||||||
if (vars.containsKey(name)) {
|
if (vars.containsKey(name)) {
|
||||||
return vars.get(name);
|
return vars.get(name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -82,7 +107,7 @@ public class FreemarkerConfigurationImpl extends Configuration {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getSharedVariableNames() {
|
public Set<String> getSharedVariableNames() {
|
||||||
Set<String> rbiNames = rbiRef.get().getSharedVariables().keySet();
|
Set<String> rbiNames = getRequestInfo().getSharedVariables().keySet();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Set<String> superNames = super.getSharedVariableNames();
|
Set<String> superNames = super.getSharedVariableNames();
|
||||||
|
@ -94,7 +119,7 @@ public class FreemarkerConfigurationImpl extends Configuration {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Locale getLocale() {
|
public Locale getLocale() {
|
||||||
return rbiRef.get().getReq().getLocale();
|
return getRequestInfo().getReq().getLocale();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] joinNames(Set<String> nameSet, String[] nameArray) {
|
private String[] joinNames(Set<String> nameSet, String[] nameArray) {
|
||||||
|
|
|
@ -179,7 +179,7 @@ public class DeveloperSettings {
|
||||||
// The factory
|
// The factory
|
||||||
// ----------------------------------------------------------------------
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
private static final String ATTRIBUTE_NAME = DeveloperSettings.class
|
protected static final String ATTRIBUTE_NAME = DeveloperSettings.class
|
||||||
.getName();
|
.getName();
|
||||||
|
|
||||||
public static DeveloperSettings getBean(HttpServletRequest req) {
|
public static DeveloperSettings getBean(HttpServletRequest req) {
|
||||||
|
@ -203,7 +203,7 @@ public class DeveloperSettings {
|
||||||
|
|
||||||
private final Map<Keys, Object> settings = new EnumMap<>(Keys.class);
|
private final Map<Keys, Object> settings = new EnumMap<>(Keys.class);
|
||||||
|
|
||||||
private DeveloperSettings(ServletContext ctx) {
|
protected DeveloperSettings(ServletContext ctx) {
|
||||||
updateFromFile(ctx);
|
updateFromFile(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package stubs.edu.cornell.mannlib.vitro.webapp.utils.developer;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do everything that a standard DeveloperSettings would do, except loading from
|
||||||
|
* a properties file.
|
||||||
|
*
|
||||||
|
* That way, we don't require ConfigurationProperties to find the Vitro home
|
||||||
|
* directory, so we don't throw errors if there is no ConfigurationProperties.
|
||||||
|
*/
|
||||||
|
public class DeveloperSettingsStub extends DeveloperSettings {
|
||||||
|
/**
|
||||||
|
* Factory method. Create the stub and set it into the ServletContext.
|
||||||
|
*/
|
||||||
|
public static void set(ServletContext ctx) {
|
||||||
|
ctx.setAttribute(ATTRIBUTE_NAME, new DeveloperSettingsStub(ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DeveloperSettingsStub(ServletContext ctx) {
|
||||||
|
super(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateFromFile(ServletContext ctx) {
|
||||||
|
// Don't bother.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,6 +21,8 @@ import javax.servlet.ServletException;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import stubs.edu.cornell.mannlib.vitro.webapp.utils.developer.DeveloperSettingsStub;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple stand-in for the {@link ServletContext}, for use in unit tests.
|
* A simple stand-in for the {@link ServletContext}, for use in unit tests.
|
||||||
*/
|
*/
|
||||||
|
@ -36,6 +38,11 @@ public class ServletContextStub implements ServletContext {
|
||||||
private final Map<String, String> mockResources = new HashMap<String, String>();
|
private final Map<String, String> mockResources = new HashMap<String, String>();
|
||||||
private final Map<String, String> realPaths = new HashMap<String, String>();
|
private final Map<String, String> realPaths = new HashMap<String, String>();
|
||||||
|
|
||||||
|
public ServletContextStub() {
|
||||||
|
// Assume that unit tests won't want to use Developer mode.
|
||||||
|
DeveloperSettingsStub.set(this);
|
||||||
|
}
|
||||||
|
|
||||||
public void setContextPath(String contextPath) {
|
public void setContextPath(String contextPath) {
|
||||||
if (contextPath == null) {
|
if (contextPath == null) {
|
||||||
throw new NullPointerException("contextPath may not be null.");
|
throw new NullPointerException("contextPath may not be null.");
|
||||||
|
|
|
@ -13,20 +13,16 @@ $(document).ready(function(){
|
||||||
jQuery('section#flash-message').css('display', 'none').fadeIn(1500);
|
jQuery('section#flash-message').css('display', 'none').fadeIn(1500);
|
||||||
|
|
||||||
/////////////////////////////
|
/////////////////////////////
|
||||||
// Home search fiter
|
// Home search filter
|
||||||
// Toggle filter select list
|
// Toggle filter select list
|
||||||
var $searchFilterList = $('#filter-search-nav');
|
var $searchFilterList = $('#filter-search-nav');
|
||||||
var $isFilterOpen = false;
|
var $isFilterOpen = false;
|
||||||
|
|
||||||
console.log("Filter is open = " + $isFilterOpen);
|
|
||||||
|
|
||||||
$('a.filter-search').click(function(e) {
|
$('a.filter-search').click(function(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!$isFilterOpen) {
|
if (!$isFilterOpen) {
|
||||||
|
|
||||||
console.log("Filter is closed = " + $isFilterOpen);
|
|
||||||
|
|
||||||
//Change button filter state to selected
|
//Change button filter state to selected
|
||||||
//$(this).css('background','url(../../themes/vivo-cornell/images/filteredSearchActive.gif) no-repeat right top');
|
//$(this).css('background','url(../../themes/vivo-cornell/images/filteredSearchActive.gif) no-repeat right top');
|
||||||
$(this).removeClass('filter-default');
|
$(this).removeClass('filter-default');
|
||||||
|
@ -37,7 +33,6 @@ $(document).ready(function(){
|
||||||
|
|
||||||
$isFilterOpen = true;
|
$isFilterOpen = true;
|
||||||
|
|
||||||
console.log("open");
|
|
||||||
} else {
|
} else {
|
||||||
//Change button filter state to default
|
//Change button filter state to default
|
||||||
//$('a.filter-search').css('background','url(../../themes/vivo-cornell/images/filteredSearch.gif) no-repeat right top');
|
//$('a.filter-search').css('background','url(../../themes/vivo-cornell/images/filteredSearch.gif) no-repeat right top');
|
||||||
|
@ -49,7 +44,6 @@ $(document).ready(function(){
|
||||||
|
|
||||||
$isFilterOpen = false;
|
$isFilterOpen = false;
|
||||||
|
|
||||||
console.log("closed");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -63,7 +57,6 @@ $(document).ready(function(){
|
||||||
//Selected filter feedback
|
//Selected filter feedback
|
||||||
$('.search-filter-selected').text('');
|
$('.search-filter-selected').text('');
|
||||||
$('input[name="classgroup"]').val('');
|
$('input[name="classgroup"]').val('');
|
||||||
console.log("ALL");
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
$('.search-filter-selected').text($(this).text()).fadeIn('slow');
|
$('.search-filter-selected').text($(this).text()).fadeIn('slow');
|
||||||
|
@ -110,6 +103,5 @@ $(document).ready(function(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("HIDE input value ") ;
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue