diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DescribeDirective.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DescribeDirective.java index a174802ad..7aa71738d 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DescribeDirective.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/directives/dump/DescribeDirective.java @@ -71,7 +71,7 @@ public class DescribeDirective extends BaseTemplateDirectiveModel { } DumpHelper helper = new DumpHelper(env); - List methods = helper.getMethodsAvailableToTemplate(tm, unwrappedModel.getClass()); + List methods = helper.getMethodsAvailableToTemplate(unwrappedModel.getClass()); List methodDisplayNames = new ArrayList(methods.size()); for (Method m : methods) { methodDisplayNames.add(helper.getMethodDisplayName(m)); 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 dfa3de49d..a1bb8063e 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 @@ -7,11 +7,12 @@ import java.io.Writer; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; - -import javax.servlet.http.HttpServletRequest; +import java.util.SortedMap; +import java.util.TreeMap; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.logging.Log; @@ -21,10 +22,6 @@ import edu.cornell.mannlib.vitro.webapp.utils.StringUtils; import edu.cornell.mannlib.vitro.webapp.web.directives.BaseTemplateDirectiveModel; import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel; 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; @@ -86,7 +83,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) { - map.putAll(getTemplateModelValues(tm, (BaseTemplateModel)unwrappedModel)); + map.putAll(getTemplateModelValues((BaseTemplateModel)unwrappedModel)); type = className; // Can't use this, because tm of (at least some) POJOs are // StringModels, which are both TemplateScalarModels and TemplateHashModels @@ -145,62 +142,34 @@ public class DumpHelper { } } - protected List getMethodsAvailableToTemplate(TemplateModel wrappedModel, Class cls) { - int exposureLevel = getExposureLevel(wrappedModel, cls); - return getMethodsAvailableToTemplate(exposureLevel, cls); - } - - private int getExposureLevel(TemplateModel model, Class cls) { - - int exposureLevel; - // Get the exposure level of the BeansWrapper that wrapped this object. - if (model instanceof BeanModel) { - exposureLevel = WrapperExtractor.getWrapperExposureLevel((BeanModel) model); - log.debug("Exposure level for class " + cls.getCanonicalName() + " wrapped as " + model.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"); - BeansWrapper wrapper = (BeansWrapper) config.getObjectWrapper(); - exposureLevel = WrapperExtractor.getWrapperExposureLevel(wrapper); - log.debug("Class " + cls.getCanonicalName() + " wrapped as " + model.getClass() + " uses default exposure level " + exposureLevel); - } - - return exposureLevel; - } - - private List getMethodsAvailableToTemplate(int exposureLevel, Class cls) { + protected List getMethodsAvailableToTemplate(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(exposureLevel, cls); - methods.addAll(getMethodsAvailableToTemplate(exposureLevel, cls.getSuperclass())); + methods = getDeclaredPublicMethods(cls); + methods.addAll(getMethodsAvailableToTemplate(cls.getSuperclass())); } return methods; } - - private List getDeclaredMethodsAvailableToTemplate(int exposureLevel, Class cls) { + + private List getDeclaredPublicMethods(Class cls) { List methods = new ArrayList(); Method[] declaredMethods = cls.getDeclaredMethods(); - for (Method method : declaredMethods) { - int mod = method.getModifiers(); + for (Method m : declaredMethods) { + int mod = m.getModifiers(); if (Modifier.isPublic(mod) && !Modifier.isStatic(mod)) { - Class[] params = method.getParameterTypes(); - // 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); + // If the method takes args, make sure the BeanWrapper used makes this method visible. + // RY It may not be possible to determine this. + methods.add(m); } } return methods; } + protected String getMethodDisplayName(Method method) { String methodName = method.getName(); Class[] paramTypes = method.getParameterTypes(); @@ -221,19 +190,14 @@ public class DumpHelper { } return methodName; - } + } - private Map getTemplateModelValues(TemplateModel wrappedModel, BaseTemplateModel unwrappedModel) { - int exposureLevel = getExposureLevel(wrappedModel, unwrappedModel.getClass()); - return getTemplateModelValues(unwrappedModel, exposureLevel); - } - - private Map getTemplateModelValues(BaseTemplateModel model, int exposureLevel) { + private Map getTemplateModelValues(BaseTemplateModel model) { Map map = new HashMap(); map.put("value", model.dump()); - List publicMethods = getMethodsAvailableToTemplate(exposureLevel, model.getClass()); - Map properties = new HashMap(); + List publicMethods = getMethodsAvailableToTemplate(model.getClass()); + SortedMap properties = new TreeMap(); List methods = new ArrayList(); for (Method method : publicMethods) { // Don't include the dump method, since this is used above to provide the value of the object. @@ -248,13 +212,18 @@ public class DumpHelper { Object result = method.invoke(model); String value; if (result == null) { - value = "null"; + value = "null"; // distinguish a null from an empty string } else if (result instanceof BaseTemplateModel) { - value = getTemplateModelDump((BaseTemplateModel)result, exposureLevel); + value = getTemplateModelDump((BaseTemplateModel)result); } else { - // Don't use ?html in the template, because then the output of - // getTemplateModelDump, which is html, gets escaped too. - value = StringEscapeUtils.escapeHtml(result.toString()); + value = result.toString(); + if (value.isEmpty()) { + value = "(empty string)"; + } else { + // Don't use ?html in the template, because then the output of + // getTemplateModelDump, which is html, gets escaped too. + value = StringEscapeUtils.escapeHtml(value); + } } properties.put(key, value); } catch (Exception e) { @@ -266,12 +235,13 @@ public class DumpHelper { map.put("type", model.getClass().getName()); map.put("properties", properties); + Collections.sort(methods); map.put("methods", methods); return map; } - private String getTemplateModelDump(BaseTemplateModel model, int exposureLevel) { - Map map = getTemplateModelValues(model, exposureLevel); + private String getTemplateModelDump(BaseTemplateModel model) { + Map map = getTemplateModelValues(model); return BaseTemplateDirectiveModel.processTemplateToString("dump-var.ftl", map, env); } diff --git a/webapp/src/freemarker/ext/beans/WrapperExtractor.java b/webapp/src/freemarker/ext/beans/WrapperExtractor.java deleted file mode 100644 index 7ed256885..000000000 --- a/webapp/src/freemarker/ext/beans/WrapperExtractor.java +++ /dev/null @@ -1,27 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package freemarker.ext.beans; - -/** - * Class to extract information about the wrapper used to wrap an object in - * the template model. This is something of a hack: the class belongs to - * package freemarker.ext.beans so we can get at protected members of - * BeanModel and BeansWrapper. The Freemarker API unfortunately provides - * no way to get the wrapper that is used to wrap an object in the - * template data model. - */ -public class WrapperExtractor { - - public static BeansWrapper getWrapper(BeanModel model) { - return model.wrapper; - } - - public static int getWrapperExposureLevel(BeanModel model) { - return model.wrapper.getExposureLevel(); - } - - public static int getWrapperExposureLevel(BeansWrapper wrapper) { - return wrapper.getExposureLevel(); - } - -} diff --git a/webapp/web/css/dump.css b/webapp/web/css/dump.css index 8e929400b..adab1cbd0 100644 --- a/webapp/web/css/dump.css +++ b/webapp/web/css/dump.css @@ -42,6 +42,7 @@ list-style: decimal inside none; } -.var .var { +.dump .var .var, +.dump.datamodel .var .var { margin-left: 1.5em; } diff --git a/webapp/web/templates/freemarker/body/test.ftl b/webapp/web/templates/freemarker/body/test.ftl index 520140eef..c711808d1 100644 --- a/webapp/web/templates/freemarker/body/test.ftl +++ b/webapp/web/templates/freemarker/body/test.ftl @@ -4,6 +4,5 @@

${title}

-<@dumpAll />