001/** 002 * Copyright 2005-2016 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.theme.util; 017 018import org.apache.commons.lang3.StringUtils; 019import org.codehaus.plexus.util.DirectoryScanner; 020import org.codehaus.plexus.util.FileUtils; 021import org.codehaus.plexus.util.SelectorUtils; 022 023import java.io.File; 024import java.io.FileInputStream; 025import java.io.FileWriter; 026import java.io.IOException; 027import java.util.ArrayList; 028import java.util.List; 029import java.util.Properties; 030 031/** 032 * Utility methods for the view builder module 033 * 034 * @author Kuali Rice Team (rice.collab@kuali.org) 035 */ 036public class ThemeBuilderUtils { 037 038 /** 039 * Retrieve the {@link Properties} object loaded from the theme.properties file found in the given 040 * theme directory 041 * 042 * @param themeDirectory directory for the theme to pull properties file from 043 * @return Properties object loaded with the theme configuration, or null if the properties file 044 * does not exist 045 * @throws IOException 046 */ 047 public static Properties retrieveThemeProperties(String themeDirectory) throws IOException { 048 Properties themeProperties = null; 049 050 FileInputStream fileInputStream = null; 051 052 try { 053 File propertiesFile = new File(themeDirectory, ThemeBuilderConstants.THEME_PROPERTIES_FILE); 054 055 if (propertiesFile.exists()) { 056 fileInputStream = new FileInputStream(propertiesFile); 057 058 themeProperties = new Properties(); 059 themeProperties.load(fileInputStream); 060 } 061 } finally { 062 if (fileInputStream != null) { 063 fileInputStream.close(); 064 } 065 } 066 067 return themeProperties; 068 } 069 070 /** 071 * Stores the given properties object in a file named <code>theme-derived.properties</code> within the 072 * given theme directory 073 * 074 * @param themeDirectory directory the properties file should be created in 075 * @param themeProperties properties that should be written to the properties file 076 * @throws IOException 077 */ 078 public static void storeThemeProperties(String themeDirectory, Properties themeProperties) throws IOException { 079 File propertiesFile = new File(themeDirectory, ThemeBuilderConstants.THEME_DERIVED_PROPERTIES_FILE); 080 081 // need to remove file if already exists so the new properties will be written 082 if (propertiesFile.exists()) { 083 FileUtils.forceDelete(propertiesFile); 084 } 085 086 FileWriter fileWriter = null; 087 088 try { 089 fileWriter = new FileWriter(propertiesFile); 090 091 themeProperties.store(fileWriter, null); 092 } finally { 093 if (fileWriter != null) { 094 fileWriter.close(); 095 } 096 } 097 } 098 099 /** 100 * Retrieves the value for the property with the given key from the properties object, as a list of 101 * strings (by splitting the value on commas) 102 * 103 * @param key key for the property to retrieve 104 * @param properties properties object to pull property from 105 * @return list of strings parsed from the property value 106 */ 107 public static List<String> getPropertyValueAsList(String key, Properties properties) { 108 List<String> propertyValueList = null; 109 110 String[] propertyValueArray = getPropertyValueAsArray(key, properties); 111 if (propertyValueArray != null) { 112 propertyValueList = new ArrayList<String>(); 113 114 for (String value : propertyValueArray) { 115 propertyValueList.add(value); 116 } 117 } 118 119 return propertyValueList; 120 } 121 122 /** 123 * Retrieves the value for the property with the given key from the properties object, as an array of 124 * strings (by splitting the value on commas) 125 * 126 * @param key key for the property to retrieve 127 * @param properties properties object to pull property from 128 * @return array of strings parsed from the property value 129 */ 130 public static String[] getPropertyValueAsArray(String key, Properties properties) { 131 String[] propertyValue = null; 132 133 if (properties.containsKey(key)) { 134 String propertyValueString = properties.getProperty(key); 135 136 if (!StringUtils.isBlank(propertyValueString)) { 137 propertyValue = propertyValueString.split(","); 138 } 139 } 140 141 return propertyValue; 142 } 143 144 /** 145 * Copies the property key/value from the source properties to the target properties if a property with the 146 * same key does not exist in the target properties 147 * 148 * @param propertyKey key of the property to copy 149 * @param sourceProperties properties to pull the property from 150 * @param targetProperties properties to copy the property to 151 */ 152 public static void copyProperty(String propertyKey, Properties sourceProperties, Properties targetProperties) { 153 if (targetProperties != null && targetProperties.containsKey(propertyKey) && StringUtils.isNotBlank( 154 targetProperties.getProperty(propertyKey))) { 155 return; 156 } 157 158 if (sourceProperties != null && sourceProperties.containsKey(propertyKey)) { 159 String propertyValue = sourceProperties.getProperty(propertyKey); 160 161 if (targetProperties == null) { 162 targetProperties = new Properties(); 163 } 164 165 targetProperties.put(propertyKey, propertyValue); 166 } 167 } 168 169 /** 170 * Iterates through each file in the given list and verifies the file exists, if not a runtime 171 * exception is thrown with the provided message 172 * 173 * @param filesToValidate list of files to check existence for 174 * @param exceptionMessage message for runtime exception if a file is found that does not exist 175 */ 176 public static void validateFileExistence(List<File> filesToValidate, String exceptionMessage) { 177 if (filesToValidate == null) { 178 return; 179 } 180 181 for (File file : filesToValidate) { 182 if (!file.exists()) { 183 throw new RuntimeException(exceptionMessage + " Path: " + file.getPath()); 184 } 185 } 186 } 187 188 /** 189 * Indicates whether there is a file with the given name within the given directory 190 * 191 * @param directory directory to check for file 192 * @param fileName name of the file to check for 193 * @return true if there is a file in the directory, false if not 194 */ 195 public static boolean directoryContainsFile(File directory, String fileName) { 196 boolean containsFile = false; 197 198 List<String> directoryContents = getDirectoryContents(directory, null, null); 199 200 for (String directoryFile : directoryContents) { 201 String directoryFilename = FileUtils.filename(directoryFile); 202 203 if (directoryFilename.equals(fileName)) { 204 containsFile = true; 205 } 206 } 207 208 return containsFile; 209 } 210 211 /** 212 * Retrieves a list of files that are in the given directory, possibly filtered by the list of include 213 * patterns or exclude patterns 214 * 215 * @param baseDirectory directory to retrieve files from 216 * @param includes list of patterns to match against for files to include, can include Ant patterns 217 * @param excludes list of patterns to match for excluded files, can include Ant patterns 218 * @return list of files within the directory that match all given patterns 219 */ 220 public static List<File> getDirectoryFiles(File baseDirectory, String[] includes, String[] excludes) { 221 List<File> directoryFiles = new ArrayList<File>(); 222 223 List<String> directoryFileNames = getDirectoryFileNames(baseDirectory, includes, excludes); 224 225 for (String fileName : directoryFileNames) { 226 directoryFiles.add(new File(baseDirectory, fileName)); 227 } 228 229 return directoryFiles; 230 } 231 232 /** 233 * Retrieves a list of file names that are in the given directory, possibly filtered by the list of include 234 * patterns or exclude patterns 235 * 236 * @param baseDirectory directory to retrieve file names from 237 * @param includes list of patterns to match against for file names to include, can include Ant patterns 238 * @param excludes list of patterns to match for excluded file names, can include Ant patterns 239 * @return list of file names within the directory that match all given patterns 240 */ 241 public static List<String> getDirectoryFileNames(File baseDirectory, String[] includes, String[] excludes) { 242 List<String> files = new ArrayList<String>(); 243 244 DirectoryScanner scanner = new DirectoryScanner(); 245 246 if (includes != null) { 247 scanner.setIncludes(includes); 248 } 249 250 if (excludes != null) { 251 scanner.setExcludes(excludes); 252 } 253 254 scanner.setCaseSensitive(false); 255 scanner.addDefaultExcludes(); 256 scanner.setBasedir(baseDirectory); 257 258 scanner.scan(); 259 260 for (String includedFilename : scanner.getIncludedFiles()) { 261 files.add(includedFilename); 262 } 263 264 return files; 265 } 266 267 /** 268 * Get the sub directories of the given directory that have the given names 269 * 270 * @param baseDirectory directory containing the sub directories 271 * @param subDirectoryNames list of sub directory names to return 272 * @return list of Files pointing to the sub directories 273 */ 274 public static List<File> getSubDirectories(File baseDirectory, List<String> subDirectoryNames) { 275 List<File> subDirs = null; 276 277 if (subDirectoryNames != null) { 278 subDirs = new ArrayList<File>(); 279 280 for (String pluginName : subDirectoryNames) { 281 subDirs.add(new File(baseDirectory, pluginName)); 282 } 283 } 284 285 return subDirs; 286 } 287 288 /** 289 * Retrieves a list of files and directories that are in the given directory, possibly filtered by the 290 * list of include patterns or exclude patterns 291 * 292 * @param baseDirectory directory to retrieve files and directories from 293 * @param includes list of patterns to match against for files to include, can include Ant patterns 294 * @param excludes list of patterns to match for excluded files, can include Ant patterns 295 * @return list of files within the directory that match all given patterns 296 */ 297 public static List<String> getDirectoryContents(File baseDirectory, String[] includes, String[] excludes) { 298 List<String> contents = new ArrayList<String>(); 299 300 DirectoryScanner scanner = new DirectoryScanner(); 301 302 if (includes != null) { 303 scanner.setIncludes(includes); 304 } 305 306 if (excludes != null) { 307 scanner.setExcludes(excludes); 308 } 309 310 scanner.setCaseSensitive(false); 311 scanner.addDefaultExcludes(); 312 scanner.setBasedir(baseDirectory); 313 314 scanner.scan(); 315 316 for (String includedDirectory : scanner.getIncludedDirectories()) { 317 contents.add(includedDirectory); 318 } 319 320 for (String includedFilename : scanner.getIncludedFiles()) { 321 contents.add(includedFilename); 322 } 323 324 return contents; 325 } 326 327 /** 328 * Copies all the contents from the directory given by the source path to the directory given by the 329 * target path 330 * 331 * <p> 332 * If source directory does not exist nothing is performed. The target directory will be created if it 333 * does not exist. Any hidden directories (directory names that start with ".") will be deleted from the 334 * target directory 335 * </p> 336 * 337 * @param sourceDirectoryPath absolute path to the source directory 338 * @param targetDirectoryPath absolute path to the target directory 339 * @throws IOException 340 */ 341 public static void copyDirectory(String sourceDirectoryPath, String targetDirectoryPath) 342 throws IOException { 343 File sourceDir = new File(sourceDirectoryPath); 344 345 if (!sourceDir.exists()) { 346 return; 347 } 348 349 File targetDir = new File(targetDirectoryPath); 350 if (targetDir.exists()) { 351 // force removal so the copy starts clean 352 FileUtils.forceDelete(targetDir); 353 } 354 355 targetDir.mkdir(); 356 357 FileUtils.copyDirectoryStructure(sourceDir, targetDir); 358 359 // remove hidden directories from the target 360 DirectoryScanner scanner = new DirectoryScanner(); 361 scanner.setBasedir(targetDir); 362 363 scanner.scan(); 364 365 for (String includedDirectory : scanner.getIncludedDirectories()) { 366 File subdirectory = new File(targetDir, includedDirectory); 367 368 if (subdirectory.exists() && subdirectory.isDirectory()) { 369 if (subdirectory.getName().startsWith(".")) { 370 FileUtils.forceDelete(subdirectory); 371 } 372 } 373 } 374 } 375 376 /** 377 * Copies all content (files and directories) from the source directory to the target directory, except content 378 * that already exists in the target directory (same name and path), in other words it does not override any 379 * existing content 380 * 381 * <p> 382 * Files from the source directory can be excluded from the copying by setting one or more patterns in the 383 * source excludes list 384 * </p> 385 * 386 * @param sourceDirectory directory to copy content from 387 * @param targetDirectory directory to copy content to 388 * @param sourceExcludes list of patterns to match on for source exclusions 389 * @throws IOException 390 */ 391 public static void copyMissingContent(File sourceDirectory, File targetDirectory, List<String> sourceExcludes) 392 throws IOException { 393 String[] copyExcludes = null; 394 395 if ((sourceExcludes != null) && !sourceExcludes.isEmpty()) { 396 copyExcludes = new String[sourceExcludes.size()]; 397 398 copyExcludes = sourceExcludes.toArray(copyExcludes); 399 } 400 401 List<String> sourceDirectoryContents = getDirectoryContents(sourceDirectory, null, copyExcludes); 402 List<String> targetDirectoryContents = getDirectoryContents(targetDirectory, null, null); 403 404 for (String sourceContent : sourceDirectoryContents) { 405 if (targetDirectoryContents.contains(sourceContent)) { 406 continue; 407 } 408 409 // copy file to target 410 File sourceFile = new File(sourceDirectory, sourceContent); 411 File targetFile = new File(targetDirectory, sourceContent); 412 413 if (sourceFile.isDirectory()) { 414 targetFile.mkdir(); 415 } else { 416 FileUtils.copyFile(sourceFile, targetFile); 417 } 418 } 419 } 420 421 /** 422 * Determines if one of the given patterns matches the given name, or if the include list is null 423 * or empty the file will be included 424 * 425 * @param name string to match 426 * @param includes list of string patterns to match on 427 * @return true if the name is a match, false if not 428 */ 429 public static boolean inIncludeList(String name, String[] includes) { 430 if ((includes == null) || (includes.length == 0)) { 431 return true; 432 } 433 434 for (String include : includes) { 435 if (SelectorUtils.matchPath(include, name, false)) { 436 return true; 437 } 438 } 439 440 return false; 441 } 442 443 /** 444 * Determines if one of the given patterns matches the given name, or if the exclude list is null 445 * or empty the file will not be excluded 446 * 447 * @param name string to match 448 * @param excludes list of string patterns to match on 449 * @return true if the name is a match, false if not 450 */ 451 public static boolean inExcludeList(String name, String[] excludes) { 452 if ((excludes == null) || (excludes.length == 0)) { 453 return false; 454 } 455 456 for (String exclude : excludes) { 457 if (SelectorUtils.matchPath(exclude, name, false)) { 458 return true; 459 } 460 } 461 462 return false; 463 } 464 465 /** 466 * Iterates through the given list of patterns and checks whether the pattern ends with the given 467 * extension or a wildcard, if not the extension is appended to the pattern 468 * 469 * @param patterns array of patterns to check and append to if necessary 470 * @param extension string extension to check for and append if necessary 471 */ 472 public static void addExtensionToPatterns(String[] patterns, String extension) { 473 if (patterns == null) { 474 return; 475 } 476 477 for (int i = 0; i < patterns.length; i++) { 478 String pattern = patterns[i]; 479 480 if (!(pattern.endsWith("*") || pattern.endsWith(extension))) { 481 patterns[i] = pattern + extension; 482 } 483 } 484 } 485 486 /** 487 * Builds a list of strings that hold the path from each given file relative to the parent 488 * directory 489 * 490 * @param parentDirectory directory to build path from 491 * @param files list of files to build relative paths for 492 * @return list of strings containing the relative paths 493 */ 494 public static List<String> getRelativePaths(File parentDirectory, List<File> files) { 495 List<String> relativePaths = new ArrayList<String>(); 496 497 for (File file : files) { 498 relativePaths.add(getRelativePath(parentDirectory, file)); 499 } 500 501 return relativePaths; 502 } 503 504 /** 505 * Returns the path of the given file relative to the parent directory 506 * 507 * @param parentDirectory directory to build path from 508 * @param file file to build relative paths for 509 * @return string containing the relative path 510 */ 511 public static String getRelativePath(File parentDirectory, File file) { 512 String relativePath = null; 513 514 String parentPath = parentDirectory.getPath(); 515 String childPath = file.getPath(); 516 517 if (childPath.startsWith(parentPath + File.separator)) { 518 relativePath = childPath.substring(parentPath.length() + 1); 519 } 520 521 // switch path separators 522 relativePath = relativePath.replaceAll("\\\\", "/"); 523 524 return relativePath; 525 } 526 527 /** 528 * Calculates the path from the first file to the second 529 * 530 * <p> 531 * Assumes there is a common base directory somewhere in the path of both files. Once it finds that base 532 * directory, builds the path starting at the from file to it, then adds the path from the base directory 533 * to the target file 534 * </p> 535 * 536 * @param fromFile file whose path is the starting point 537 * @param toFile file whose path is the ending point 538 * @return string containing the path 539 */ 540 public static String calculatePathToFile(File fromFile, File toFile) { 541 String pathToFile = ""; 542 543 int directoriesUp = 0; 544 String parentPath = fromFile.getParent(); 545 546 while ((parentPath != null) && !fileMatchesPath(parentPath, toFile)) { 547 File parent = new File(parentPath); 548 549 parentPath = parent.getParent(); 550 directoriesUp += 1; 551 } 552 553 if (parentPath != null) { 554 for (int i = 0; i < directoriesUp; i++) { 555 pathToFile += "../"; 556 } 557 558 String remainingPath = toFile.getPath().replace(parentPath, ""); 559 560 if (remainingPath.startsWith(File.separator)) { 561 remainingPath = remainingPath.substring(1); 562 } 563 564 // switch path separators 565 remainingPath = remainingPath.replaceAll("\\\\", "/"); 566 567 // remove file name from path 568 if (remainingPath.contains("/")) { 569 int separatorIndex = remainingPath.lastIndexOf("/"); 570 remainingPath = remainingPath.substring(0, separatorIndex + 1); 571 } else { 572 // file in same directory, no remaining path 573 remainingPath = null; 574 } 575 576 if (remainingPath != null) { 577 pathToFile += remainingPath; 578 } 579 } 580 581 return pathToFile; 582 } 583 584 /** 585 * Indicates whether the given file is withing the given path (file's path starts with the given path), note 586 * this does not check whether the file exists 587 * 588 * @param path path to check for 589 * @param file file whose path should be checked 590 * @return true if the file is contained in the path, false if not 591 */ 592 protected static boolean fileMatchesPath(String path, File file) { 593 return file.getPath().startsWith(path); 594 } 595 596 /** 597 * Orders the list of plugin files and sub directory files according to the given patterns 598 * 599 * @param pluginFiles list of plugin files to order 600 * @param subDirFiles list of sub directory files to order 601 * @param loadFirstPatterns list of patterns for files that should be ordered first 602 * @param loadLastPatterns list of patterns for files that should be ordered last 603 * @param pluginLoadOrder list of patterns for ordering the plugin files 604 * @param subDirLoadOrder list of patterns for ordering the sub directory files 605 * @return list containing all of the given plugin and sub directory files ordered by the given patterns 606 */ 607 public static List<File> orderFiles(List<File> pluginFiles, List<File> subDirFiles, List<String> loadFirstPatterns, 608 List<String> loadLastPatterns, List<String> pluginLoadOrder, List<String> subDirLoadOrder) { 609 List<File> orderedFiles = new ArrayList<File>(); 610 611 List<File> allThemeFiles = new ArrayList<File>(); 612 if (pluginFiles != null) { 613 allThemeFiles.addAll(pluginFiles); 614 } 615 616 if (subDirFiles != null) { 617 allThemeFiles.addAll(subDirFiles); 618 } 619 620 // build end of the ordered list since those should take priority 621 List<File> endFiles = new ArrayList<File>(); 622 623 if (loadLastPatterns != null) { 624 for (String pattern : loadLastPatterns) { 625 endFiles.addAll(matchFiles(allThemeFiles, pattern)); 626 } 627 } 628 629 // build beginning of the ordered list 630 if (loadFirstPatterns != null) { 631 for (String pattern : loadFirstPatterns) { 632 List<File> matchedFiles = matchFiles(allThemeFiles, pattern); 633 matchedFiles.removeAll(endFiles); 634 635 orderedFiles.addAll(matchedFiles); 636 } 637 } 638 639 // add plugin files that have been configured to load before other plugin files 640 if (pluginLoadOrder != null) { 641 for (String pattern : pluginLoadOrder) { 642 List<File> matchedFiles = matchFiles(pluginFiles, pattern); 643 matchedFiles.removeAll(endFiles); 644 matchedFiles.removeAll(orderedFiles); 645 646 orderedFiles.addAll(matchedFiles); 647 } 648 } 649 650 // add remaining plugin files 651 if (pluginFiles != null) { 652 for (File pluginFile : pluginFiles) { 653 if (!orderedFiles.contains(pluginFile) && !endFiles.contains(pluginFile)) { 654 orderedFiles.add(pluginFile); 655 } 656 } 657 } 658 659 // add sub dir files that have been configured to load before other sub dir files 660 if (subDirLoadOrder != null) { 661 for (String pattern : subDirLoadOrder) { 662 List<File> matchedFiles = matchFiles(subDirFiles, pattern); 663 matchedFiles.removeAll(endFiles); 664 matchedFiles.removeAll(orderedFiles); 665 666 orderedFiles.addAll(matchedFiles); 667 } 668 } 669 670 // add remaining sub dir files 671 if (subDirFiles != null) { 672 for (File subDirFile : subDirFiles) { 673 if (!orderedFiles.contains(subDirFile) && !endFiles.contains(subDirFile)) { 674 orderedFiles.add(subDirFile); 675 } 676 } 677 } 678 679 // now add the end files in reverse to the ordered list 680 File[] endFileArray = new File[endFiles.size()]; 681 endFileArray = endFiles.toArray(endFileArray); 682 683 for (int i = endFileArray.length - 1; i >= 0; i--) { 684 orderedFiles.add(endFileArray[i]); 685 } 686 687 return orderedFiles; 688 } 689 690 /** 691 * Iterates through the list of files and returns those files whose names matches the given pattern 692 * 693 * @param filesToMatch list of files to match 694 * @param pattern pattern to match on 695 * @return list of files whose name that match the pattern 696 */ 697 public static List<File> matchFiles(List<File> filesToMatch, String pattern) { 698 List<File> matchedFiles = new ArrayList<File>(); 699 700 for (File file : filesToMatch) { 701 if (isMatch(file, pattern)) { 702 matchedFiles.add(file); 703 } 704 } 705 706 return matchedFiles; 707 } 708 709 /** 710 * Indicates whether the base name for the given file (name without path and the extension) matches 711 * the given pattern 712 * 713 * @param file file to match 714 * @param pattern pattern to match on 715 * @return true if the file name matches the pattern, false if not 716 */ 717 public static boolean isMatch(File file, String pattern) { 718 boolean isMatch = false; 719 720 String fileBasename = FileUtils.basename(file.getName()); 721 if (fileBasename.endsWith(".")) { 722 fileBasename = fileBasename.substring(0, fileBasename.length() - 1); 723 } 724 725 if (SelectorUtils.matchPath(pattern, fileBasename, false)) { 726 isMatch = true; 727 } 728 729 return isMatch; 730 } 731 732 /** 733 * Returns a list of files from the given list of files, that are contained within one of the given 734 * list of directories 735 * 736 * @param files list of files to filter 737 * @param directories list of directories to filter by 738 * @return list of files that are contained in the directories 739 */ 740 public static List<File> getContainedFiles(List<File> files, List<File> directories) { 741 List<File> directoryFiles = new ArrayList<File>(); 742 743 for (File directory : directories) { 744 for (File file : files) { 745 if (ThemeBuilderUtils.directoryContainsFile(directory, file.getName())) { 746 directoryFiles.add(file); 747 } 748 } 749 } 750 751 return directoryFiles; 752 } 753 754 /** 755 * Adds the string to the end of the array of strings, or creates a new array containing the string 756 * if the array parameter is null 757 * 758 * @param array string array to add to 759 * @param stringToAdd string to add 760 * @return array containing all the original array elements plus the string 761 */ 762 public static String[] addToArray(String[] array, String stringToAdd) { 763 String[] arrayToAdd = null; 764 765 if (stringToAdd != null) { 766 arrayToAdd = new String[1]; 767 arrayToAdd[0] = stringToAdd; 768 } 769 770 return addToArray(array, arrayToAdd); 771 } 772 773 /** 774 * Adds the second array of strings to the end of the first array of strings, or creates a new array 775 * containing the second array elements if the first does not exist 776 * 777 * <p> 778 * Note: Can't use org.apache.commons.lang.ArrayUtils#addAll(java.lang.Object[], java.lang.Object[]) because it 779 * doesn't allow String arrays to be passed in. Latest version of ArrayUtils uses generics and does 780 * </p> 781 * 782 * @param array array to add to 783 * @param arrayToAdd array to add 784 * @return array containing all the strings from both arrays 785 */ 786 public static String[] addToArray(String[] array, String[] arrayToAdd) { 787 if (array == null) { 788 return arrayToAdd; 789 } else if (arrayToAdd == null) { 790 return array; 791 } 792 793 int combinedArrayLength = array.length + arrayToAdd.length; 794 795 String[] combinedArray = new String[combinedArrayLength]; 796 797 for (int i = 0; i < array.length; i++) { 798 combinedArray[i] = array[i]; 799 } 800 801 for (int i = 0; i < arrayToAdd.length; i++) { 802 combinedArray[i + array.length] = arrayToAdd[i]; 803 } 804 805 return combinedArray; 806 } 807 808 /** 809 * Builds a string formed with the name for each file in the list delimited by commas 810 * 811 * @param list list to join names for 812 * @return string containing all the file names 813 */ 814 public static String joinFileList(List<File> list) { 815 String joinedString = null; 816 817 if (list != null) { 818 joinedString = ""; 819 820 for (File file : list) { 821 if (!"".equals(joinedString)) { 822 joinedString += ","; 823 } 824 825 joinedString += file.getName(); 826 } 827 } 828 829 return joinedString; 830 } 831 832}