diff --git a/webapp/src/freemarker/ext/dump/BaseDumpDirective.java b/webapp/src/freemarker/ext/dump/BaseDumpDirective.java index c26084fc5..73e0dffb3 100644 --- a/webapp/src/freemarker/ext/dump/BaseDumpDirective.java +++ b/webapp/src/freemarker/ext/dump/BaseDumpDirective.java @@ -112,78 +112,82 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { } } - - protected Map getTemplateVariableData(String varName, Environment env) + protected Map getTemplateVariableDump(String varName, Environment env) throws TemplateModelException { - + + TemplateHashModel dataModel = env.getDataModel(); + TemplateModel model = dataModel.get(varName); + return getTemplateVariableDump(varName, model); + } + + protected Map getTemplateVariableDump(String varName, TemplateModel model) + throws TemplateModelException { + Map map = new HashMap(); map.put(Key.NAME.toString(), varName); - TemplateHashModel dataModel = env.getDataModel(); - TemplateModel model = dataModel.get(varName); - // Don't return null if model == null. We still want to send the map to the template. if (model != null) { // TemplateMethodModel and TemplateDirectiveModel objects can only be // included in the data model at the top level. if (model instanceof TemplateMethodModel) { - map.putAll( getTemplateModelData( ( TemplateMethodModel)model, varName ) ); + map.putAll( getTemplateModelDump( ( TemplateMethodModel)model, varName ) ); } else if (model instanceof TemplateDirectiveModel) { - map.putAll( getTemplateModelData( ( TemplateDirectiveModel)model, varName ) ); + map.putAll( getTemplateModelDump( ( TemplateDirectiveModel)model, varName ) ); } else { - map.putAll(getData(model)); + map.putAll(getDump(model)); } } - return map; + return map; } - private Map getData(TemplateModel model) throws TemplateModelException { + private Map getDump(TemplateModel model) throws TemplateModelException { Map map = new HashMap(); // Don't return null if model == null. We still want to send the map to the template. if (model != null) { if ( model instanceof TemplateSequenceModel ) { - map.putAll( getTemplateModelData( ( TemplateSequenceModel)model ) ); + map.putAll( getTemplateModelDump( ( TemplateSequenceModel)model ) ); } else if ( model instanceof TemplateNumberModel ) { - map.putAll( getTemplateModelData( (TemplateNumberModel)model ) ); + map.putAll( getTemplateModelDump( (TemplateNumberModel)model ) ); } else if ( model instanceof TemplateBooleanModel ) { - map.putAll( getTemplateModelData( (TemplateBooleanModel)model ) ); + map.putAll( getTemplateModelDump( (TemplateBooleanModel)model ) ); } else if ( model instanceof TemplateDateModel ) { - map.putAll( getTemplateModelData( (TemplateDateModel)model ) ); + map.putAll( getTemplateModelDump( (TemplateDateModel)model ) ); } else if ( model instanceof TemplateCollectionModel ) { - map.putAll( getTemplateModelData( ( TemplateCollectionModel)model ) ); + map.putAll( getTemplateModelDump( ( TemplateCollectionModel)model ) ); } else if ( model instanceof StringModel ) { Object unwrappedModel = DeepUnwrap.permissiveUnwrap(model); if (unwrappedModel instanceof String) { - map.putAll( getTemplateModelData( (TemplateScalarModel)model ) ); + map.putAll( getTemplateModelDump( (TemplateScalarModel)model ) ); } else { - map.putAll( getTemplateModelData( ( TemplateHashModelEx)model ) ); + map.putAll( getTemplateModelDump( ( TemplateHashModelEx)model ) ); } } else if ( model instanceof TemplateScalarModel ) { - map.putAll( getTemplateModelData( (TemplateScalarModel)model ) ); + map.putAll( getTemplateModelDump( (TemplateScalarModel)model ) ); } else if ( model instanceof TemplateHashModelEx ) { - map.putAll( getTemplateModelData( ( TemplateHashModelEx)model ) ); + map.putAll( getTemplateModelDump( ( TemplateHashModelEx)model ) ); } else if (model instanceof TemplateHashModel ) { - map.putAll( getTemplateModelData( ( TemplateHashModel)model ) ); + map.putAll( getTemplateModelDump( ( TemplateHashModel)model ) ); // Nodes and transforms not included here } else { - map.putAll( getTemplateModelData( (TemplateModel)model ) ); + map.putAll( getTemplateModelDump( (TemplateModel)model ) ); } } else { map.put(Key.VALUE.toString(), "null"); @@ -192,28 +196,28 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return map; } - private Map getTemplateModelData(TemplateScalarModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateScalarModel model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.STRING); map.put(Key.VALUE.toString(), model.getAsString()); return map; } - private Map getTemplateModelData(TemplateBooleanModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateBooleanModel model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.BOOLEAN); map.put(Key.VALUE.toString(), model.getAsBoolean()); return map; } - private Map getTemplateModelData(TemplateNumberModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateNumberModel model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.NUMBER); map.put(Key.VALUE.toString(), model.getAsNumber()); return map; } - private Map getTemplateModelData(TemplateDateModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateDateModel model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.DATE); int dateType = model.getDateType(); @@ -238,7 +242,7 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return map; } - private Map getTemplateModelData(TemplateHashModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateHashModel model) throws TemplateModelException { // The data model is a hash; when else do we get here? log.debug("Dumping model " + model); Map map = new HashMap(); @@ -247,32 +251,32 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return map; } - private Map getTemplateModelData(TemplateSequenceModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateSequenceModel model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.SEQUENCE); int itemCount = model.size(); List> items = new ArrayList>(itemCount); for ( int i = 0; i < itemCount; i++ ) { TemplateModel item = model.get(i); - items.add(getData(item)); + items.add(getDump(item)); } map.put(Key.VALUE.toString(), items); return map; } - private Map getTemplateModelData(TemplateHashModelEx model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateHashModelEx model) throws TemplateModelException { Object unwrappedModel = DeepUnwrap.permissiveUnwrap(model); // This seems to be the most reliable way of distinguishing a wrapped map from a wrapped object. // A map may be wrapped as a SimpleHash, and an object may be wrapped as a StringModel, but they could // be wrapped as other types as well. if ( unwrappedModel instanceof Map ) { - return getMapData(model); + return getMapDump(model); } // Java objects are wrapped as TemplateHashModelEx-s. - return getObjectData(model, unwrappedModel); + return getObjectDump(model, unwrappedModel); } - private Map getMapData(TemplateHashModelEx model) throws TemplateModelException { + private Map getMapDump(TemplateHashModelEx model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.HASH_EX); SortedMap items = new TreeMap(); @@ -281,13 +285,13 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { while (iModel.hasNext()) { String key = iModel.next().toString(); TemplateModel value = model.get(key); - items.put(key, getData(value)); + items.put(key, getDump(value)); } map.put(Key.VALUE.toString(), items); return map; } - private Map getObjectData(TemplateHashModelEx model, Object object) throws TemplateModelException { + private Map getObjectDump(TemplateHashModelEx model, Object object) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), object.getClass().getName()); @@ -344,7 +348,7 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { // The method is available as a property if (keySet.contains(propertyName)) { TemplateModel value = model.get(propertyName); - properties.put(propertyName, getData(value)); + properties.put(propertyName, getDump(value)); continue; } } @@ -391,27 +395,27 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return StringUtils.uncapitalize(keyName); } - private Map getTemplateModelData(TemplateCollectionModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateCollectionModel model) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.COLLECTION); List> items = new ArrayList>(); TemplateModelIterator iModel = model.iterator(); while (iModel.hasNext()) { TemplateModel m = iModel.next(); - items.add(getData(m)); + items.add(getDump(m)); } map.put(Key.VALUE.toString(), items); return map; } - private Map getTemplateModelData(TemplateMethodModel model, String varName) throws TemplateModelException { + private Map getTemplateModelDump(TemplateMethodModel model, String varName) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.METHOD); map.put("help", getHelp(model, varName)); return map; } - private Map getTemplateModelData(TemplateDirectiveModel model, String varName) throws TemplateModelException { + private Map getTemplateModelDump(TemplateDirectiveModel model, String varName) throws TemplateModelException { Map map = new HashMap(); map.put(Key.TYPE.toString(), Type.DIRECTIVE); map.put("help", getHelp(model, varName)); @@ -439,7 +443,7 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return map; } - private Map getTemplateModelData(TemplateModel model) throws TemplateModelException { + private Map getTemplateModelDump(TemplateModel model) throws TemplateModelException { // One of the above cases should have applied. Track whether this actually occurs. log.debug("Found model with no known type"); Map map = new HashMap(); @@ -449,7 +453,7 @@ public abstract class BaseDumpDirective implements TemplateDirectiveModel { return map; } - protected void dump(String templateName, Map map, String modelName, Environment env) + protected void dump(String templateName, Map map, Environment env) throws TemplateException, IOException { Template template = env.getConfiguration().getTemplate(templateName); diff --git a/webapp/src/freemarker/ext/dump/DumpAllDirective.java b/webapp/src/freemarker/ext/dump/DumpAllDirective.java new file mode 100644 index 000000000..beda35f49 --- /dev/null +++ b/webapp/src/freemarker/ext/dump/DumpAllDirective.java @@ -0,0 +1,76 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package freemarker.ext.dump; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import freemarker.core.Environment; +import freemarker.template.TemplateDirectiveBody; +import freemarker.template.TemplateException; +import freemarker.template.TemplateHashModel; +import freemarker.template.TemplateModel; +import freemarker.template.TemplateModelException; +import freemarker.template.utility.DeepUnwrap; + +public class DumpAllDirective extends BaseDumpDirective { + + @SuppressWarnings("unused") + private static final Log log = LogFactory.getLog(DumpDirective.class); + + @SuppressWarnings("rawtypes") + @Override + public void execute(Environment env, Map params, TemplateModel[] loopVars, + TemplateDirectiveBody body) throws TemplateException, IOException { + + if (params.size() != 0) { + throw new TemplateModelException( + "The dumpAll directive doesn't allow parameters."); + } + + if (loopVars.length != 0) { + throw new TemplateModelException( + "The dump directive doesn't allow loop variables."); + } + + if (body != null) { + throw new TemplateModelException( + "The dump directive doesn't allow nested content."); + } + + TemplateHashModel dataModel = env.getDataModel(); + // Need to unwrap in order to iterate through the variables + @SuppressWarnings("unchecked") + Map unwrappedDataModel = (Map) DeepUnwrap.permissiveUnwrap(dataModel); + List varNames = new ArrayList(unwrappedDataModel.keySet()); + Collections.sort(varNames); + + // *** RY Change data structure so it's + // "employee" => { type =>..., value => ...} + // rather than { name => "employee", type => ..., value => ...} + // Then this will be a SortedMap + // Otherwise we need a Comparator to sort on the "name" key. Yuck! + // The first data structure seems more natural + List> models = new ArrayList>(); + for (String varName : varNames) { + models.add(getTemplateVariableDump(varName, dataModel.get(varName))); + } + + Map map = new HashMap(); + map.put("templateName", env.getTemplate().getName()); + + + map.put("models", models); + + dump("dumpAll.ftl", map, env); + } + + +} diff --git a/webapp/src/freemarker/ext/dump/DumpDirective.java b/webapp/src/freemarker/ext/dump/DumpDirective.java index 8a3730868..45ce17f66 100644 --- a/webapp/src/freemarker/ext/dump/DumpDirective.java +++ b/webapp/src/freemarker/ext/dump/DumpDirective.java @@ -43,8 +43,8 @@ public class DumpDirective extends BaseDumpDirective { String varName = ((SimpleScalar)o).getAsString(); Map map = new HashMap(); - map.put("var", getTemplateVariableData(varName, env)); + map.put("var", getTemplateVariableDump(varName, env)); - dump("dumpvar.ftl", map, varName, env); + dump("dumpvar.ftl", map, env); } }