001 // Copyright 2007 by Basil Vandegriend. All rights reserved.
002
003 package com.basilv.envgen;
004
005 import java.util.HashMap;
006 import java.util.Iterator;
007 import java.util.Map;
008
009 import com.basilv.core.Assert;
010
011 import freemarker.template.TemplateHashModel;
012 import freemarker.template.TemplateModel;
013 import freemarker.template.TemplateScalarModel;
014
015 /**
016 * Adapts a Map of property names and values to Freemarker's TemplateModel interface.
017 * Properties of the form "foo.bar" need special handling, as FreeMarker considers a period
018 * to be a dereference operator, and thus first looks up property "foo", and then in the result looks up
019 * property "bar". So we store these properties in the same fashion.
020 *
021 * This class can represent both a simple string value for a given property, or a map of properties.
022 * This allows it to store the properties "foo.bar=one" and "foo.bar.baz=two" as follows. The property "foo"
023 * is mapped to instance #2 of this class. Instance #2 has property "bar", which maps to instance #3
024 * that holds the string value "one" and holds the property "baz" which maps to instance #4 that just holds
025 * the string value "two".
026 */
027 public class TemplateMapModel implements TemplateHashModel, TemplateScalarModel
028 {
029
030 private Map map = new HashMap();
031 private String stringValue;
032
033 private TemplateMapModel() {
034 }
035
036 public TemplateMapModel(Map properties) {
037 Assert.notNull("properties", properties);
038
039 for (Iterator i = properties.entrySet().iterator(); i.hasNext(); ) {
040 Map.Entry entry = (Map.Entry) i.next();
041 String key = (String) entry.getKey();
042 Assert.notNullOrEmpty("key", key);
043 put(key, (String)entry.getValue());
044
045 }
046 }
047
048 public TemplateMapModel getAsTemplateMapModel(String key) {
049 return (TemplateMapModel) map.get(key);
050 }
051
052 public TemplateModel get(String key) {
053 return getAsTemplateMapModel(key);
054 }
055
056 public boolean isEmpty() {
057 return map.isEmpty();
058 }
059
060 public String getAsString() {
061 return stringValue;
062 }
063
064 private void put(String key, String value) {
065 Assert.notNullOrEmpty("key", key);
066
067 if (key.indexOf(".") != -1) {
068 putDereferencingKey(key, value);
069 } else {
070 putRegularKey(key, value);
071 }
072
073 }
074
075 private void putDereferencingKey(String key, String value) {
076 // Key is of the form foo.bar, which we want to split into the first 'foo' plus the remainder
077 // The remainder may also contain a period, so this recursively calls put.
078 String[] parts = key.split("\\.", 2);
079 Assert.isTrue("Key [" + key + "] was not properly split two parts.", parts.length==2);
080 String firstKey = parts[0];
081 String remainingKey = parts[1];
082
083 TemplateMapModel modelForKey = getModelForKeyCreatingIfNotExists(firstKey);
084 modelForKey.put(remainingKey, value);
085 }
086
087 private void putRegularKey(String key, String value) {
088 TemplateMapModel modelForKey = getModelForKeyCreatingIfNotExists(key);
089 modelForKey.stringValue = value;
090 }
091
092 private TemplateMapModel getModelForKeyCreatingIfNotExists(String key) {
093
094 TemplateMapModel modelForKey = (TemplateMapModel) map.get(key);
095
096 if (modelForKey == null) {
097 modelForKey = new TemplateMapModel();
098 map.put(key, modelForKey);
099 }
100 return modelForKey;
101 }
102
103 }