1/*2 * $Id: PatternUtil.java 921998 2010-03-11 19:58:08Z apetrelli $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.LinkedHashMap;
26import java.util.List;
27import java.util.Locale;
28import java.util.Map;
29import java.util.Set;
30import java.util.regex.Matcher;
31import java.util.regex.Pattern;
3233import org.apache.tiles.Attribute;
34import org.apache.tiles.Definition;
35import org.apache.tiles.Expression;
36import org.apache.tiles.ListAttribute;
3738/***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.043 */44publicfinalclassPatternUtil {
4546/***47 * The root locale. Notice that this is a replacement for Locale.ROOT for48 * Java 1.6.49 */50privatestaticfinal Locale ROOT_LOCALE = new Locale("", "");
5152/*** Pattern to find {.*} occurrences that do not match {[0-9]+} so to prevent MessageFormat from crashing.53 */54privatestaticfinal Pattern INVALID_FORMAT_ELEMENT = Pattern.compile("//Q{//E[//D^}]+//Q}//E");
5556/***57 * Private constructor to avoid instantiation.58 */59privatePatternUtil() {
60 }
6162/***63 * Creates a definition given its representation with wildcards and64 * attribute values with placeholders, replacing real values into65 * 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.072 */73publicstatic Definition replacePlaceholders(Definition d, String name,
74 Object... vars) {
75 Definition nudef = new Definition();
7677 nudef.setExtends(replace(d.getExtends(), vars));
78 nudef.setName(name);
79 nudef.setPreparer(replace(d.getPreparer(), vars));
80 Attribute templateAttribute = d.getTemplateAttribute();
81if (templateAttribute != null) {
82 nudef.setTemplateAttribute(replaceVarsInAttribute(
83 templateAttribute, vars));
84 }
8586 Set<String> attributeNames = d.getLocalAttributeNames();
87if (attributeNames != null && !attributeNames.isEmpty()) {
88for (String attributeName : attributeNames) {
89 Attribute attr = d.getLocalAttribute(attributeName);
90 Attribute nuattr = replaceVarsInAttribute(attr, vars);
9192 nudef.putAttribute(replace(attributeName, vars), nuattr);
93 }
94 }
9596 attributeNames = d.getCascadedAttributeNames();
97if (attributeNames != null && !attributeNames.isEmpty()) {
98for (String attributeName : attributeNames) {
99 Attribute attr = d.getCascadedAttribute(attributeName);
100 Attribute nuattr = replaceVarsInAttribute(attr, vars);
101102 nudef.putAttribute(replace(attributeName, vars), nuattr, true);
103 }
104 }
105106return nudef;
107 }
108109/***110 * Creates a new map that contains all the entries of the111 * <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.1119 */120publicstatic <K, V> Map<K, V> createExtractedMap(Map<K, V> map, Set<K> keys) {
121 Map<K, V> retValue = new LinkedHashMap<K, V>();
122for (K key : keys) {
123 retValue.put(key, map.get(key));
124 }
125return retValue;
126 }
127128/***129 * Replaces variables into an attribute.130 *131 * @param attr The attribute to be used as a basis, containing placeholders132 * for variables.133 * @param vars The variables to replace.134 * @return A new instance of an attribute, whose properties have been135 * replaced with variables' values.136 */137privatestatic Attribute replaceVarsInAttribute(Attribute attr,
138 Object... vars) {
139 Attribute nuattr;
140if (attr instanceof ListAttribute) {
141 nuattr = replaceVarsInListAttribute((ListAttribute) attr, vars);
142 } else {
143 nuattr = replaceVarsInSimpleAttribute(attr, vars);
144 }
145return nuattr;
146 }
147148/***149 * Replaces variables into a simple (not list) attribute.150 *151 * @param attr The attribute to be used as a basis, containing placeholders152 * for variables.153 * @param vars The variables to replace.154 * @return A new instance of an attribute, whose properties have been155 * replaced with variables' values.156 */157privatestatic Attribute replaceVarsInSimpleAttribute(Attribute attr,
158 Object... vars) {
159 Attribute nuattr;
160 nuattr = new Attribute();
161162 nuattr.setRole(replace(attr.getRole(), vars));
163 nuattr.setRenderer(attr.getRenderer());
164 Expression expressionObject = attr.getExpressionObject();
165if (expressionObject != null) {
166 Expression newExpressionObject = Expression
167 .createExpression(replace(expressionObject.getExpression(), vars), expressionObject.getLanguage());
168 nuattr.setExpressionObject(newExpressionObject);
169 }
170171 Object value = attr.getValue();
172if (value instanceof String) {
173 value = replace((String) value, vars);
174 }
175 nuattr.setValue(value);
176return nuattr;
177 }
178179/***180 * Replaces variables into a list attribute.181 *182 * @param listAttr The attribute to be used as a basis, containing attributes183 * that may contain placeholders for variables.184 * @param vars The variables to replace.185 * @return A new instance of an attribute, whose properties have been186 * replaced with variables' values.187 */188 @SuppressWarnings("unchecked")
189privatestatic 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();
195for (Object item : (List<Object>) listAttr.getValue()) {
196if (item instanceof Attribute) {
197 Attribute child = (Attribute) item;
198 child = replaceVarsInAttribute(child, vars);
199 nuItems.add(child);
200 } else {
201// Seems improbable, but APIs permit it.202 nuItems.add(item);
203 }
204 }
205 nuattr = nuListAttr;
206return nuattr;
207 }
208209/***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 */216privatestatic String replace(String st, Object... vars) {
217if (st != null && st.indexOf('{') >= 0) {
218// remember the invalid "{...}" occurrences219 Matcher m = INVALID_FORMAT_ELEMENT.matcher(st);
220// replace them with markers221 st = INVALID_FORMAT_ELEMENT.matcher(st).replaceAll("INVALID_FORMAT_ELEMENT");
222// do the MessageFormat replacement (escaping quote characters)223 st = new MessageFormat(st.replaceAll("'", "'''"), ROOT_LOCALE)
224 .format(vars, new StringBuffer(), null).toString();
225// return the markers to their original invalid occurrences226while (m.find()) {
227 st = st.replaceFirst("INVALID_FORMAT_ELEMENT", m.group());
228 }
229 }
230return st;
231 }
232 }