This project has retired. For details please refer to its Attic page.
PatternUtil xref
View Javadoc

1   /*
2    * $Id: PatternUtil.java 921998 2010-03-11 19:58:08Z apetrelli $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   * http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
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                 // Seems improbable, but APIs permit it.
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             // remember the invalid "{...}" occurrences
219             Matcher m = INVALID_FORMAT_ELEMENT.matcher(st);
220             // replace them with markers
221             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 occurrences
226             while (m.find()) {
227                 st = st.replaceFirst("INVALID_FORMAT_ELEMENT", m.group());
228             }
229         }
230         return st;
231     }
232 }