Project

General

Profile

Download (20.4 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
* Copyright (C) 2007 EDIT
3
* European Distributed Institute of Taxonomy
4
* http://www.e-taxonomy.eu
5
*
6
* The contents of this file are subject to the Mozilla Public License Version 1.1
7
* See LICENSE.TXT at the top of this package for the full license terms.
8
*/
9

    
10
package eu.etaxonomy.cdm.common;
11

    
12
import java.io.BufferedReader;
13
import java.io.File;
14
import java.io.IOException;
15
import java.io.InputStream;
16
import java.io.InputStreamReader;
17
import java.lang.annotation.Annotation;
18
import java.lang.reflect.Field;
19
import java.lang.reflect.Modifier;
20
import java.net.HttpURLConnection;
21
import java.net.MalformedURLException;
22
import java.net.URI;
23
import java.net.URISyntaxException;
24
import java.net.URL;
25
import java.util.ArrayList;
26
import java.util.HashMap;
27
import java.util.List;
28
import java.util.Map;
29
import java.util.regex.Matcher;
30
import java.util.regex.Pattern;
31

    
32
import org.apache.commons.lang.StringUtils;
33
import org.apache.log4j.Logger;
34

    
35
/**
36
 * Util class for consistent access to and creation of per instance application configuration files.
37
 *
38
 * @author a.mueller
39
 * @author a.kohlbecker
40
 */
41
public class CdmUtils {
42

    
43
    private static final Logger logger = Logger.getLogger(CdmUtils.class);
44

    
45
    // ============= TODO externalize into CdmFileUtils class ? ========== //
46

    
47
    private static final String USER_HOME = System.getProperty("user.home");
48

    
49
    /**
50
     * The per user cdm folder name: ".cdmLibrary"
51
     */
52
    private static final String CDM_FOLDER_NAME = ".cdmLibrary";
53

    
54
    /**
55
     * The per user cdm folder "~/.cdmLibrary"
56
     */
57
    public final static File PER_USER_CDM_FOLDER = new File(USER_HOME + File.separator + CDM_FOLDER_NAME );
58

    
59
    /**
60
     * suggested sub folder for web app related data and configurations.
61
     * Each webapp instance should use a dedicated subfolder or file
62
     * which is named by the data source bean id.
63
     */
64
    public static final String SUBFOLDER_WEBAPP = "remote-webapp";
65

    
66
    static final String MUST_EXIST_FILE = "MUST-EXIST.txt";
67

    
68
    //folder separator
69
    static String folderSeparator;
70

    
71
    public static File getCdmHomeDir() {
72
        return new File(PER_USER_CDM_FOLDER + File.separator);
73
    }
74

    
75
	/**
76
	 * Returns specified the sub folder of  {@link #CDM_FOLDER_NAME}.
77
	 * If the sub folder does not exist it will be created.
78
	 *
79
	 * @param subFolderName
80
	 * @return the sub folder or null in case the folder did not exist ant the attempt to create it has failed.
81
	 *
82
	 * @see {@link #SUBFOLDER_WEBAPP}
83
	 */
84
	public static File getCdmHomeSubDir(String subFolderName) {
85

    
86
		File parentFolder = getCdmHomeDir();
87
        return ensureSubfolderExists(parentFolder, subFolderName);
88
	}
89

    
90
	/**
91
     * Returns an instance specific folder folder in  {@link #CDM_FOLDER_NAME}/<code>subFolderName</code>
92
     * Non existing folders will be created.
93
     *
94
     * @param subFolderName
95
     *      The name of a subfolded. In most cases this will be {@link #SUBFOLDER_WEBAPP}
96
     * @param instanceName
97
     *      The name of the application instance. The name should be related to the data source id.
98
     * @return the sub folder or null in case the folder did not exist ant the attempt to create it has failed.
99
     *
100
     * @see {@link #SUBFOLDER_WEBAPP}
101
     */
102
    public static File getCdmInstanceSubDir(String subFolderName, String instanceName) {
103

    
104
        File subfolder = ensureSubfolderExists(getCdmHomeDir(), subFolderName);
105
        return ensureSubfolderExists(subfolder, instanceName);
106
    }
107

    
108
    /**
109
     * @param subFolderName
110
     * @param parentFolder
111
     * @return
112
     */
113
    private static File ensureSubfolderExists(File parentFolder, String subFolderName) {
114
        if (!parentFolder.exists()){
115
            if (!parentFolder.mkdir()) {
116
                throw new RuntimeException("Parent folder could not be created: " + parentFolder.getAbsolutePath());
117
            }
118
        }
119

    
120
        File subfolder = new File(parentFolder, subFolderName);
121
		// if the directory does not exist, create it
122
		if (!subfolder.exists()) {
123
			if (!subfolder.mkdir()) {
124
				throw new RuntimeException("Subfolder could not be created: " + subfolder.getAbsolutePath());
125
			}
126
		}
127
		return subfolder;
128
    }
129

    
130
	// ============= END of CdmFileUtils ========== //
131

    
132
    /**
133
     * Returns the an InputStream for a read-only source
134
     * @param resourceFileName the resources path within the classpath(!)
135
     * @return
136
     * @throws IOException
137
     */
138
    public static InputStream getReadableResourceStream(String resourceFileName)
139
            throws IOException{
140
        InputStream urlStream = CdmUtils.class.getResourceAsStream("/"+ resourceFileName);
141
        return urlStream;
142
    }
143

    
144
    /**
145
     * Returns the an InputStream for a read-only source
146
     * @param resourceFileName the resources path within the classpath(!)
147
     * @return
148
     * @throws IOException
149
     */
150
    public static InputStreamReader getUtf8ResourceReader(String resourceFileName)
151
            throws IOException{
152
        InputStream urlStream = CdmUtils.class.getResourceAsStream("/"+ resourceFileName);
153
        InputStreamReader inputStreamReader = new InputStreamReader(urlStream, "UTF8");
154
        return inputStreamReader;
155
    }
156

    
157

    
158
    /**
159
     * @return
160
     */
161
    static public String getFolderSeperator(){
162
        if (folderSeparator == null){
163
            URL url = CdmUtils.class.getResource("/"+ MUST_EXIST_FILE);
164
            if ( url != null && ! urlIsJarOrBundle(url) ){
165
                folderSeparator =  File.separator;
166
            }else{
167
                folderSeparator = "/";
168
            }
169
        }
170
        return folderSeparator;
171
    }
172

    
173

    
174
    /**
175
     * @param url
176
     * @return
177
     */
178
    static private boolean urlIsJarOrBundle(URL url){
179
        return url.getProtocol().startsWith("jar") || url.getProtocol().startsWith("bundleresource");
180
    }
181

    
182
    /**
183
     * Returns the file name for the file in which 'clazz' is to be found (helps finding according libraries)
184
     * @param clazz
185
     * @return
186
     */
187
    static public String findLibrary(Class<?> clazz){
188
        String result = null;
189
        if (clazz != null){
190
            String fullPackageName = clazz.getCanonicalName();
191
            fullPackageName = fullPackageName.replace(".", "/");
192
            URL url = CdmUtils.class.getResource("/" + fullPackageName + ".class" );
193
            if (url != null){
194
                result = url.getFile();
195
            }else{
196
                result = "";
197
            }
198
            logger.debug("LibraryURL for " + clazz.getCanonicalName() + " : " + result);
199
        }
200
        return result;
201
    }
202

    
203
    static public String testMe(){
204
        String message = "This is a test";
205
        System.out.println(message);
206
        return message;
207
    }
208

    
209
    static public String readInputLine(String inputQuestion){
210
        try {
211

    
212
            System.out.print(inputQuestion);
213
            BufferedReader in = new BufferedReader( new java.io.InputStreamReader( System.in ));
214
            String input;
215
            input = in.readLine();
216
            return input;
217
        } catch (IOException e) {
218
            logger.warn("IOExeption");
219
            return null;
220
        }
221
    }
222

    
223

    
224
    /**
225
     * Returns the trimmed value string if value is not <code>null</code>.
226
     * Returns the empty string if value is <code>null</code>.
227
     * @param value
228
     * @return
229
     */
230
    static public String NzTrim(String value){
231
        return (value == null ? "" : value);
232
    }
233

    
234

    
235
    /**
236
     * Returns value if value is not <code>null</code>. Returns empty string if value is <code>null</code>.
237
     * @param value
238
     * @return
239
     */
240
    static public String Nz(String value){
241
        return (value == null ? "" : value);
242
    }
243

    
244
    /**
245
     * Returns value if value is not <code>null</code>. Returns defaultValue if value is <code>null</code>.
246
     * @param value
247
     * @return
248
     */
249
    static public String Nz(String value, String defaultValue){
250
        return (value == null ? defaultValue : value);
251
    }
252

    
253
    /**
254
     * Returns value if value is not <code>null</code>. Returns 0 if value is <code>null</code>.
255
     * @param value
256
     * @return
257
     */
258
    static public Integer Nz(Integer value){
259
        return (value == null ? 0 : value);
260
    }
261

    
262
    /**
263
     * Returns value if value is not <code>null</code>. Returns 0 if value is <code>null</code>.
264
     * @param value
265
     * @return
266
     */
267
    static public Long Nz(Long value){
268
        return (value == null ? 0 : value);
269
    }
270

    
271
    /**
272
     * Returns str if str is not the empty String (''). Returns null if str is empty.
273
     * @param str
274
     * @return
275
     */
276
    static public String Ne(String str){
277
        return ("".equals(str)? null : str);
278
    }
279

    
280
    /**
281
     * Returns str if str.trim() is not empty. Returns null otherwise.
282
     * @param str
283
     * @return
284
     */
285
    static public String Nb(String str){
286
        return (str == null || str.trim().equals("")? null : str);
287
    }
288

    
289

    
290
    /**
291
     * Concatenates an array of strings using the defined separator.<BR>
292
     * <code>Null</code> values are interpreted as empty strings.<BR>
293
     * If all strings are <code>null</code> then <code>null</code> is returned.
294
     * @param strings
295
     * @param seperator
296
     * @return String
297
     */
298
    static public String concat(CharSequence separator, String... strings){
299
        String result = "";
300
        boolean allNull = true;
301
        for (String string : strings){
302
            if (string != null){
303
                if (result.length() > 0 && string.length() > 0){
304
                    result += separator;
305
                }
306
                result += string;
307
                allNull = false;
308
            }
309
        }
310
        //if all strings are null result should be null, not ""
311
        if (allNull){
312
            return null;
313
        }else {
314
            return result;
315
        }
316
    }
317

    
318
    /**
319
     * Concatenates two strings, using the defined seperator.<BR>
320
     * <code>Null</code> values are interpreted as empty Strings.<BR>
321
     * If both strings are <code>null</code> then <code>null</code> is returned.
322
     * @see #concat(CharSequence, String[])
323
     * @param seperator
324
     * @param string1
325
     * @param string2
326
     * @return String
327
     */
328
    static public String concat(CharSequence separator, String string1, String string2){
329
        String[] strings = {string1, string2};
330
        return concat(separator, strings);
331
    }
332

    
333

    
334
	/**
335
	 * Returns <code>preferred</code> if not blank, else returns <code>alternative</code>.
336
	 * If reverse is <code>true</code> computation is
337
	 * the other way round (<code>alternative</code> if not blank, otherwise <code>preferred</code>).
338
	 * @param preferred first string
339
	 * @param alternative second string
340
	 * @param reverse reverse flag
341
	 * @param nzTrim if <code>true</code> the result is trimmed and <code>null</code> values are replaced by empty string.
342
	 * @return the preferred string
343
	 */
344
	static public String getPreferredNonEmptyString(String preferred, String alternative, boolean reverse, boolean nzTrim){
345
		String result;
346
		if (! reverse){
347
			result = StringUtils.isBlank(preferred) ? alternative : preferred;
348
		}else{
349
			result = StringUtils.isBlank(alternative) ? preferred : alternative;
350
		}
351
		if (nzTrim){
352
			result = Nz(result).trim();
353
		}
354
		return result;
355
	}
356

    
357

    
358
    /** Returns a version of the input where all contiguous
359
     * whitespace characters are replaced with a single
360
     * space. Line terminators are treated like whitespace.
361
     *
362
     * @param inputStr
363
     * @return
364
     */
365
    public static CharSequence removeDuplicateWhitespace(CharSequence inputStr) {
366

    
367
        String patternStr = "\\s+";
368
        String replaceStr = " ";
369
        Pattern pattern = Pattern.compile(patternStr);
370
        Matcher matcher = pattern.matcher(inputStr);
371
        return matcher.replaceAll(replaceStr);
372
    }
373

    
374

    
375
    /** Builds a list of strings by splitting an input string
376
     * with delimiters whitespace, comma, or semicolon
377
     * @param value
378
     * @return
379
     */
380
    public static List<String> buildList(String value) {
381

    
382
        List<String> resultList = new ArrayList<String>();
383
        for (String tag : value.split("[\\s,;]+")) {
384
            resultList.add(tag);
385
        }
386
        return resultList;
387
    }
388

    
389

    
390
    static public boolean urlExists(String strUrl, boolean withWarning){
391
        try {
392
             HttpURLConnection.setFollowRedirects(false);
393
              // note : you may also need
394
              //        HttpURLConnection.setInstanceFollowRedirects(false)
395
              HttpURLConnection con =
396
                 (HttpURLConnection) new URL(strUrl).openConnection();
397
              con.setRequestMethod("HEAD");
398
              return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
399
        } catch (MalformedURLException e) {
400
            if (withWarning) {
401
                logger.warn(e);
402
            }
403
        } catch (IOException e) {
404
            //
405
        };
406
        return false;
407
    }
408

    
409
    static public URI string2Uri(String string) {
410
        URI uri = null;
411
        try {
412
            uri = new URI(string);
413
            logger.debug("uri: " + uri.toString());
414
        } catch (URISyntaxException ex) {
415
            logger.error("Problem converting string " + string + " to URI " + uri);
416
            return null;
417
        }
418
        return uri;
419
    }
420

    
421
    static public boolean isNumeric(String string){
422
        if (string == null){
423
            return false;
424
        }
425
        try {
426
            Double.valueOf(string);
427
            return true;
428
        } catch (NumberFormatException e) {
429
            return false;
430
        }
431

    
432
    }
433

    
434
    /**
435
     * Returns <code>true</code> if the passed string starts with an upper case letter.
436
     * <code>false</code> otherwise. The later includes <code>null</code> and empty strings.
437
     * @param string
438
     * @return
439
     */
440
    static public boolean isCapital(String string){
441
        if (isBlank(string)){
442
            return false;
443
        }else{
444
            Character firstChar = string.charAt(0);
445
            if (firstChar.equals(Character.toUpperCase(firstChar))){
446
                return true;
447
            }else{
448
                return false;
449
            }
450
        }
451

    
452
    }
453

    
454
    /**
455
     * Returns true if string is null, "" or string.trim() is ""
456
     * @see isNotEmpty(String string)
457
     * @param string
458
     * @return
459
     */
460
    static public boolean isBlank(String string){
461
        if (string == null){
462
            return true;
463
        }
464
        if ("".equals(string.trim())){
465
            return true;
466
        }
467
        return false;
468
    }
469

    
470
    /**
471
     * Removes all non-word character (i.e. *, @, %, line breaks, etc.)
472
     * from the given string
473
     * @param string the string which should be trimmed
474
     * @return the trimmed string
475
     */
476
    static public String trimNonWordCharacters(String string){
477
        return replaceNonWordCharacters(string, "");
478
    }
479

    
480
    /**
481
     * Replaces all non-word character (i.e. *, @, %, line breaks, etc.)
482
     * with the given replacement string
483
     * @param string the string which should be trimmed
484
     * @param replacement the replacement for the non-word characters
485
     * @return the trimmed string
486
     */
487
    static public String replaceNonWordCharacters(String string, String replacement){
488
        return string.replaceAll("\\W", replacement);
489
    }
490

    
491
    /**
492
     * Returns <code>false</code> if string is null, "" or string.trim() is ""
493
     * @see isNotEmpty(String string)
494
     * @param string
495
     * @return
496
     */
497
    static public boolean isNotBlank(String string){
498
        return ! isBlank(string);
499
    }
500

    
501
    /**
502
     * @see #isBlank(String)
503
     * @deprecated use {@link #isBlank(String)} instead
504
     * @param string
505
     * @return
506
     */
507
    @Deprecated
508
    static public boolean isEmpty(String string){
509
        return isBlank(string);
510
    }
511

    
512
    static public boolean areBlank(String ... strings){
513
        for (String string : strings){
514
            if (! isBlank(string)){
515
                return false;
516
            }
517
        }
518
        return true;
519
    }
520

    
521
    /**
522
     * Tests if two objects are equal or both null. Otherwise returns false
523
     * @param obj1
524
     * @param obj2
525
     * @return
526
     */
527
    public static boolean nullSafeEqual(Object obj1, Object obj2) {
528
        if (obj1 == null){
529
            return obj2 == null;
530
        }
531
        return (obj1.equals(obj2));
532
    }
533

    
534

    
535
    /**
536
     * Compares 2 strings with defined values for <code>null</code>
537
     * @param str1
538
     * @param str2
539
     * @return
540
     */
541
    public static int nullSafeCompareTo(String str1, String str2) {
542
        if (str1 == null){
543
            return str2 == null ? 0 : -1;
544
        }else if (str2 == null){
545
            return 1;
546
        }else{
547
            return (str1.compareTo(str2));
548
        }
549
    }
550

    
551
    /**
552
     * Returns false if string is null, "" or string.trim() is ""
553
     * Else true.
554
     * @see isBlank(String string)
555
     * @see #isNotBlank(String)
556
     * @deprecated use {@link #isNotBlank(String)} instead
557
     * @param string
558
     * @return
559
     */
560
    @Deprecated
561
    static public boolean isNotEmpty(String string){
562
        return isNotBlank(string);
563
    }
564

    
565

    
566
    /**
567
     * Computes all fields recursively
568
     * @param clazz
569
     * @return
570
     */
571
    public static Map<String, Field> getAllFields(Class clazz, Class highestClass, boolean includeStatic, boolean includeTransient, boolean makeAccessible, boolean includeHighestClass) {
572
        Map<String, Field> result = new HashMap<>();
573
        if ( highestClass.isAssignableFrom(clazz) && (clazz != highestClass || includeHighestClass)){
574
            //exclude static
575
            for (Field field: clazz.getDeclaredFields()){
576
                if (includeStatic || ! Modifier.isStatic(field.getModifiers())){
577
                    if (includeTransient || ! isTransient(field)){
578
                        field.setAccessible(makeAccessible);
579
                        result.put(field.getName(), field);
580
                    }
581
                }
582
            }
583

    
584
            //include superclass fields
585
            Class superclass = clazz.getSuperclass();
586
            if (superclass != null){
587
                result.putAll(getAllFields(superclass, highestClass, includeStatic, includeTransient, makeAccessible, includeHighestClass));
588
            }
589
        }
590
        return result;
591
    }
592

    
593

    
594
    /**
595
     * Returns true, if field has an annotation of type javax.persistence.Annotation
596
     * @param field
597
     * @return
598
     */
599
    protected static boolean isTransient(Field field) {
600
        for (Annotation annotation : field.getAnnotations()){
601
            //if (Transient.class.isAssignableFrom(annotation.annotationType())){
602
            if (annotation.annotationType().getSimpleName().equals("Transient")){
603
                return true;
604
            }
605
        }
606
        return false;
607
    }
608

    
609
    /**
610
     * Trims the string and if the string ends with a dot removes it.
611
     * @param string
612
     * @return
613
     */
614
    public static String removeTrailingDot(String string){
615
        if (string == null){
616
            return null;
617
        }
618
        if (string.trim().endsWith(".")){
619
            return string.substring(0, string.length() -1);
620
        }
621
        return string;
622
    }
623

    
624
    /**
625
     * Returns surrounding brackets "(",")". Trim the string if necessary.
626
     * @param text
627
     * @return
628
     */
629
    public static String removeBrackets(String text) {
630
        if (text == null){
631
            return null;
632
        }
633
        text = text.trim();
634
        if (text.matches("^\\(.*\\)$")){
635
            text = text.substring(1, text.length() -1);
636
        }
637
        return text;
638
    }
639

    
640
    /**
641
     * Compares 2 strings. If they are not empty and equal returns <code>true</code>
642
     * otherwise false.
643
     *
644
     * @param str1
645
     * @param str2
646
     * @return compare result as boolean
647
     */
648
    public static boolean nonEmptyEquals(String str1, String str2) {
649
        return (isNotBlank(str1) && str1.equals(str2));
650
    }
651

    
652
    /**
653
     * Compares if str1 and str2 is equal when ignoring whitespaces.
654
     * Returns <code>true</code> if both or <code>null</code> or
655
     * whitespace ignore equal.
656
     * @param str1
657
     * @param str2
658
     * @return
659
     */
660
    public static boolean equalsIgnoreWS(String str1, String str2) {
661
        if (str1 == null){
662
            return str2 == null;
663
        }else if (str2 == null){
664
            return false;
665
        }else{
666
            return str1.replaceAll("\\s", "").equals(str2.replaceAll("\\s", ""));
667
        }
668
    }
669

    
670

    
671
    /**
672
     * Checks if all strings given provide are {@link #isBlank(String) blank}.
673
     * Returns <code>true</code> if strs is null or empty
674
     * @param strs
675
     * @return
676
     */
677
    public static boolean isBlank(String ... strs) {
678
        if (strs == null){
679
            return true;
680
        }
681
        for (String str : strs) {
682
            if (isNotBlank(str)){
683
                return false;
684
            }
685
        }
686
        return true;
687
    }
688

    
689
}
(3-3/21)