1 /*
2 * TemplateBinding.java
3 */
4
5 package net.sf.tacos.binding;
6
7 import org.apache.commons.lang.StringUtils;
8 import org.apache.hivemind.Location;
9 import org.apache.tapestry.IBinding;
10 import org.apache.tapestry.IComponent;
11 import org.apache.tapestry.binding.AbstractBinding;
12 import org.apache.tapestry.binding.BindingFactory;
13 import org.apache.tapestry.coerce.ValueConverter;
14
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.Map;
18
19 /**
20 * An implementation of Tapestry {@link IBinding} that provides a binding
21 * similar to {@link org.apache.tapestry.binding.LiteralBinding} with the
22 * additional benefit that it can also include variables.
23 *
24 * The variables should be put into <code>${}</code> .<br/>
25 *
26 * Here's an example:
27 * <code>
28 * <binding name="effects" value="template:some id is ${currNote.id}."/>
29 * </code>
30 * <p/>
31 * <p/>
32 * The binding can also get its content from resource bundles. It will still
33 * go on and process it - looking for variables to substitute.<br/>
34 * Example:
35 * <code>
36 * <binding name="effects" value="template:%message-code"/>
37 * </code>
38 *
39 */
40 public class TemplateBinding extends AbstractBinding
41 {
42 /**
43 * The root object against which the nested property name is evaluated.
44 */
45 private final IComponent root;
46 /**
47 * The expression that have variables, as a string.
48 */
49 private String expression;
50 /**
51 * cache the variable expression and it's compiled binding.
52 */
53 private Map variableBindings;
54 /**
55 * the BindingFactory for creating the inside variable IBinding.
56 */
57 private BindingFactory nestedBindingFactory;
58
59 /**
60 * constructor
61 *
62 * @param description
63 * @param location
64 * @param valueConverter
65 * @param root The root object against which the nested property name is evaluated.
66 * @param expression plain string or message code in page's specification file.
67 * @param nestedBindingFactory Internal used BindingFactory
68 */
69 public TemplateBinding(String description, Location location, ValueConverter valueConverter,
70 IComponent root, String expression, BindingFactory nestedBindingFactory)
71 {
72 super(description, valueConverter, location);
73 this.root = root;
74 this.expression = extractExpression(expression);
75 this.nestedBindingFactory = nestedBindingFactory;
76 buildingVariableBindings();
77 }
78
79 /**
80 * build variable binding map.
81 */
82 private void buildingVariableBindings()
83 {
84 if (variableBindings == null) {
85 variableBindings = new HashMap();
86 }
87 String least = expression;
88 int start;
89 while ((start = least.indexOf("${")) != -1) {
90 least = least.substring(start);
91 int length = least.indexOf("}");
92 String innerExp = least.substring(2, length);
93 IBinding expBinding = nestedBindingFactory.createBinding(root, getDescription(), innerExp, getLocation());
94 variableBindings.put("${" + innerExp + "}", expBinding);
95 least = least.substring(length + 1);
96 }
97 }
98
99 /**
100 * Extract expression if it is indicated as message code.
101 *
102 * @param expr
103 * @return real evaluated expression.
104 */
105 private String extractExpression(String expr)
106 {
107 if (expr.startsWith("%")) {
108 String key = expr.substring(1);
109 return root.getMessages().getMessage(key);
110 }
111 return expr;
112 }
113
114 /**
115 * Evaluate the value with inside variables.
116 *
117 * @return binding value
118 */
119 public Object getObject()
120 {
121 String value = expression;
122 Iterator it = variableBindings.entrySet().iterator();
123 while (it.hasNext()) {
124 Map.Entry entry = (Map.Entry) it.next();
125 String key = (String) entry.getKey();
126 IBinding exp = (IBinding) entry.getValue();
127 String replacement = "";
128 Object object = exp.getObject();
129 if (object != null) {
130 replacement = object.toString();
131 }
132 value = StringUtils.replace(value, key, replacement);
133 }
134 return value;
135 }
136
137 /**
138 * Should be variant because of inside ognl expression.
139 *
140 * @return indicate it is variant.
141 * @see org.apache.tapestry.IBinding#isInvariant()
142 */
143 public boolean isInvariant()
144 {
145 return false;
146 }
147 }