1/*2 * $Id: PatternUtil.java 1594481 2014-05-14 06:52:35Z mck $3 *4 * Licensed to the Apache Software Foundation (ASF) under one5 * or more contributor license agreements. See the NOTICE file6 * distributed with this work for additional information7 * regarding copyright ownership. The ASF licenses this file8 * to you under the Apache License, Version 2.0 (the9 * "License"); you may not use this file except in compliance10 * with the License. You may obtain a copy of the License at11 *12 * http://www.apache.org/licenses/LICENSE-2.013 *14 * Unless required by applicable law or agreed to in writing,15 * software distributed under the License is distributed on an16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY17 * KIND, either express or implied. See the License for the18 * specific language governing permissions and limitations19 * under the License.20 */2122package org.apache.tiles.definition.pattern;
2324import java.text.MessageFormat;
25import java.util.ArrayList;
26import java.util.LinkedHashMap;
27import java.util.List;
28import java.util.Locale;
29import java.util.Map;
30import java.util.Set;
31import java.util.regex.Matcher;
32import java.util.regex.Pattern;
3334import org.apache.tiles.Attribute;
35import org.apache.tiles.Definition;
36import org.apache.tiles.Expression;
37import org.apache.tiles.ListAttribute;
3839/**40 * Utilities for pattern matching and substitution.41 *42 * @version $Rev: 1594481 $ $Date: 2014-05-14 16:52:35 +1000 (Wed, 14 May 2014) $43 * @since 2.2.044 */45publicfinalclassPatternUtil {
4647/**48 * The root locale. Notice that this is a replacement for Locale.ROOT for49 * Java 1.6.50 */51privatestaticfinal Locale ROOT_LOCALE = new Locale("", "");
5253/** Pattern to find {.*} occurrences that do not match {[0-9]+} so to prevent MessageFormat from crashing.54 */55privatestaticfinal Pattern INVALID_FORMAT_ELEMENT = Pattern.compile("\\{[^}0-9]+\\}");
5657/**58 * Private constructor to avoid instantiation.59 */60privatePatternUtil() {
61 }
6263/**64 * Creates a definition given its representation with wildcards and65 * attribute values with placeholders, replacing real values into66 * placeholders.67 *68 * @param d The definition to replace.69 * @param name The name of the definition to be created.70 * @param varsOrig The variables to be substituted.71 * @return The definition that can be rendered.72 * @since 2.2.073 */74publicstaticDefinition replacePlaceholders(Definition d, String name,
75 Object... varsOrig) {
7677 Object[] vars = replaceNullsWithBlank(varsOrig);
7879Definition nudef = newDefinition();
8081 nudef.setExtends(replace(d.getExtends(), vars));
82 nudef.setName(name);
83 nudef.setPreparer(replace(d.getPreparer(), vars));
84Attribute templateAttribute = d.getTemplateAttribute();
85if (templateAttribute != null) {
86 nudef.setTemplateAttribute(replaceVarsInAttribute(
87 templateAttribute, vars));
88 }
8990 Set<String> attributeNames = d.getLocalAttributeNames();
91if (attributeNames != null && !attributeNames.isEmpty()) {
92for (String attributeName : attributeNames) {
93Attribute attr = d.getLocalAttribute(attributeName);
94Attribute nuattr = replaceVarsInAttribute(attr, vars);
9596 nudef.putAttribute(replace(attributeName, vars), nuattr);
97 }
98 }
99100 attributeNames = d.getCascadedAttributeNames();
101if (attributeNames != null && !attributeNames.isEmpty()) {
102for (String attributeName : attributeNames) {
103Attribute attr = d.getCascadedAttribute(attributeName);
104Attribute nuattr = replaceVarsInAttribute(attr, vars);
105106 nudef.putAttribute(replace(attributeName, vars), nuattr, true);
107 }
108 }
109110return nudef;
111 }
112113/**114 * Creates a new map that contains all the entries of the115 * <code>defsMap</code> whose keys are contained in <code>keys</code>.116 *117 * @param map The map to read.118 * @param keys The keys to extract.119 * @param <K> The key of the map.120 * @param <V> The value of the map.121 * @return The extracted map.122 * @since 2.2.1123 */124publicstatic <K, V> Map<K, V> createExtractedMap(Map<K, V> map, Set<K> keys) {
125 Map<K, V> retValue = new LinkedHashMap<K, V>();
126for (K key : keys) {
127 retValue.put(key, map.get(key));
128 }
129return retValue;
130 }
131132/**133 * Replaces variables into an attribute.134 *135 * @param attr The attribute to be used as a basis, containing placeholders136 * for variables.137 * @param vars The variables to replace.138 * @return A new instance of an attribute, whose properties have been139 * replaced with variables' values.140 */141privatestaticAttribute replaceVarsInAttribute(Attribute attr,
142 Object... vars) {
143Attribute nuattr;
144if (attr instanceof ListAttribute) {
145 nuattr = replaceVarsInListAttribute((ListAttribute) attr, vars);
146 } else {
147 nuattr = replaceVarsInSimpleAttribute(attr, vars);
148 }
149return nuattr;
150 }
151152/**153 * Replaces variables into a simple (not list) attribute.154 *155 * @param attr The attribute to be used as a basis, containing placeholders156 * for variables.157 * @param vars The variables to replace.158 * @return A new instance of an attribute, whose properties have been159 * replaced with variables' values.160 */161privatestaticAttribute replaceVarsInSimpleAttribute(Attribute attr,
162 Object... vars) {
163Attribute nuattr;
164 nuattr = newAttribute();
165166 nuattr.setRole(replace(attr.getRole(), vars));
167 nuattr.setRenderer(attr.getRenderer());
168Expression expressionObject = attr.getExpressionObject();
169if (expressionObject != null) {
170Expression newExpressionObject = Expression171 .createExpression(replace(expressionObject.getExpression(), vars), expressionObject.getLanguage());
172 nuattr.setExpressionObject(newExpressionObject);
173 }
174175 Object value = attr.getValue();
176if (value instanceof String) {
177 value = replace((String) value, vars);
178 }
179 nuattr.setValue(value);
180return nuattr;
181 }
182183/**184 * Replaces variables into a list attribute.185 *186 * @param listAttr The attribute to be used as a basis, containing attributes187 * that may contain placeholders for variables.188 * @param vars The variables to replace.189 * @return A new instance of an attribute, whose properties have been190 * replaced with variables' values.191 */192privatestaticAttribute replaceVarsInListAttribute(ListAttribute listAttr,
193 Object... vars) {
194Attribute nuattr;
195ListAttribute nuListAttr = newListAttribute();
196 nuListAttr.setInherit(listAttr.isInherit());
197 List<Attribute> nuItems = nuListAttr.getValue();
198for (Object item : listAttr.getValue()) {
199Attribute child = (Attribute) item;
200 child = replaceVarsInAttribute(child, vars);
201 nuItems.add(child);
202 }
203 nuattr = nuListAttr;
204return nuattr;
205 }
206207/**208 * Replaces a string with placeholders using values of a variable map.209 *210 * @param st The string to replace.211 * @param vars The variables.212 * @return The replaced string.213 */214privatestatic String replace(String st, Object... vars) {
215if (st != null && st.indexOf('{') >= 0) {
216217// replace them with markers218 List<String> originals = new ArrayList<String>();
219for(Matcher m = INVALID_FORMAT_ELEMENT.matcher(st); m.find() ; m = INVALID_FORMAT_ELEMENT.matcher(st)) {
220 originals.add(m.group());
221 st = m.replaceFirst("INVALID_FORMAT_ELEMENT");
222 }
223224// do the MessageFormat replacement (escaping quote characters)225 st = new MessageFormat(st.replaceAll("'", "'''"), ROOT_LOCALE)
226 .format(vars, new StringBuffer(), null).toString();
227228// return the markers to their original invalid occurrences229for (String original : originals) {
230 st = st.replaceFirst("INVALID_FORMAT_ELEMENT", original);
231 }
232 }
233return st;
234 }
235236privatestatic Object[] replaceNullsWithBlank(Object[] varsOrig) {
237 Object[] vars = new Object[varsOrig.length];
238for(int i = 0; i < varsOrig.length; ++i) {
239 vars[i] = null != varsOrig[i] ? varsOrig[i] : "";
240 }
241return vars;
242 }
243 }