diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DumpTestController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DumpTestController.java new file mode 100644 index 000000000..813c9f34d --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/DumpTestController.java @@ -0,0 +1,253 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.freemarker; + +import java.sql.Time; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.time.DateUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; +import freemarker.ext.beans.BeansWrapper; +import freemarker.template.SimpleCollection; +import freemarker.template.TemplateModelException; + +/** + * Test of dump directives + * @author rjy7 + * + */ +public class DumpTestController extends FreemarkerHttpServlet { + + private static final long serialVersionUID = 1L; + private static final Log log = LogFactory.getLog(TestController.class); + private static final String TEMPLATE_DEFAULT = "test.ftl"; + + @Override + protected ResponseValues processRequest(VitroRequest vreq) { + //Portal portal = vreq.getPortal(); + + Map body = new HashMap(); + + body.put("title", "Freemarker Test"); + + body.put("dog", "Rover"); + body.put("int", 7); + body.put("bool", false); + body.put("now", new Date()); + + java.sql.Date date = new java.sql.Date(1302297332043L); + body.put("date", date); + + Time time = new Time(1302297332043L); + body.put("time", time); + + Timestamp ts = new Timestamp(1302297332043L); + body.put("timestamp", ts); + + // List of strings + List fruit = new ArrayList(); + fruit.add("apples"); + fruit.add("bananas"); + fruit.add("peaches"); + body.put("fruit", fruit); + + // Mixed list + List mixedList = new ArrayList(); + + String myString = "apples"; + mixedList.add(myString); + + int myInt = 4; + mixedList.add(myInt); + + boolean myBool = true; + mixedList.add(myBool); + + List myList = new ArrayList(); + myList.add("dog"); + myList.add("cat"); + myList.add("elephant"); + mixedList.add(myList); + body.put("mixedList", mixedList); + + // Collection (non-indexable) + Set odds = new HashSet(); + for (int i=0; i <= 10; i++) { + if (i % 2 == 1) { + odds.add(i); + } + } + body.put("oddNums", new SimpleCollection(odds)); + + // String-string map + Map myMap = new HashMap(); + myMap.put("Albany", "New York"); + myMap.put("St. Paul", "Minnesota"); + myMap.put("Austin", "Texas"); + myMap.put("Sacramento", "California"); + myMap.put("Richmond", "Virginia"); + body.put("capitals", myMap); + + + // Mixed map + Map mixedMap = new HashMap(); + + mixedMap.put("myString", myString); + mixedMap.put("myBoolean", myBool); + mixedMap.put("myNumber", myInt); + Date myDate = new Date(); + mixedMap.put("myDate", myDate); + mixedMap.put("myList", myList); + mixedMap.put("capitals", myMap); + body.put("mixedMap", mixedMap); + + // Java object + Employee jdoe = getEmployee(); + body.put("employeeLimited", jdoe); + try { + body.put("employeeInvisible", wrap(jdoe, BeansWrapper.EXPOSE_NOTHING)); + body.put("employeeFull", wrap(jdoe, BeansWrapper.EXPOSE_SAFE)); + } catch (TemplateModelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return new TemplateResponseValues(TEMPLATE_DEFAULT, body); + } + + @Override + protected String getTitle(String siteName, VitroRequest vreq) { + return "Test"; + } + + public static class Employee { + + private static int count = 0; + + private String firstName; + private String lastName; + private String nickname; + private Date birthdate; + private boolean married; + private int id; + private String middleName; + private List favoriteColors; + private Employee supervisor; + private float salary; + + Employee(String firstName, String lastName, int id, Date birthdate) { + this.firstName = firstName; + this.lastName = lastName; + this.middleName = null; // test a null value + this.birthdate = birthdate; + this.married = true; + this.id = id; + this.nickname = ""; + this.favoriteColors = new ArrayList(); + count++; + } + + protected void setSupervisor(Employee supervisor) { + this.supervisor = supervisor; + } + + void setSalary(float salary) { + this.salary = salary; + } + + public void setNickname(String nickname) { + this.nickname = nickname; + } + + public void setFavoriteColors(String...colors) { + for (String color : colors) { + favoriteColors.add(color); + } + } + + float getSalary() { + return salary; + } + + public static int getEmployeeCount() { + return count; + } + + /* Public accessor methods for templates */ + + public String getFullName() { + return firstName + " " + lastName; + } + + public String getName(String which) { + return which == "first" ? firstName : lastName; + } + + public String getMiddleName() { + return middleName; + } + + public String getNickname() { + return nickname; + } + + public Date getBirthdate() { + return birthdate; + } + + public int getId() { + return id; + } + + public boolean isMarried() { + return married; + } + + @Deprecated + public int getFormerId() { + return id % 10000; + } + + public Employee getSupervisor() { + return supervisor; + } + + public List getFavoriteColors() { + return favoriteColors; + } + } + + private Employee getEmployee() { + + Calendar c = Calendar.getInstance(); + c.set(1982, Calendar.MAY, 5); + c = DateUtils.truncate(c, Calendar.DATE); + Employee jdoe = new Employee("John", "Doe", 34523, c.getTime()); + jdoe.setFavoriteColors("blue", "green"); + jdoe.setSalary(65000); + + c.clear(); + c.set(1975, Calendar.OCTOBER, 25); + c = DateUtils.truncate(c, Calendar.DATE); + Employee jsmith = new Employee("Jane", "Smith", 78234, c.getTime()); + jsmith.setFavoriteColors("red", "orange"); + + jdoe.setSupervisor(jsmith); + + return jdoe; + } +} + diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index dd77f61cc..3e9a94432 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -255,7 +255,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { return UrlBuilder.getUrl(path); } - protected TemplateModel wrap(int exposureLevel, Object obj) throws TemplateModelException { + protected TemplateModel wrap(Object obj, int exposureLevel) throws TemplateModelException { BeansWrapper wrapper = getBeansWrapper(exposureLevel); return wrapper.wrap(obj); } @@ -271,7 +271,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { // instead of the configuration's object wrapper, which doesn't. The templates can // add stylesheets and scripts to the lists by calling their add() methods. try { - return wrap(BeansWrapper.EXPOSE_SAFE, new Tags()); + return wrap(new Tags(), BeansWrapper.EXPOSE_SAFE); } catch (TemplateModelException e) { log.error("Error creating Tags template model"); return null; diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java index 417294876..6a3cc9c5e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/IndividualController.java @@ -133,7 +133,7 @@ public class IndividualController extends FreemarkerHttpServlet { * This is still safe, because we are only putting BaseTemplateModel objects * into the data model: no real data can be modified. */ - body.put("individual", wrap(BeansWrapper.EXPOSE_SAFE, itm)); + body.put("individual", wrap(itm, BeansWrapper.EXPOSE_SAFE)); body.put("headContent", getRdfLinkTag(itm)); String template = getIndividualTemplate(individual, vreq); diff --git a/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java b/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java index 268a78d08..c7e97ec5a 100644 --- a/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java +++ b/webapp/test/freemarker/ext/dump/DumpDirectiveTest.java @@ -1011,7 +1011,7 @@ public class DumpDirectiveTest { // Properties SortedMap propertiesExpectedDump = new TreeMap(); - if (exposureLevel != BeansWrapper.EXPOSE_NOTHING) { + if (exposureLevel < BeansWrapper.EXPOSE_NOTHING) { Map birthdateExpectedDump = new HashMap(); birthdateExpectedDump.put(Key.TYPE.toString(), Type.DATE); @@ -1078,7 +1078,7 @@ public class DumpDirectiveTest { private List getEmployeeMethodsExpectedDump(int exposureLevel) { List expectedDump = new ArrayList(); - if (exposureLevel == BeansWrapper.EXPOSE_SAFE || exposureLevel == BeansWrapper.EXPOSE_ALL) { + if (exposureLevel <= BeansWrapper.EXPOSE_SAFE) { expectedDump.add("getEmployeeCount"); expectedDump.add("getName(String)"); expectedDump.add("setFavoriteColors(Strings)"); @@ -1095,7 +1095,7 @@ public class DumpDirectiveTest { SortedMap propertiesExpectedDump = new TreeMap(); // Properties - if (exposureLevel != BeansWrapper.EXPOSE_NOTHING) { + if (exposureLevel < BeansWrapper.EXPOSE_NOTHING) { Map birthdateExpectedDump = new HashMap(); birthdateExpectedDump.put(Key.TYPE.toString(), Type.DATE); diff --git a/webapp/web/templates/freemarker/body/partials/dump/dump1.ftl b/webapp/web/templates/freemarker/body/partials/dump/dump1.ftl index 9edf33cd9..17fa26fd6 100644 --- a/webapp/web/templates/freemarker/body/partials/dump/dump1.ftl +++ b/webapp/web/templates/freemarker/body/partials/dump/dump1.ftl @@ -31,6 +31,10 @@ div.dump { .dump ul li.item .value { margin-left: 1.5em; } + +.dump ul.methods li { + margin-bottom: .25em; +}
@@ -44,40 +48,62 @@ div.dump {
    <#list dump?keys as key>
  • -

    Variable name: ${key}

    - <@doMap dump[key] /> +

    Variable name: ${key}

    + + <#local type = dump[key].type> + <#if type == "Directive" || type == "Method"> + <@doMethod dump[key] /> + <#else> + <@doTypeAndValue dump[key] /> +
-<#macro doMap map> - <#if map.type?has_content> -

Type: ${map.type}

+<#macro doTypeAndValue map> + <#local type = map.type!> + <#if type?has_content> +

Type: ${type}

<#if map.dateType?has_content>

Date type: ${map.dateType}

- - <#if map.type == "Directive" || map.type == "Method"> - <@doHelp map.help! /> - <#else> - <@doValue map.type map.value! /> - - + + <#local value = map.value!> + <#if value??> +
+ <#if type?contains(".")><@doObjectValue value /> + <#elseif value?is_sequence><@doSequenceValue value type /> + <#elseif value?is_hash_ex><@doMapValue value /> + <#else><@doScalarValue value /> + +
+ -<#macro doValue type value=""> -
- <#if value??> - <#if value?is_sequence><@doSequenceValue value type/> - <#elseif value?is_hash_ex><@doMapValue value /> - <#else><@doScalarValue type value /> - - -
+<#macro doObjectValue obj> + <#if obj.properties?has_content> +

Properties:

+
    + <#list obj.properties?keys as property> + <@liItem> + ${property} => <@divValue><@doTypeAndValue obj.properties[property] /> + + +
+ + + <#if obj.methods?has_content> +

Methods: +

    + <#list obj.methods as method> + <@liItem>${method} + +
+ <#macro doSequenceValue seq type> @@ -85,14 +111,13 @@ div.dump { <#if seq?has_content>
    <#list seq as item> -
  • + <@liItem> <#if type == "Sequence"> Item ${item_index}: - <@valueDiv><@doMap item /> - <#else><@doMap item /> - - -
  • + <@divValue><@doTypeAndValue item /> + <#else><@doTypeAndValue item /> + +
<#else>no values @@ -104,33 +129,35 @@ div.dump { <#if map?has_content>
    <#list map?keys as key> -
  • - ${key} => <@valueDiv><@doMap map[key] /> -
  • + <@liItem> + ${key} => <@divValue><@doTypeAndValue map[key] /> +
<#else>no values -<#macro doScalarValue type value> +<#macro doScalarValue value> Value: - <#if value?is_string || value?is_number>${value} + <#if value?is_string>${value} + <#elseif value?is_number>${value?c} <#elseif value?is_boolean>${value?string} <#elseif value?is_date>${value?string("EEEE, MMMM dd, yyyy hh:mm:ss a zzz")} - <#else>no value -<#macro doHelp help=""> +<#macro doMethod method> +

Type: ${method.type}

+ <#local help = method.help> <#if help?has_content>

Help:

    <#list help?keys as key>
  • <#local value = help[key]> - <@valueDiv> + <@divValue> <#if value?is_string>

    ${key?capitalize}: ${value}

    <#else>

    ${key?capitalize}:

    @@ -146,17 +173,21 @@ div.dump {
- + -<#macro valueDiv> +<#macro divValue>
<#nested>
+<#macro liItem> +
  • <#nested>
  • + + <#-- This will work after we move stylesheets to Configuration sharedVariables ${stylesheets.add('')}