1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.tiles.definition.pattern;
23
24 import java.text.MessageFormat;
25 import java.util.LinkedHashMap;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
32
33 import org.apache.tiles.Attribute;
34 import org.apache.tiles.Definition;
35 import org.apache.tiles.Expression;
36 import org.apache.tiles.ListAttribute;
37
38 /***
39 * Utilities for pattern matching and substitution.
40 *
41 * @version $Rev: 921998 $ $Date: 2010-03-11 20:58:08 +0100 (gio, 11 mar 2010) $
42 * @since 2.2.0
43 */
44 public final class PatternUtil {
45
46 /***
47 * The root locale. Notice that this is a replacement for Locale.ROOT for
48 * Java 1.6.
49 */
50 private static final Locale ROOT_LOCALE = new Locale("", "");
51
52 /*** Pattern to find {.*} occurrences that do not match {[0-9]+} so to prevent MessageFormat from crashing.
53 */
54 private static final Pattern INVALID_FORMAT_ELEMENT = Pattern.compile("//Q{//E[//D^}]+//Q}//E");
55
56 /***
57 * Private constructor to avoid instantiation.
58 */
59 private PatternUtil() {
60 }
61
62 /***
63 * Creates a definition given its representation with wildcards and
64 * attribute values with placeholders, replacing real values into
65 * placeholders.
66 *
67 * @param d The definition to replace.
68 * @param name The name of the definition to be created.
69 * @param vars The variables to be substituted.
70 * @return The definition that can be rendered.
71 * @since 2.2.0
72 */
73 public static Definition replacePlaceholders(Definition d, String name,
74 Object... vars) {
75 Definition nudef = new Definition();
76
77 nudef.setExtends(replace(d.getExtends(), vars));
78 nudef.setName(name);
79 nudef.setPreparer(replace(d.getPreparer(), vars));
80 Attribute templateAttribute = d.getTemplateAttribute();
81 if (templateAttribute != null) {
82 nudef.setTemplateAttribute(replaceVarsInAttribute(
83 templateAttribute, vars));
84 }
85
86 Set<String> attributeNames = d.getLocalAttributeNames();
87 if (attributeNames != null && !attributeNames.isEmpty()) {
88 for (String attributeName : attributeNames) {
89 Attribute attr = d.getLocalAttribute(attributeName);
90 Attribute nuattr = replaceVarsInAttribute(attr, vars);
91
92 nudef.putAttribute(replace(attributeName, vars), nuattr);
93 }
94 }
95
96 attributeNames = d.getCascadedAttributeNames();
97 if (attributeNames != null && !attributeNames.isEmpty()) {
98 for (String attributeName : attributeNames) {
99 Attribute attr = d.getCascadedAttribute(attributeName);
100 Attribute nuattr = replaceVarsInAttribute(attr, vars);
101
102 nudef.putAttribute(replace(attributeName, vars), nuattr, true);
103 }
104 }
105
106 return nudef;
107 }
108
109 /***
110 * Creates a new map that contains all the entries of the
111 * <code>defsMap</code> whose keys are contained in <code>keys</code>.
112 *
113 * @param map The map to read.
114 * @param keys The keys to extract.
115 * @param <K> The key of the map.
116 * @param <V> The value of the map.
117 * @return The extracted map.
118 * @since 2.2.1
119 */
120 public static <K, V> Map<K, V> createExtractedMap(Map<K, V> map, Set<K> keys) {
121 Map<K, V> retValue = new LinkedHashMap<K, V>();
122 for (K key : keys) {
123 retValue.put(key, map.get(key));
124 }
125 return retValue;
126 }
127
128 /***
129 * Replaces variables into an attribute.
130 *
131 * @param attr The attribute to be used as a basis, containing placeholders
132 * for variables.
133 * @param vars The variables to replace.
134 * @return A new instance of an attribute, whose properties have been
135 * replaced with variables' values.
136 */
137 private static Attribute replaceVarsInAttribute(Attribute attr,
138 Object... vars) {
139 Attribute nuattr;
140 if (attr instanceof ListAttribute) {
141 nuattr = replaceVarsInListAttribute((ListAttribute) attr, vars);
142 } else {
143 nuattr = replaceVarsInSimpleAttribute(attr, vars);
144 }
145 return nuattr;
146 }
147
148 /***
149 * Replaces variables into a simple (not list) attribute.
150 *
151 * @param attr The attribute to be used as a basis, containing placeholders
152 * for variables.
153 * @param vars The variables to replace.
154 * @return A new instance of an attribute, whose properties have been
155 * replaced with variables' values.
156 */
157 private static Attribute replaceVarsInSimpleAttribute(Attribute attr,
158 Object... vars) {
159 Attribute nuattr;
160 nuattr = new Attribute();
161
162 nuattr.setRole(replace(attr.getRole(), vars));
163 nuattr.setRenderer(attr.getRenderer());
164 Expression expressionObject = attr.getExpressionObject();
165 if (expressionObject != null) {
166 Expression newExpressionObject = Expression
167 .createExpression(replace(expressionObject.getExpression(), vars), expressionObject.getLanguage());
168 nuattr.setExpressionObject(newExpressionObject);
169 }
170
171 Object value = attr.getValue();
172 if (value instanceof String) {
173 value = replace((String) value, vars);
174 }
175 nuattr.setValue(value);
176 return nuattr;
177 }
178
179 /***
180 * Replaces variables into a list attribute.
181 *
182 * @param listAttr The attribute to be used as a basis, containing attributes
183 * that may contain placeholders for variables.
184 * @param vars The variables to replace.
185 * @return A new instance of an attribute, whose properties have been
186 * replaced with variables' values.
187 */
188 @SuppressWarnings("unchecked")
189 private static Attribute replaceVarsInListAttribute(ListAttribute listAttr,
190 Object... vars) {
191 Attribute nuattr;
192 ListAttribute nuListAttr = new ListAttribute();
193 nuListAttr.setInherit(listAttr.isInherit());
194 List<Object> nuItems = (List<Object>) nuListAttr.getValue();
195 for (Object item : (List<Object>) listAttr.getValue()) {
196 if (item instanceof Attribute) {
197 Attribute child = (Attribute) item;
198 child = replaceVarsInAttribute(child, vars);
199 nuItems.add(child);
200 } else {
201
202 nuItems.add(item);
203 }
204 }
205 nuattr = nuListAttr;
206 return nuattr;
207 }
208
209 /***
210 * Replaces a string with placeholders using values of a variable map.
211 *
212 * @param st The string to replace.
213 * @param vars The variables.
214 * @return The replaced string.
215 */
216 private static String replace(String st, Object... vars) {
217 if (st != null && st.indexOf('{') >= 0) {
218
219 Matcher m = INVALID_FORMAT_ELEMENT.matcher(st);
220
221 st = INVALID_FORMAT_ELEMENT.matcher(st).replaceAll("INVALID_FORMAT_ELEMENT");
222
223 st = new MessageFormat(st.replaceAll("'", "'''"), ROOT_LOCALE)
224 .format(vars, new StringBuffer(), null).toString();
225
226 while (m.find()) {
227 st = st.replaceFirst("INVALID_FORMAT_ELEMENT", m.group());
228 }
229 }
230 return st;
231 }
232 }