Coverage Report - org.apache.tapestry5.internal.TapestryInternalUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
TapestryInternalUtils
96%
104/108
94%
51/54
0
TapestryInternalUtils$1
100%
5/5
N/A
0
 
 1  
 // Copyright 2006, 2007, 2008, 2009 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package org.apache.tapestry5.internal;
 16  
 
 17  
 import org.apache.tapestry5.*;
 18  
 import org.apache.tapestry5.ioc.Messages;
 19  
 import org.apache.tapestry5.ioc.Resource;
 20  
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 21  
 import org.apache.tapestry5.ioc.internal.util.Defense;
 22  
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 23  
 
 24  
 import java.io.IOException;
 25  
 import java.io.InputStream;
 26  
 import java.io.OutputStream;
 27  
 import java.util.List;
 28  
 import java.util.Map;
 29  
 import java.util.regex.Pattern;
 30  
 
 31  
 /**
 32  
  * Shared utility methods used by various implementation classes.
 33  
  */
 34  0
 public class TapestryInternalUtils
 35  
 {
 36  
     private static final String SLASH = "/";
 37  
 
 38  2
     private static final Pattern SLASH_PATTERN = Pattern.compile(SLASH);
 39  
 
 40  2
     private static final Pattern NON_WORD_PATTERN = Pattern.compile("[^\\w]");
 41  
 
 42  2
     private static final Pattern COMMA_PATTERN = Pattern.compile("\\s*,\\s*");
 43  
 
 44  
     private static final int BUFFER_SIZE = 5000;
 45  
 
 46  2
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 47  
 
 48  
     /**
 49  
      * Capitalizes the string, and inserts a space before each upper case character (or sequence of upper case
 50  
      * characters). Thus "userId" becomes "User Id", etc. Also, converts underscore into space (and capitalizes the
 51  
      * following word), thus "user_id" also becomes "User Id".
 52  
      */
 53  
     public static String toUserPresentable(String id)
 54  
     {
 55  1941
         StringBuilder builder = new StringBuilder(id.length() * 2);
 56  
 
 57  1941
         char[] chars = id.toCharArray();
 58  1941
         boolean postSpace = true;
 59  1941
         boolean upcaseNext = true;
 60  
 
 61  13918
         for (char ch : chars)
 62  
         {
 63  11977
             if (upcaseNext)
 64  
             {
 65  2005
                 builder.append(Character.toUpperCase(ch));
 66  2005
                 upcaseNext = false;
 67  
 
 68  2005
                 continue;
 69  
             }
 70  
 
 71  9972
             if (ch == '_')
 72  
             {
 73  64
                 builder.append(' ');
 74  64
                 upcaseNext = true;
 75  64
                 continue;
 76  
             }
 77  
 
 78  9908
             boolean upperCase = Character.isUpperCase(ch);
 79  
 
 80  9908
             if (upperCase && !postSpace) builder.append(' ');
 81  
 
 82  9908
             builder.append(ch);
 83  
 
 84  9908
             postSpace = upperCase;
 85  
         }
 86  
 
 87  1941
         return builder.toString();
 88  
     }
 89  
 
 90  
     public static Map<String, String> mapFromKeysAndValues(String... keysAndValues)
 91  
     {
 92  4
         Map<String, String> result = CollectionFactory.newMap();
 93  
 
 94  4
         int i = 0;
 95  12
         while (i < keysAndValues.length)
 96  
         {
 97  8
             String key = keysAndValues[i++];
 98  8
             String value = keysAndValues[i++];
 99  
 
 100  8
             result.put(key, value);
 101  8
         }
 102  
 
 103  4
         return result;
 104  
     }
 105  
 
 106  
     /**
 107  
      * Converts a string to an {@link OptionModel}. The string is of the form "value=label". If the equals sign is
 108  
      * omitted, then the same value is used for both value and label.
 109  
      *
 110  
      * @param input
 111  
      * @return
 112  
      */
 113  
     public static OptionModel toOptionModel(String input)
 114  
     {
 115  98
         Defense.notNull(input, "input");
 116  
 
 117  98
         int equalsx = input.indexOf('=');
 118  
 
 119  98
         if (equalsx < 0) return new OptionModelImpl(input);
 120  
 
 121  38
         String value = input.substring(0, equalsx);
 122  38
         String label = input.substring(equalsx + 1);
 123  
 
 124  38
         return new OptionModelImpl(label, value);
 125  
     }
 126  
 
 127  
     /**
 128  
      * Parses a string input into a series of value=label pairs compatible with {@link #toOptionModel(String)}. Splits
 129  
      * on commas. Ignores whitespace around commas.
 130  
      *
 131  
      * @param input comma seperated list of terms
 132  
      * @return list of option models
 133  
      */
 134  
     public static List<OptionModel> toOptionModels(String input)
 135  
     {
 136  31
         Defense.notNull(input, "input");
 137  
 
 138  31
         List<OptionModel> result = CollectionFactory.newList();
 139  
 
 140  125
         for (String term : input.split(","))
 141  94
             result.add(toOptionModel(term.trim()));
 142  
 
 143  31
         return result;
 144  
     }
 145  
 
 146  
     /**
 147  
      * Wraps the result of {@link #toOptionModels(String)} as a {@link SelectModel} (with no option groups).
 148  
      *
 149  
      * @param input
 150  
      * @return
 151  
      */
 152  
     public static SelectModel toSelectModel(String input)
 153  
     {
 154  11
         List<OptionModel> options = toOptionModels(input);
 155  
 
 156  11
         return new SelectModelImpl(null, options);
 157  
     }
 158  
 
 159  
     /**
 160  
      * Converts a map entry to an {@link OptionModel}.
 161  
      *
 162  
      * @param input
 163  
      * @return
 164  
      */
 165  
     public static OptionModel toOptionModel(Map.Entry input)
 166  
     {
 167  10
         Defense.notNull(input, "input");
 168  
 
 169  10
         String label = input.getValue() != null ? String.valueOf(input.getValue()) : "";
 170  
 
 171  10
         return new OptionModelImpl(label, input.getKey());
 172  
     }
 173  
 
 174  
     /**
 175  
      * Processes a map input into a series of map entries compatible with {@link #toOptionModel(Map.Entry)}.
 176  
      *
 177  
      * @param input map of elements
 178  
      * @return list of option models
 179  
      */
 180  
     public static <K, V> List<OptionModel> toOptionModels(Map<K, V> input)
 181  
     {
 182  4
         Defense.notNull(input, "input");
 183  
 
 184  4
         List<OptionModel> result = CollectionFactory.newList();
 185  
 
 186  4
         for (Map.Entry entry : input.entrySet())
 187  8
             result.add(toOptionModel(entry));
 188  
 
 189  4
         return result;
 190  
     }
 191  
 
 192  
     /**
 193  
      * Wraps the result of {@link #toOptionModels(Map)} as a {@link SelectModel} (with no option groups).
 194  
      *
 195  
      * @param input
 196  
      * @return
 197  
      */
 198  
     public static <K, V> SelectModel toSelectModel(Map<K, V> input)
 199  
     {
 200  0
         List<OptionModel> options = toOptionModels(input);
 201  
 
 202  0
         return new SelectModelImpl(null, options);
 203  
     }
 204  
 
 205  
     /**
 206  
      * Converts an object to an {@link OptionModel}.
 207  
      *
 208  
      * @param input
 209  
      * @return
 210  
      */
 211  
     public static OptionModel toOptionModel(Object input)
 212  
     {
 213  38
         String label = (input != null ? String.valueOf(input) : "");
 214  
 
 215  38
         return new OptionModelImpl(label, input);
 216  
     }
 217  
 
 218  
     /**
 219  
      * Processes a list input into a series of objects compatible with {@link #toOptionModel(Object)}.
 220  
      *
 221  
      * @param input list of elements
 222  
      * @return list of option models
 223  
      */
 224  
     public static <E> List<OptionModel> toOptionModels(List<E> input)
 225  
     {
 226  10
         Defense.notNull(input, "input");
 227  
 
 228  10
         List<OptionModel> result = CollectionFactory.newList();
 229  
 
 230  10
         for (E element : input)
 231  36
             result.add(toOptionModel(element));
 232  
 
 233  10
         return result;
 234  
     }
 235  
 
 236  
     /**
 237  
      * Wraps the result of {@link #toOptionModels(List)} as a {@link SelectModel} (with no option groups).
 238  
      *
 239  
      * @param input
 240  
      * @return
 241  
      */
 242  
     public static <E> SelectModel toSelectModel(List<E> input)
 243  
     {
 244  8
         List<OptionModel> options = toOptionModels(input);
 245  
 
 246  8
         return new SelectModelImpl(null, options);
 247  
     }
 248  
 
 249  
     /**
 250  
      * Parses a key/value pair where the key and the value are seperated by an equals sign. The key and value are
 251  
      * trimmed of leading and trailing whitespace, and returned as a {@link KeyValue}.
 252  
      *
 253  
      * @param input
 254  
      * @return
 255  
      */
 256  
     public static KeyValue parseKeyValue(String input)
 257  
     {
 258  278
         int pos = input.indexOf('=');
 259  
 
 260  278
         if (pos < 1) throw new IllegalArgumentException(InternalMessages.badKeyValue(input));
 261  
 
 262  276
         String key = input.substring(0, pos);
 263  276
         String value = input.substring(pos + 1);
 264  
 
 265  276
         return new KeyValue(key.trim(), value.trim());
 266  
     }
 267  
 
 268  
 
 269  
     /**
 270  
      * Used to convert a property expression into a key that can be used to locate various resources (Blocks, messages,
 271  
      * etc.). Strips out any punctuation characters, leaving just words characters (letters, number and the
 272  
      * underscore).
 273  
      *
 274  
      * @param expression a property expression
 275  
      * @return the expression with punctuation removed
 276  
      */
 277  
     public static String extractIdFromPropertyExpression(String expression)
 278  
     {
 279  2256
         return replace(expression, NON_WORD_PATTERN, "");
 280  
     }
 281  
 
 282  
     /**
 283  
      * Looks for a label within the messages based on the id. If found, it is used, otherwise the name is converted to a
 284  
      * user presentable form.
 285  
      */
 286  
     public static String defaultLabel(String id, Messages messages, String propertyExpression)
 287  
     {
 288  1160
         String key = id + "-label";
 289  
 
 290  1160
         if (messages.contains(key)) return messages.get(key);
 291  
 
 292  1094
         return toUserPresentable(extractIdFromPropertyExpression(lastTerm(propertyExpression)));
 293  
     }
 294  
 
 295  
     /**
 296  
      * Strips a dotted sequence (such as a property expression, or a qualified class name) down to the last term of that
 297  
      * expression, by locating the last period ('.') in the string.
 298  
      */
 299  
     public static String lastTerm(String input)
 300  
     {
 301  1616
         int dotx = input.lastIndexOf('.');
 302  
 
 303  1616
         return input.substring(dotx + 1);
 304  
     }
 305  
 
 306  
     /**
 307  
      * Converts an list of strings into a space-separated string combining them all, suitable for use as an HTML class
 308  
      * attribute value.
 309  
      *
 310  
      * @param classes classes to combine
 311  
      * @return the joined classes, or null if classes is empty
 312  
      */
 313  
     public static String toClassAttributeValue(List<String> classes)
 314  
     {
 315  11948
         if (classes.isEmpty()) return null;
 316  
 
 317  9504
         return InternalUtils.join(classes, " ");
 318  
     }
 319  
 
 320  
 
 321  
     /**
 322  
      * Converts an enum to a label string, allowing for overrides from a message catalog.
 323  
      * <p/>
 324  
      * <ul> <li>As key <em>prefix</em>.<em>name</em> if present.  Ex: "ElementType.LOCAL_VARIABLE" <li>As key
 325  
      * <em>name</em> if present, i.e., "LOCAL_VARIABLE". <li>As a user-presentable version of the name, i.e., "Local
 326  
      * Variable". </ul>
 327  
      *
 328  
      * @param messages the messages to search for the label
 329  
      * @param prefix
 330  
      * @param value    to get a label for
 331  
      * @return the label
 332  
      */
 333  
     public static String getLabelForEnum(Messages messages, String prefix, Enum value)
 334  
     {
 335  713
         String name = value.name();
 336  
 
 337  713
         String key = prefix + "." + name;
 338  
 
 339  713
         if (messages.contains(key)) return messages.get(key);
 340  
 
 341  711
         if (messages.contains(name)) return messages.get(name);
 342  
 
 343  689
         return toUserPresentable(name.toLowerCase());
 344  
     }
 345  
 
 346  
     public static String getLabelForEnum(Messages messages, Enum value)
 347  
     {
 348  348
         String prefix = lastTerm(value.getClass().getName());
 349  
 
 350  348
         return getLabelForEnum(messages, prefix, value);
 351  
     }
 352  
 
 353  
     private static String replace(String input, Pattern pattern, String replacement)
 354  
     {
 355  2256
         return pattern.matcher(input).replaceAll(replacement);
 356  
     }
 357  
 
 358  
     /**
 359  
      * Determines if the two values are equal. They are equal if they are the exact same value (including if they are
 360  
      * both null). Otherwise standard equals() comparison is used.
 361  
      *
 362  
      * @param <T>
 363  
      * @param left  value to compare, possibly null
 364  
      * @param right value to compare, possibly null
 365  
      * @return true if same value, both null, or equal
 366  
      */
 367  
     public static <T> boolean isEqual(T left, T right)
 368  
     {
 369  45452
         if (left == right) return true;
 370  
 
 371  11142
         if (left == null) return right == null;
 372  
 
 373  11138
         return left.equals(right);
 374  
     }
 375  
 
 376  
 
 377  
     /**
 378  
      * Splits a path at each slash.
 379  
      */
 380  
     public static String[] splitPath(String path)
 381  
     {
 382  3192
         return SLASH_PATTERN.split(path);
 383  
     }
 384  
 
 385  
     /**
 386  
      * Splits a value around commas.  Whitespace around the commas is removed, as is leading and trailing whitespace.
 387  
      *
 388  
      * @since 5.1.0.0
 389  
      */
 390  
     public static String[] splitAtCommas(String value)
 391  
     {
 392  3376
         if (InternalUtils.isBlank(value))
 393  1640
             return EMPTY_STRING_ARRAY;
 394  
 
 395  1736
         return COMMA_PATTERN.split(value.trim());
 396  
     }
 397  
 
 398  
     /**
 399  
      * Copies some content from an input stream to an output stream. It is the caller's responsibility to close the
 400  
      * streams.
 401  
      *
 402  
      * @param in  source of data
 403  
      * @param out sink of data
 404  
      * @throws IOException
 405  
      * @since 5.1.0.0
 406  
      */
 407  
     public static void copy(InputStream in, OutputStream out) throws IOException
 408  
     {
 409  290
         byte[] buffer = new byte[BUFFER_SIZE];
 410  
 
 411  
         while (true)
 412  
         {
 413  1548
             int length = in.read(buffer);
 414  
 
 415  1548
             if (length < 0) break;
 416  
 
 417  1258
             out.write(buffer, 0, length);
 418  1258
         }
 419  
 
 420  
         // TAPESTRY-2415: WebLogic needs this flush() call.
 421  290
         out.flush();
 422  290
     }
 423  
 
 424  
     public static boolean isEqual(EventContext left, EventContext right)
 425  
     {
 426  82
         if (left == right) return true;
 427  
 
 428  80
         int count = left.getCount();
 429  
 
 430  80
         if (count != right.getCount()) return false;
 431  
 
 432  156
         for (int i = 0; i < count; i++)
 433  
         {
 434  76
             if (!left.get(Object.class, i).equals(right.get(Object.class, i)))
 435  0
                 return false;
 436  
         }
 437  
 
 438  80
         return true;
 439  
     }
 440  
 
 441  
     /**
 442  
      * Converts an Asset to an Asset2 if necessary. When actually wrapping an Asset as an Asset2, the asset is assumed
 443  
      * to be variant (i.e., not cacheable).
 444  
      *
 445  
      * @since 5.1.0.0
 446  
      */
 447  
     public static Asset2 toAsset2(final Asset asset)
 448  
     {
 449  58
         if (asset instanceof Asset2)
 450  56
             return (Asset2) asset;
 451  
 
 452  2
         return new Asset2()
 453  
         {
 454  
             /** Returns false. */
 455  
             public boolean isInvariant()
 456  
             {
 457  2
                 return false;
 458  
             }
 459  
 
 460  
             public Resource getResource()
 461  
             {
 462  2
                 return asset.getResource();
 463  
             }
 464  
 
 465  
             public String toClientURL()
 466  
             {
 467  2
                 return asset.toClientURL();
 468  
             }
 469  
 
 470  
             @Override
 471  2
             public String toString()
 472  
             {
 473  2
                 return asset.toString();
 474  
             }
 475  
         };
 476  
     }
 477  
 }