diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java index 3080b1ee0..5ef76ca56 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerConfigurationLoader.java @@ -101,12 +101,14 @@ public class FreemarkerConfigurationLoader { } // Specify how templates will see the data model. - // The default wrapper exposes set methods unless exposure level is set. - // By default we want to block exposure of set methods. + // The Freemarker default wrapper exposes set methods and get methods that take + // arguments. We block exposure to these methods by default. BeansWrapper wrapper = new DefaultObjectWrapper(); - wrapper.setExposureLevel(BeansWrapper.EXPOSE_PROPERTIES_ONLY); + int defaultExposureLevel = BeansWrapper.EXPOSE_PROPERTIES_ONLY; + wrapper.setExposureLevel(defaultExposureLevel); config.setObjectWrapper(wrapper); - + config.setCustomAttribute("defaultExposureLevel", defaultExposureLevel); + // Set some formatting defaults. These can be overridden at the template // or environment (template-processing) level, or for an individual // token by using built-ins. diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DumpHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DumpHelper.java index 2a96a439b..2c5d723c2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DumpHelper.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DumpHelper.java @@ -11,6 +11,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.servlet.http.HttpServletRequest; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -21,6 +23,7 @@ import freemarker.core.Environment; import freemarker.ext.beans.BeanModel; import freemarker.ext.beans.BeansWrapper; import freemarker.ext.beans.WrapperExtractor; +import freemarker.template.Configuration; import freemarker.template.TemplateBooleanModel; import freemarker.template.TemplateDateModel; import freemarker.template.TemplateHashModel; @@ -53,17 +56,12 @@ public class DumpHelper { tm = dataModel.get(varName); } catch (TemplateModelException e) { log.error("Error getting value of template model '" + varName + "' from data model."); - return null; - } - - if (tm == null) { - log.error("No variable '" + varName + "' defined in data model." ); - return null; } Map map = new HashMap(); map.put("var", varName); + // DON'T return null if tm == null. We still want to return the map to the template. if (tm != null) { Object unwrappedModel = null; try { @@ -87,7 +85,7 @@ public class DumpHelper { // view in the dump. Not sure if we should handle our application-specific, non-template // model objects in the same way. For now, these get assigned a shorthand type below. if (unwrappedModel instanceof BaseTemplateModel) { - value = getTemplateModelDump(tm, (BaseTemplateModel)unwrappedModel); //((BaseTemplateModel)unwrappedModel).dump(); + map.putAll(getTemplateModelValues(tm, (BaseTemplateModel)unwrappedModel)); type = className; } // Can't use this, because tm of (at least some) POJOs are @@ -115,8 +113,13 @@ public class DumpHelper { type = className; } - map.put("value", value); map.put("type", type); + + // Don't overwrite value returned from getTemplateModelValues(). + if (! map.containsKey("value")) { + map.put("value", value); + } + } return map; @@ -133,18 +136,37 @@ public class DumpHelper { } protected List getMethodsAvailableToTemplate(TemplateModel wrappedModel, Class cls) { + + int exposureLevel; + // Get the exposure level of the BeansWrapper that wrapped this object. + if (wrappedModel instanceof BeanModel) { + exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel) wrappedModel); + log.debug("Exposure level for class " + cls.getCanonicalName() + " of type " + wrappedModel.getClass() + " = " + exposureLevel); + // We don't expect to get here, since we are dealing only with BaseTemplateModel objects, which get wrapped into BeanModel objects, + // but it's here as a safety net. + } else { + HttpServletRequest request = (HttpServletRequest) env.getCustomAttribute("request"); + Configuration config = (Configuration) request.getAttribute("freemarkerConfig"); + exposureLevel = (Integer) config.getCustomAttribute("defaultExposureLevel"); + log.debug("Class " + cls.getCanonicalName() + " of type " + wrappedModel.getClass() + " uses default exposure level " + exposureLevel); + } + + return getMethodsAvailableToTemplate(exposureLevel, cls); + } + + private List getMethodsAvailableToTemplate(int exposureLevel, Class cls) { List methods = new ArrayList(); - + // Go up the class hierarchy only as far as the immediate subclass of BaseTemplateModel if (! cls.getName().equals("edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel")) { - methods = getDeclaredMethodsAvailableToTemplate(wrappedModel, cls); - methods.addAll(getMethodsAvailableToTemplate(wrappedModel, cls.getSuperclass())); + methods = getDeclaredMethodsAvailableToTemplate(exposureLevel, cls); + methods.addAll(getMethodsAvailableToTemplate(exposureLevel, cls.getSuperclass())); } return methods; } - private List getDeclaredMethodsAvailableToTemplate(TemplateModel wrappedModel, Class cls) { + private List getDeclaredMethodsAvailableToTemplate(int exposureLevel, Class cls) { List methods = new ArrayList(); Method[] declaredMethods = cls.getDeclaredMethods(); @@ -152,18 +174,10 @@ public class DumpHelper { int mod = method.getModifiers(); if (Modifier.isPublic(mod) && !Modifier.isStatic(mod)) { Class[] params = method.getParameterTypes(); - // If the method takes arguments... - if (params.length > 0) { - // Unless the object has been wrapped with a non-default BeansWrapper with an exposure - // level that is more permissive than the Configuration's default BeansWrapper, this - // method is not visible to the template. - if ( ! ( wrappedModel instanceof BeanModel ) ) { - continue; - } - int exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel)wrappedModel); - if ( exposureLevel > BeansWrapper.EXPOSE_SAFE ) { - continue; - } + // If the method takes arguments, then it is not available to the template unless + // the exposure level of the BeansWrapper that wrapped the object allows it. + if (params.length > 0 && exposureLevel > BeansWrapper.EXPOSE_SAFE) { + continue; } methods.add(method); } @@ -194,20 +208,20 @@ public class DumpHelper { return methodName + paramList; } - private String getTemplateModelDump(TemplateModel wrappedModel, BaseTemplateModel unwrappedModel) { + private Map getTemplateModelValues(TemplateModel wrappedModel, BaseTemplateModel unwrappedModel) { -// if (tm instanceof BeanModel) { -// int exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel) tm); -// log.debug(varName + " is an instance of BeanModel. Exposure level = " + exposureLevel); -// } + Map map = new HashMap(); + map.put("value", unwrappedModel.dump()); - Map map = new HashMap(); List publicMethods = getMethodsAvailableToTemplate(wrappedModel, unwrappedModel.getClass()); Map properties = new HashMap(); List methods = new ArrayList(); for (Method method : publicMethods) { - String key = getMethodDisplayName(method); - + // Don't include the dump method, since this is used above to provide the value of the object. + if (method.getName().equals("dump")) { + continue; + } + String key = getMethodDisplayName(method); if (key.endsWith(")")) { methods.add(key); } else { @@ -221,11 +235,10 @@ public class DumpHelper { } } } - + map.put("properties", properties); map.put("methods", methods); - return BaseTemplateDirectiveModel.processTemplateToString("dump-tm.ftl", map, env); - + return map; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java index e0decfe72..5d8c617e2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/BaseTemplateModel.java @@ -43,8 +43,8 @@ public abstract class BaseTemplateModel { servletContext = context; } -// public String dump() { -// return toString(); // fallback when subclass doesn't define a class-specific dump() -// } + public String dump() { + return toString(); // fallback when subclass doesn't define a class-specific dump() + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/files/Files.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/files/Files.java index e742ea9cc..f9300bb22 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/files/Files.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/files/Files.java @@ -75,6 +75,10 @@ public abstract class Files extends BaseTemplateModel { return tags; } + public String dump() { + return list.toString(); + } + protected abstract String getTag(String url); } diff --git a/webapp/web/css/dump.css b/webapp/web/css/dump.css index 411080e52..e8d70ae92 100644 --- a/webapp/web/css/dump.css +++ b/webapp/web/css/dump.css @@ -24,6 +24,11 @@ margin: 1em 0; } +.dump ol li, +.dump ul li { + margin-bottom: .5em; +} + .dump .var p { margin-bottom: .3em; } @@ -33,11 +38,6 @@ margin-left: 1.5em; } -.dump .directive ol li, -.dump .directive ul li { - margin-bottom: .5em; -} - .dump .directive ol li { list-style: decimal inside none; } \ No newline at end of file diff --git a/webapp/web/templates/freemarker/body/partials/dump/dump-tm.ftl b/webapp/web/templates/freemarker/body/partials/dump/dump-tm.ftl deleted file mode 100644 index 841052add..000000000 --- a/webapp/web/templates/freemarker/body/partials/dump/dump-tm.ftl +++ /dev/null @@ -1,25 +0,0 @@ -<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> - -<#-- Template for dumping the value template model object --> - - -<#if properties?has_content> -

Property values

-
    - <#list properties?keys as property> -
  • ${property}: ${properties[property]?html}
  • - -
- - -<#if methods?has_content> -

Methods

-
    - <#list methods as method> -
  • ${method}
  • - -
- - - - diff --git a/webapp/web/templates/freemarker/body/partials/dump/dump-var.ftl b/webapp/web/templates/freemarker/body/partials/dump/dump-var.ftl index e23cae502..57f834d35 100644 --- a/webapp/web/templates/freemarker/body/partials/dump/dump-var.ftl +++ b/webapp/web/templates/freemarker/body/partials/dump/dump-var.ftl @@ -3,12 +3,32 @@ <#-- Template for dumping a template variable -->
-

Variable name: ${var}

+

Variable name: ${var}

<#if value??>

Type: ${type}

-
Value: ${value}
+

Value: ${value}

+ + <#-- Template model objects --> + <#if properties?has_content> +

Properties:

+
    + <#list properties?keys as property> +
  • ${property}: ${properties[property]?html}
  • + +
+ + + <#if methods?has_content> +

Methods:

+
    + <#list methods as method> +
  • ${method}
  • + +
+ + <#else> -

Variable is undefined in the data model

+

Value: null