1 /**
2 * Copyright 2005-2014 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.kuali.rice.krad.theme.util;
17
18 import org.apache.commons.lang3.StringUtils;
19 import org.codehaus.plexus.util.DirectoryScanner;
20 import org.codehaus.plexus.util.FileUtils;
21 import org.codehaus.plexus.util.SelectorUtils;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileWriter;
26 import java.io.IOException;
27 import java.util.ArrayList;
28 import java.util.List;
29 import java.util.Properties;
30
31 /**
32 * Utility methods for the view builder module
33 *
34 * @author Kuali Rice Team (rice.collab@kuali.org)
35 */
36 public class ThemeBuilderUtils {
37
38 /**
39 * Retrieve the {@link Properties} object loaded from the theme.properties file found in the given
40 * theme directory
41 *
42 * @param themeDirectory directory for the theme to pull properties file from
43 * @return Properties object loaded with the theme configuration, or null if the properties file
44 * does not exist
45 * @throws IOException
46 */
47 public static Properties retrieveThemeProperties(String themeDirectory) throws IOException {
48 Properties themeProperties = null;
49
50 FileInputStream fileInputStream = null;
51
52 try {
53 File propertiesFile = new File(themeDirectory, ThemeBuilderConstants.THEME_PROPERTIES_FILE);
54
55 if (propertiesFile.exists()) {
56 fileInputStream = new FileInputStream(propertiesFile);
57
58 themeProperties = new Properties();
59 themeProperties.load(fileInputStream);
60 }
61 } finally {
62 if (fileInputStream != null) {
63 fileInputStream.close();
64 }
65 }
66
67 return themeProperties;
68 }
69
70 /**
71 * Stores the given properties object in a file named <code>theme-derived.properties</code> within the
72 * given theme directory
73 *
74 * @param themeDirectory directory the properties file should be created in
75 * @param themeProperties properties that should be written to the properties file
76 * @throws IOException
77 */
78 public static void storeThemeProperties(String themeDirectory, Properties themeProperties) throws IOException {
79 File propertiesFile = new File(themeDirectory, ThemeBuilderConstants.THEME_DERIVED_PROPERTIES_FILE);
80
81 // need to remove file if already exists so the new properties will be written
82 if (propertiesFile.exists()) {
83 FileUtils.forceDelete(propertiesFile);
84 }
85
86 FileWriter fileWriter = null;
87
88 try {
89 fileWriter = new FileWriter(propertiesFile);
90
91 themeProperties.store(fileWriter, null);
92 } finally {
93 if (fileWriter != null) {
94 fileWriter.close();
95 }
96 }
97 }
98
99 /**
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 }