Coverage Report - com.puppycrawl.tools.checkstyle.utils.CommonUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
CommonUtils
100%
191/191
100%
86/86
3.154
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle.utils;
 21  
 
 22  
 import java.io.Closeable;
 23  
 import java.io.File;
 24  
 import java.io.IOException;
 25  
 import java.lang.reflect.Constructor;
 26  
 import java.lang.reflect.InvocationTargetException;
 27  
 import java.net.MalformedURLException;
 28  
 import java.net.URI;
 29  
 import java.net.URISyntaxException;
 30  
 import java.net.URL;
 31  
 import java.nio.file.Path;
 32  
 import java.nio.file.Paths;
 33  
 import java.util.AbstractMap;
 34  
 import java.util.Map;
 35  
 import java.util.regex.Matcher;
 36  
 import java.util.regex.Pattern;
 37  
 import java.util.regex.PatternSyntaxException;
 38  
 
 39  
 import org.apache.commons.beanutils.ConversionException;
 40  
 
 41  
 import antlr.Token;
 42  
 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
 43  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 44  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 45  
 
 46  
 /**
 47  
  * Contains utility methods.
 48  
  *
 49  
  * @author <a href="mailto:nesterenko-aleksey@list.ru">Aleksey Nesterenko</a>
 50  
  */
 51  
 public final class CommonUtils {
 52  
 
 53  
     /** Copied from org.apache.commons.lang3.ArrayUtils. */
 54  19
     public static final String[] EMPTY_STRING_ARRAY = new String[0];
 55  
     /** Copied from org.apache.commons.lang3.ArrayUtils. */
 56  19
     public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = new Integer[0];
 57  
     /** Copied from org.apache.commons.lang3.ArrayUtils. */
 58  19
     public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
 59  
     /** Copied from org.apache.commons.lang3.ArrayUtils. */
 60  19
     public static final int[] EMPTY_INT_ARRAY = new int[0];
 61  
     /** Copied from org.apache.commons.lang3.ArrayUtils. */
 62  19
     public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
 63  
     /** Copied from org.apache.commons.lang3.ArrayUtils. */
 64  19
     public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
 65  
 
 66  
     /** Prefix for the exception when unable to find resource. */
 67  
     private static final String UNABLE_TO_FIND_EXCEPTION_PREFIX = "Unable to find: ";
 68  
 
 69  
     /** Symbols with which javadoc starts. */
 70  
     private static final String JAVADOC_START = "/**";
 71  
     /** Symbols with which multiple comment starts. */
 72  
     private static final String BLOCK_MULTIPLE_COMMENT_BEGIN = "/*";
 73  
     /** Symbols with which multiple comment ends. */
 74  
     private static final String BLOCK_MULTIPLE_COMMENT_END = "*/";
 75  
 
 76  
     /** Stop instances being created. **/
 77  1
     private CommonUtils() {
 78  
 
 79  1
     }
 80  
 
 81  
     /**
 82  
      * Helper method to create a regular expression.
 83  
      *
 84  
      * @param pattern
 85  
      *            the pattern to match
 86  
      * @return a created regexp object
 87  
      * @throws ConversionException
 88  
      *             if unable to create Pattern object.
 89  
      **/
 90  
     public static Pattern createPattern(String pattern) {
 91  906
         return createPattern(pattern, 0);
 92  
     }
 93  
 
 94  
     /**
 95  
      * Helper method to create a regular expression with a specific flags.
 96  
      *
 97  
      * @param pattern
 98  
      *            the pattern to match
 99  
      * @param flags
 100  
      *            the flags to set
 101  
      * @return a created regexp object
 102  
      * @throws IllegalArgumentException
 103  
      *             if unable to create Pattern object.
 104  
      **/
 105  
     public static Pattern createPattern(String pattern, int flags) {
 106  
         try {
 107  954
             return Pattern.compile(pattern, flags);
 108  
         }
 109  3
         catch (final PatternSyntaxException ex) {
 110  3
             throw new IllegalArgumentException(
 111  
                 "Failed to initialise regular expression " + pattern, ex);
 112  
         }
 113  
     }
 114  
 
 115  
     /**
 116  
      * Create block comment from string content.
 117  
      * @param content comment content.
 118  
      * @return DetailAST block comment
 119  
      */
 120  
     public static DetailAST createBlockCommentNode(String content) {
 121  57
         final DetailAST blockCommentBegin = new DetailAST();
 122  57
         blockCommentBegin.setType(TokenTypes.BLOCK_COMMENT_BEGIN);
 123  57
         blockCommentBegin.setText(BLOCK_MULTIPLE_COMMENT_BEGIN);
 124  57
         blockCommentBegin.setLineNo(0);
 125  57
         blockCommentBegin.setColumnNo(-JAVADOC_START.length());
 126  
 
 127  57
         final DetailAST commentContent = new DetailAST();
 128  57
         commentContent.setType(TokenTypes.COMMENT_CONTENT);
 129  57
         commentContent.setText("*" + content);
 130  57
         commentContent.setLineNo(0);
 131  
         // javadoc should starts at 0 column, so COMMENT_CONTENT node
 132  
         // that contains javadoc identificator has -1 column
 133  57
         commentContent.setColumnNo(-1);
 134  
 
 135  57
         final DetailAST blockCommentEnd = new DetailAST();
 136  57
         blockCommentEnd.setType(TokenTypes.BLOCK_COMMENT_END);
 137  57
         blockCommentEnd.setText(BLOCK_MULTIPLE_COMMENT_END);
 138  
 
 139  57
         blockCommentBegin.setFirstChild(commentContent);
 140  57
         commentContent.setNextSibling(blockCommentEnd);
 141  57
         return blockCommentBegin;
 142  
     }
 143  
 
 144  
     /**
 145  
      * Create block comment from token.
 146  
      * @param token
 147  
      *        Token object.
 148  
      * @return DetailAST with BLOCK_COMMENT type.
 149  
      */
 150  
     public static DetailAST createBlockCommentNode(Token token) {
 151  2644
         final DetailAST blockComment = new DetailAST();
 152  2644
         blockComment.initialize(TokenTypes.BLOCK_COMMENT_BEGIN, BLOCK_MULTIPLE_COMMENT_BEGIN);
 153  
 
 154  
         // column counting begins from 0
 155  2644
         blockComment.setColumnNo(token.getColumn() - 1);
 156  2644
         blockComment.setLineNo(token.getLine());
 157  
 
 158  2644
         final DetailAST blockCommentContent = new DetailAST();
 159  2644
         blockCommentContent.setType(TokenTypes.COMMENT_CONTENT);
 160  
 
 161  
         // column counting begins from 0
 162  
         // plus length of '/*'
 163  2644
         blockCommentContent.setColumnNo(token.getColumn() - 1 + 2);
 164  2644
         blockCommentContent.setLineNo(token.getLine());
 165  2644
         blockCommentContent.setText(token.getText());
 166  
 
 167  2644
         final DetailAST blockCommentClose = new DetailAST();
 168  2644
         blockCommentClose.initialize(TokenTypes.BLOCK_COMMENT_END, BLOCK_MULTIPLE_COMMENT_END);
 169  
 
 170  5288
         final Map.Entry<Integer, Integer> linesColumns = countLinesColumns(
 171  2644
                 token.getText(), token.getLine(), token.getColumn());
 172  2644
         blockCommentClose.setLineNo(linesColumns.getKey());
 173  2644
         blockCommentClose.setColumnNo(linesColumns.getValue());
 174  
 
 175  2644
         blockComment.addChild(blockCommentContent);
 176  2644
         blockComment.addChild(blockCommentClose);
 177  2644
         return blockComment;
 178  
     }
 179  
 
 180  
     /**
 181  
      * Count lines and columns (in last line) in text.
 182  
      * @param text
 183  
      *        String.
 184  
      * @param initialLinesCnt
 185  
      *        initial value of lines counter.
 186  
      * @param initialColumnsCnt
 187  
      *        initial value of columns counter.
 188  
      * @return entry(pair), first element is lines counter, second - columns
 189  
      *         counter.
 190  
      */
 191  
     private static Map.Entry<Integer, Integer> countLinesColumns(
 192  
             String text, int initialLinesCnt, int initialColumnsCnt) {
 193  2644
         int lines = initialLinesCnt;
 194  2644
         int columns = initialColumnsCnt;
 195  2644
         boolean foundCr = false;
 196  101236
         for (char c : text.toCharArray()) {
 197  98592
             if (c == '\n') {
 198  3157
                 foundCr = false;
 199  3157
                 lines++;
 200  3157
                 columns = 0;
 201  
             }
 202  
             else {
 203  95435
                 if (foundCr) {
 204  5
                     foundCr = false;
 205  5
                     lines++;
 206  5
                     columns = 0;
 207  
                 }
 208  95435
                 if (c == '\r') {
 209  7
                     foundCr = true;
 210  
                 }
 211  95435
                 columns++;
 212  
             }
 213  
         }
 214  2644
         if (foundCr) {
 215  2
             lines++;
 216  2
             columns = 0;
 217  
         }
 218  2644
         return new AbstractMap.SimpleEntry<>(lines, columns);
 219  
     }
 220  
 
 221  
     /**
 222  
      * Returns whether the file extension matches what we are meant to process.
 223  
      *
 224  
      * @param file
 225  
      *            the file to be checked.
 226  
      * @param fileExtensions
 227  
      *            files extensions, empty property in config makes it matches to all.
 228  
      * @return whether there is a match.
 229  
      */
 230  
     public static boolean matchesFileExtension(File file, String... fileExtensions) {
 231  4540
         boolean result = false;
 232  4540
         if (fileExtensions == null || fileExtensions.length == 0) {
 233  1709
             result = true;
 234  
         }
 235  
         else {
 236  
             // normalize extensions so all of them have a leading dot
 237  2831
             final String[] withDotExtensions = new String[fileExtensions.length];
 238  5691
             for (int i = 0; i < fileExtensions.length; i++) {
 239  2860
                 final String extension = fileExtensions[i];
 240  2860
                 if (startsWithChar(extension, '.')) {
 241  2857
                     withDotExtensions[i] = extension;
 242  
                 }
 243  
                 else {
 244  3
                     withDotExtensions[i] = "." + extension;
 245  
                 }
 246  
             }
 247  
 
 248  2831
             final String fileName = file.getName();
 249  2860
             for (final String fileExtension : withDotExtensions) {
 250  2845
                 if (fileName.endsWith(fileExtension)) {
 251  2816
                     result = true;
 252  2816
                     break;
 253  
                 }
 254  
             }
 255  
         }
 256  
 
 257  4540
         return result;
 258  
     }
 259  
 
 260  
     /**
 261  
      * Returns whether the specified string contains only whitespace up to the specified index.
 262  
      *
 263  
      * @param index
 264  
      *            index to check up to
 265  
      * @param line
 266  
      *            the line to check
 267  
      * @return whether there is only whitespace
 268  
      */
 269  
     public static boolean hasWhitespaceBefore(int index, String line) {
 270  1881
         boolean result = true;
 271  18512
         for (int i = 0; i < index; i++) {
 272  17099
             if (!Character.isWhitespace(line.charAt(i))) {
 273  468
                 result = false;
 274  468
                 break;
 275  
             }
 276  
         }
 277  1881
         return result;
 278  
     }
 279  
 
 280  
     /**
 281  
      * Returns the length of a string ignoring all trailing whitespace.
 282  
      * It is a pity that there is not a trim() like
 283  
      * method that only removed the trailing whitespace.
 284  
      *
 285  
      * @param line
 286  
      *            the string to process
 287  
      * @return the length of the string ignoring all trailing whitespace
 288  
      **/
 289  
     public static int lengthMinusTrailingWhitespace(String line) {
 290  4
         int len = line.length();
 291  10
         for (int i = len - 1; i >= 0; i--) {
 292  8
             if (!Character.isWhitespace(line.charAt(i))) {
 293  2
                 break;
 294  
             }
 295  6
             len--;
 296  
         }
 297  4
         return len;
 298  
     }
 299  
 
 300  
     /**
 301  
      * Returns the length of a String prefix with tabs expanded.
 302  
      * Each tab is counted as the number of characters is
 303  
      * takes to jump to the next tab stop.
 304  
      *
 305  
      * @param inputString
 306  
      *            the input String
 307  
      * @param toIdx
 308  
      *            index in string (exclusive) where the calculation stops
 309  
      * @param tabWidth
 310  
      *            the distance between tab stop position.
 311  
      * @return the length of string.substring(0, toIdx) with tabs expanded.
 312  
      */
 313  
     public static int lengthExpandedTabs(String inputString,
 314  
             int toIdx,
 315  
             int tabWidth) {
 316  69210
         int len = 0;
 317  1138479
         for (int idx = 0; idx < toIdx; idx++) {
 318  1069269
             if (inputString.charAt(idx) == '\t') {
 319  1571
                 len = (len / tabWidth + 1) * tabWidth;
 320  
             }
 321  
             else {
 322  1067698
                 len++;
 323  
             }
 324  
         }
 325  69210
         return len;
 326  
     }
 327  
 
 328  
     /**
 329  
      * Validates whether passed string is a valid pattern or not.
 330  
      *
 331  
      * @param pattern
 332  
      *            string to validate
 333  
      * @return true if the pattern is valid false otherwise
 334  
      */
 335  
     public static boolean isPatternValid(String pattern) {
 336  8
         boolean isValid = true;
 337  
         try {
 338  8
             Pattern.compile(pattern);
 339  
         }
 340  2
         catch (final PatternSyntaxException ignored) {
 341  2
             isValid = false;
 342  6
         }
 343  8
         return isValid;
 344  
     }
 345  
 
 346  
     /**
 347  
      * Returns base class name from qualified name.
 348  
      * @param type
 349  
      *            the fully qualified name. Cannot be null
 350  
      * @return the base class name from a fully qualified name
 351  
      */
 352  
     public static String baseClassName(String type) {
 353  
         final String className;
 354  169
         final int index = type.lastIndexOf('.');
 355  169
         if (index == -1) {
 356  1
             className = type;
 357  
         }
 358  
         else {
 359  168
             className = type.substring(index + 1);
 360  
         }
 361  169
         return className;
 362  
     }
 363  
 
 364  
     /**
 365  
      * Constructs a normalized relative path between base directory and a given path.
 366  
      *
 367  
      * @param baseDirectory
 368  
      *            the base path to which given path is relativized
 369  
      * @param path
 370  
      *            the path to relativize against base directory
 371  
      * @return the relative normalized path between base directory and
 372  
      *     path or path if base directory is null.
 373  
      */
 374  
     public static String relativizeAndNormalizePath(final String baseDirectory, final String path) {
 375  
         final String resultPath;
 376  6384
         if (baseDirectory == null) {
 377  6382
             resultPath = path;
 378  
         }
 379  
         else {
 380  2
             final Path pathAbsolute = Paths.get(path).normalize();
 381  2
             final Path pathBase = Paths.get(baseDirectory).normalize();
 382  2
             resultPath = pathBase.relativize(pathAbsolute).toString();
 383  
         }
 384  6384
         return resultPath;
 385  
     }
 386  
 
 387  
     /**
 388  
      * Tests if this string starts with the specified prefix.
 389  
      * <p>
 390  
      * It is faster version of {@link String#startsWith(String)} optimized for
 391  
      *  one-character prefixes at the expense of
 392  
      * some readability. Suggested by SimplifyStartsWith PMD rule:
 393  
      * http://pmd.sourceforge.net/pmd-5.3.1/pmd-java/rules/java/optimizations.html#SimplifyStartsWith
 394  
      * </p>
 395  
      *
 396  
      * @param value
 397  
      *            the {@code String} to check
 398  
      * @param prefix
 399  
      *            the prefix to find
 400  
      * @return {@code true} if the {@code char} is a prefix of the given {@code String};
 401  
      *  {@code false} otherwise.
 402  
      */
 403  
     public static boolean startsWithChar(String value, char prefix) {
 404  5003
         return !value.isEmpty() && value.charAt(0) == prefix;
 405  
     }
 406  
 
 407  
     /**
 408  
      * Tests if this string ends with the specified suffix.
 409  
      * <p>
 410  
      * It is faster version of {@link String#endsWith(String)} optimized for
 411  
      *  one-character suffixes at the expense of
 412  
      * some readability. Suggested by SimplifyStartsWith PMD rule:
 413  
      * http://pmd.sourceforge.net/pmd-5.3.1/pmd-java/rules/java/optimizations.html#SimplifyStartsWith
 414  
      * </p>
 415  
      *
 416  
      * @param value
 417  
      *            the {@code String} to check
 418  
      * @param suffix
 419  
      *            the suffix to find
 420  
      * @return {@code true} if the {@code char} is a suffix of the given {@code String};
 421  
      *  {@code false} otherwise.
 422  
      */
 423  
     public static boolean endsWithChar(String value, char suffix) {
 424  1397
         return !value.isEmpty() && value.charAt(value.length() - 1) == suffix;
 425  
     }
 426  
 
 427  
     /**
 428  
      * Gets constructor of targetClass.
 429  
      * @param targetClass
 430  
      *            from which constructor is returned
 431  
      * @param parameterTypes
 432  
      *            of constructor
 433  
      * @param <T> type of the target class object.
 434  
      * @return constructor of targetClass or {@link IllegalStateException} if any exception occurs
 435  
      * @see Class#getConstructor(Class[])
 436  
      */
 437  
     public static <T> Constructor<T> getConstructor(Class<T> targetClass,
 438  
                                                     Class<?>... parameterTypes) {
 439  
         try {
 440  2914
             return targetClass.getConstructor(parameterTypes);
 441  
         }
 442  1
         catch (NoSuchMethodException ex) {
 443  1
             throw new IllegalStateException(ex);
 444  
         }
 445  
     }
 446  
 
 447  
     /**
 448  
      * Returns new instance of a class.
 449  
      * @param constructor
 450  
      *            to invoke
 451  
      * @param parameters
 452  
      *            to pass to constructor
 453  
      * @param <T>
 454  
      *            type of constructor
 455  
      * @return new instance of class or {@link IllegalStateException} if any exception occurs
 456  
      * @see Constructor#newInstance(Object...)
 457  
      */
 458  
     public static <T> T invokeConstructor(Constructor<T> constructor, Object... parameters) {
 459  
         try {
 460  3105
             return constructor.newInstance(parameters);
 461  
         }
 462  1
         catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
 463  1
             throw new IllegalStateException(ex);
 464  
         }
 465  
     }
 466  
 
 467  
     /**
 468  
      * Closes a stream re-throwing IOException as IllegalStateException.
 469  
      *
 470  
      * @param closeable
 471  
      *            Closeable object
 472  
      */
 473  
     public static void close(Closeable closeable) {
 474  3
         if (closeable != null) {
 475  
             try {
 476  2
                 closeable.close();
 477  
             }
 478  1
             catch (IOException ex) {
 479  1
                 throw new IllegalStateException("Cannot close the stream", ex);
 480  1
             }
 481  
         }
 482  2
     }
 483  
 
 484  
     /**
 485  
      * Resolve the specified filename to a URI.
 486  
      * @param filename name os the file
 487  
      * @return resolved header file URI
 488  
      * @throws CheckstyleException on failure
 489  
      */
 490  
     public static URI getUriByFilename(String filename) throws CheckstyleException {
 491  
         // figure out if this is a File or a URL
 492  
         URI uri;
 493  
         try {
 494  226
             final URL url = new URL(filename);
 495  18
             uri = url.toURI();
 496  
         }
 497  209
         catch (final URISyntaxException | MalformedURLException ignored) {
 498  209
             uri = null;
 499  17
         }
 500  
 
 501  226
         if (uri == null) {
 502  209
             final File file = new File(filename);
 503  209
             if (file.exists()) {
 504  178
                 uri = file.toURI();
 505  
             }
 506  
             else {
 507  
                 // check to see if the file is in the classpath
 508  
                 try {
 509  31
                     final URL configUrl = CommonUtils.class
 510  31
                             .getResource(filename);
 511  31
                     if (configUrl == null) {
 512  18
                         throw new CheckstyleException(UNABLE_TO_FIND_EXCEPTION_PREFIX + filename);
 513  
                     }
 514  13
                     uri = configUrl.toURI();
 515  
                 }
 516  1
                 catch (final URISyntaxException ex) {
 517  1
                     throw new CheckstyleException(UNABLE_TO_FIND_EXCEPTION_PREFIX + filename, ex);
 518  12
                 }
 519  
             }
 520  
         }
 521  
 
 522  207
         return uri;
 523  
     }
 524  
 
 525  
     /**
 526  
      * Puts part of line, which matches regexp into given template
 527  
      * on positions $n where 'n' is number of matched part in line.
 528  
      * @param template the string to expand.
 529  
      * @param lineToPlaceInTemplate contains expression which should be placed into string.
 530  
      * @param regexp expression to find in comment.
 531  
      * @return the string, based on template filled with given lines
 532  
      */
 533  
     public static String fillTemplateWithStringsByRegexp(
 534  
         String template, String lineToPlaceInTemplate, Pattern regexp) {
 535  154
         final Matcher matcher = regexp.matcher(lineToPlaceInTemplate);
 536  154
         String result = template;
 537  154
         if (matcher.find()) {
 538  423
             for (int i = 0; i <= matcher.groupCount(); i++) {
 539  
                 // $n expands comment match like in Pattern.subst().
 540  272
                 result = result.replaceAll("\\$" + i, matcher.group(i));
 541  
             }
 542  
         }
 543  154
         return result;
 544  
     }
 545  
 
 546  
     /**
 547  
      * Returns file name without extension.
 548  
      * We do not use the method from Guava library to reduce Checkstyle's dependencies
 549  
      * on external libraries.
 550  
      * @param fullFilename file name with extension.
 551  
      * @return file name without extension.
 552  
      */
 553  
     public static String getFileNameWithoutExtension(String fullFilename) {
 554  2
         final String fileName = new File(fullFilename).getName();
 555  2
         final int dotIndex = fileName.lastIndexOf('.');
 556  
         final String fileNameWithoutExtension;
 557  2
         if (dotIndex == -1) {
 558  1
             fileNameWithoutExtension = fileName;
 559  
         }
 560  
         else {
 561  1
             fileNameWithoutExtension = fileName.substring(0, dotIndex);
 562  
         }
 563  2
         return fileNameWithoutExtension;
 564  
     }
 565  
 
 566  
     /**
 567  
      * Returns file extension for the given file name
 568  
      * or empty string if file does not have an extension.
 569  
      * We do not use the method from Guava library to reduce Checkstyle's dependencies
 570  
      * on external libraries.
 571  
      * @param fileNameWithExtension file name with extension.
 572  
      * @return file extension for the given file name
 573  
      *         or empty string if file does not have an extension.
 574  
      */
 575  
     public static String getFileExtension(String fileNameWithExtension) {
 576  49
         final String fileName = Paths.get(fileNameWithExtension).toString();
 577  49
         final int dotIndex = fileName.lastIndexOf('.');
 578  
         final String extension;
 579  49
         if (dotIndex == -1) {
 580  1
             extension = "";
 581  
         }
 582  
         else {
 583  48
             extension = fileName.substring(dotIndex + 1);
 584  
         }
 585  49
         return extension;
 586  
     }
 587  
 
 588  
     /**
 589  
      * Checks whether the given string is a valid identifier.
 590  
      * @param str A string to check.
 591  
      * @return true when the given string contains valid identifier.
 592  
      */
 593  
     public static boolean isIdentifier(String str) {
 594  173
         boolean isIdentifier = !str.isEmpty();
 595  
 
 596  1345
         for (int i = 0; isIdentifier && i < str.length(); i++) {
 597  1172
             if (i == 0) {
 598  168
                 isIdentifier = Character.isJavaIdentifierStart(str.charAt(0));
 599  
             }
 600  
             else {
 601  1004
                 isIdentifier = Character.isJavaIdentifierPart(str.charAt(i));
 602  
             }
 603  
         }
 604  
 
 605  173
         return isIdentifier;
 606  
     }
 607  
 
 608  
     /**
 609  
      * Checks whether the given string is a valid name.
 610  
      * @param str A string to check.
 611  
      * @return true when the given string contains valid name.
 612  
      */
 613  
     public static boolean isName(String str) {
 614  28
         boolean isName = !str.isEmpty();
 615  
 
 616  28
         final String[] identifiers = str.split("\\.", -1);
 617  197
         for (int i = 0; isName && i < identifiers.length; i++) {
 618  169
             isName = isIdentifier(identifiers[i]);
 619  
         }
 620  
 
 621  28
         return isName;
 622  
     }
 623  
 
 624  
     /**
 625  
      * Checks if the value arg is blank by either being null,
 626  
      * empty, or contains only whitespace characters.
 627  
      * @param value A string to check.
 628  
      * @return true if the arg is blank.
 629  
      */
 630  
     public static boolean isBlank(String value) {
 631  28411
         boolean result = true;
 632  28411
         if (value != null && !value.isEmpty()) {
 633  179420
             for (int i = 0; i < value.length(); i++) {
 634  179003
                 if (!Character.isWhitespace(value.charAt(i))) {
 635  22925
                     result = false;
 636  22925
                     break;
 637  
                 }
 638  
             }
 639  
         }
 640  28411
         return result;
 641  
     }
 642  
 
 643  
     /**
 644  
      * Checks whether the string contains an integer value.
 645  
      * @param str a string to check
 646  
      * @return true if the given string is an integer, false otherwise.
 647  
      */
 648  
     public static boolean isInt(String str) {
 649  
         boolean isInt;
 650  13
         if (str == null) {
 651  1
             isInt = false;
 652  
         }
 653  
         else {
 654  
             try {
 655  12
                 Integer.parseInt(str);
 656  9
                 isInt = true;
 657  
             }
 658  3
             catch (NumberFormatException ignored) {
 659  3
                 isInt = false;
 660  9
             }
 661  
         }
 662  13
         return isInt;
 663  
     }
 664  
 }