Coverage Report - org.apache.tiles.definition.pattern.PatternUtil
 
Classes in this File Line Coverage Branch Coverage Complexity
PatternUtil
97%
70/72
91%
33/36
3.25
 
 1  
 /*
 2  
  * $Id: PatternUtil.java 1594481 2014-05-14 06:52:35Z mck $
 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.ArrayList;
 26  
 import java.util.LinkedHashMap;
 27  
 import java.util.List;
 28  
 import java.util.Locale;
 29  
 import java.util.Map;
 30  
 import java.util.Set;
 31  
 import java.util.regex.Matcher;
 32  
 import java.util.regex.Pattern;
 33  
 
 34  
 import org.apache.tiles.Attribute;
 35  
 import org.apache.tiles.Definition;
 36  
 import org.apache.tiles.Expression;
 37  
 import org.apache.tiles.ListAttribute;
 38  
 
 39  
 /**
 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.0
 44  
  */
 45  
 public final class PatternUtil {
 46  
 
 47  
     /**
 48  
      * The root locale. Notice that this is a replacement for Locale.ROOT for
 49  
      * Java 1.6.
 50  
      */
 51  1
     private static final Locale ROOT_LOCALE = new Locale("", "");
 52  
 
 53  
     /** Pattern to find {.*} occurrences that do not match {[0-9]+} so to prevent MessageFormat from crashing.
 54  
      */
 55  1
     private static final Pattern INVALID_FORMAT_ELEMENT = Pattern.compile("\\{[^}0-9]+\\}");
 56  
 
 57  
     /**
 58  
      * Private constructor to avoid instantiation.
 59  
      */
 60  0
     private PatternUtil() {
 61  0
     }
 62  
 
 63  
     /**
 64  
      * Creates a definition given its representation with wildcards and
 65  
      * attribute values with placeholders, replacing real values into
 66  
      * 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.0
 73  
      */
 74  
     public static Definition replacePlaceholders(Definition d, String name,
 75  
             Object... varsOrig) {
 76  
 
 77  22
         Object[] vars = replaceNullsWithBlank(varsOrig);
 78  
 
 79  22
         Definition nudef = new Definition();
 80  
 
 81  22
         nudef.setExtends(replace(d.getExtends(), vars));
 82  22
         nudef.setName(name);
 83  22
         nudef.setPreparer(replace(d.getPreparer(), vars));
 84  22
         Attribute templateAttribute = d.getTemplateAttribute();
 85  22
         if (templateAttribute != null) {
 86  21
             nudef.setTemplateAttribute(replaceVarsInAttribute(
 87  
                     templateAttribute, vars));
 88  
         }
 89  
 
 90  22
         Set<String> attributeNames = d.getLocalAttributeNames();
 91  22
         if (attributeNames != null && !attributeNames.isEmpty()) {
 92  19
             for (String attributeName : attributeNames) {
 93  52
                 Attribute attr = d.getLocalAttribute(attributeName);
 94  52
                 Attribute nuattr = replaceVarsInAttribute(attr, vars);
 95  
 
 96  52
                 nudef.putAttribute(replace(attributeName, vars), nuattr);
 97  52
             }
 98  
         }
 99  
 
 100  22
         attributeNames = d.getCascadedAttributeNames();
 101  22
         if (attributeNames != null && !attributeNames.isEmpty()) {
 102  1
             for (String attributeName : attributeNames) {
 103  2
                 Attribute attr = d.getCascadedAttribute(attributeName);
 104  2
                 Attribute nuattr = replaceVarsInAttribute(attr, vars);
 105  
 
 106  2
                 nudef.putAttribute(replace(attributeName, vars), nuattr, true);
 107  2
             }
 108  
         }
 109  
 
 110  22
         return nudef;
 111  
     }
 112  
 
 113  
     /**
 114  
      * Creates a new map that contains all the entries of the
 115  
      * <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.1
 123  
      */
 124  
     public static <K, V> Map<K, V> createExtractedMap(Map<K, V> map, Set<K> keys) {
 125  45
         Map<K, V> retValue = new LinkedHashMap<K, V>();
 126  45
         for (K key : keys) {
 127  241
             retValue.put(key, map.get(key));
 128  241
         }
 129  45
         return retValue;
 130  
     }
 131  
 
 132  
     /**
 133  
      * Replaces variables into an attribute.
 134  
      *
 135  
      * @param attr The attribute to be used as a basis, containing placeholders
 136  
      * for variables.
 137  
      * @param vars The variables to replace.
 138  
      * @return A new instance of an attribute, whose properties have been
 139  
      * replaced with variables' values.
 140  
      */
 141  
     private static Attribute replaceVarsInAttribute(Attribute attr,
 142  
             Object... vars) {
 143  
         Attribute nuattr;
 144  80
         if (attr instanceof ListAttribute) {
 145  2
             nuattr = replaceVarsInListAttribute((ListAttribute) attr, vars);
 146  
         } else {
 147  78
             nuattr = replaceVarsInSimpleAttribute(attr, vars);
 148  
         }
 149  80
         return nuattr;
 150  
     }
 151  
 
 152  
     /**
 153  
      * Replaces variables into a simple (not list) attribute.
 154  
      *
 155  
      * @param attr The attribute to be used as a basis, containing placeholders
 156  
      * for variables.
 157  
      * @param vars The variables to replace.
 158  
      * @return A new instance of an attribute, whose properties have been
 159  
      * replaced with variables' values.
 160  
      */
 161  
     private static Attribute replaceVarsInSimpleAttribute(Attribute attr,
 162  
             Object... vars) {
 163  
         Attribute nuattr;
 164  78
         nuattr = new Attribute();
 165  
 
 166  78
         nuattr.setRole(replace(attr.getRole(), vars));
 167  78
         nuattr.setRenderer(attr.getRenderer());
 168  78
         Expression expressionObject = attr.getExpressionObject();
 169  78
         if (expressionObject != null) {
 170  7
             Expression newExpressionObject = Expression
 171  
                     .createExpression(replace(expressionObject.getExpression(), vars), expressionObject.getLanguage());
 172  7
             nuattr.setExpressionObject(newExpressionObject);
 173  
         }
 174  
 
 175  78
         Object value = attr.getValue();
 176  78
         if (value instanceof String) {
 177  75
             value = replace((String) value, vars);
 178  
         }
 179  78
         nuattr.setValue(value);
 180  78
         return nuattr;
 181  
     }
 182  
 
 183  
     /**
 184  
      * Replaces variables into a list attribute.
 185  
      *
 186  
      * @param listAttr The attribute to be used as a basis, containing attributes
 187  
      * that may contain placeholders for variables.
 188  
      * @param vars The variables to replace.
 189  
      * @return A new instance of an attribute, whose properties have been
 190  
      * replaced with variables' values.
 191  
      */
 192  
     private static Attribute replaceVarsInListAttribute(ListAttribute listAttr,
 193  
             Object... vars) {
 194  
         Attribute nuattr;
 195  2
         ListAttribute nuListAttr = new ListAttribute();
 196  2
         nuListAttr.setInherit(listAttr.isInherit());
 197  2
         List<Attribute> nuItems = nuListAttr.getValue();
 198  2
         for (Object item : listAttr.getValue()) {
 199  5
             Attribute child = (Attribute) item;
 200  5
             child = replaceVarsInAttribute(child, vars);
 201  5
             nuItems.add(child);
 202  5
         }
 203  2
         nuattr = nuListAttr;
 204  2
         return nuattr;
 205  
     }
 206  
 
 207  
     /**
 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  
      */
 214  
     private static String replace(String st, Object... vars) {
 215  258
         if (st != null && st.indexOf('{') >= 0) {
 216  
 
 217  
             // replace them with markers
 218  48
             List<String> originals = new ArrayList<String>();
 219  66
             for(Matcher m = INVALID_FORMAT_ELEMENT.matcher(st); m.find() ; m = INVALID_FORMAT_ELEMENT.matcher(st)) {
 220  18
                 originals.add(m.group());
 221  18
                 st = m.replaceFirst("INVALID_FORMAT_ELEMENT");
 222  
             }
 223  
 
 224  
             // do the MessageFormat replacement (escaping quote characters)
 225  48
             st = new MessageFormat(st.replaceAll("'", "'''"), ROOT_LOCALE)
 226  
                     .format(vars, new StringBuffer(), null).toString();
 227  
 
 228  
             // return the markers to their original invalid occurrences
 229  48
             for (String original : originals) {
 230  18
                 st = st.replaceFirst("INVALID_FORMAT_ELEMENT", original);
 231  18
             }
 232  
         }
 233  258
         return st;
 234  
     }
 235  
 
 236  
     private static Object[] replaceNullsWithBlank(Object[] varsOrig) {
 237  22
         Object[] vars = new Object[varsOrig.length];
 238  96
         for(int i = 0; i < varsOrig.length; ++i) {
 239  74
             vars[i] = null != varsOrig[i] ? varsOrig[i] : "";
 240  
         }
 241  22
         return vars;
 242  
     }
 243  
 }